(有偿问题)计算工人工作时间的问题

有三个时间段是工人的休息时间 如下:
1: 12:00 - 13:00
2: 17:30 - 18:30
3: 20:30 - 08:30

计算工人工作时间要减去休息时间
eg :开始时间(BeginTime):11:00
结束时间(EndTime):19:00
实际工作时间: (19-11)-2(中间休息时间)=4个小时(实际工作时间)

要求:最好C#语言实现: 写一个方法2个参数(开始时间,结束时间) 实时计算出工人实际工作时间(需要考虑跨天计算,超过2天工时按照结束时间 - 开始时间)

先看一下运行的结果(支持同天,跨天,跨任意多天等情况,同时还可自定义休息时间段):

2022-7-13 11:00到2022-7-15 19:00的工时计算结果:

img

2022-7-13 11:00到2022-7-17 19:00的工时计算结果:

img

以下是C#程序代码实现的逻辑(你可以任意调整BreakTimeRange中的休息时间段):

namespace ConsoleApp3
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var start = new WorkingDate(new MyDate(2022, 7, 13, 11, 0));
            var end = new WorkingDate(new MyDate(2022, 7, 17, 19, 0));
            var calc = new WorkingHoursCalculator(start, end);
            calc.CalculateWorkingHours();
            Console.WriteLine($"{calc.Start.DateAsString}{calc.End.DateAsString}的工时计算结果如下:");
            Console.WriteLine($"总工时:{calc.TotalWorkingMinutes}分钟(包含休息时间)");
            Console.WriteLine($"实际工时:{calc.ActualWorkingMinutes}分钟(不包含休息时间)");
            Console.WriteLine($"休息时长:{calc.TotalBreakMinutes}分钟");
            Console.WriteLine("=======以下是休息明细=======");
            Console.WriteLine();
            foreach (var item in calc.WorkingTimeItems)
            {
                Console.WriteLine($"从{item.StartAsString}{item.EndAsString}(工时:{item.ActualWorkingMinutes}分钟,休息{item.TotalBreakMinutes}分钟)");
                foreach (var breakTimeItem in item.BreakTimeItems)
                {
                    Console.WriteLine($"{breakTimeItem.BreakTime.Name}时间段休息:{breakTimeItem.BreakMinutes}分钟");
                }

                Console.WriteLine();
            }
            Console.ReadKey();
        }
    }

    public record MyDate(int Year, int Month, int Day, int Hour, int Minute);

    public record MyTime(int Hour, int Minute)
    {
        /// <summary>
        /// 转换得到的总的分钟数
        /// </summary>
        public int Minutes => Hour * 60 + Minute;
    }

    public record BreakTime(string Name, MyTime Start, MyTime End)
    {
        public int BreakMinutes => End.Minutes - Start.Minutes;
        public int BreakStart => Start.Minutes;
        public int BreakEnd => End.Minutes;
    }

    public class BreakTimeRange
    {
        public static List<BreakTime> BreakTimes => new()
        {
            new BreakTime("00:00-08:30",new MyTime(0, 0), new MyTime(8, 30)),
            new BreakTime("12:00-13:00",new MyTime(12, 0), new MyTime(13, 0)),
            new BreakTime("17:00-18:00",new MyTime(17, 30), new MyTime(18, 30)),
            new BreakTime("20:30-24:00",new MyTime(20, 30), new MyTime(24, 0))
        };
    }

    public class WorkingDate
    {
        public WorkingDate(MyDate date)
        {
            _myDate = date;
            Year = _myDate.Year;
            Month = _myDate.Month;
            Day = _myDate.Day;
            Hour = _myDate.Hour;
            Minute = _myDate.Minute;
        }

        private readonly MyDate _myDate;
        public int Year { get; }
        public int Month { get; }
        public int Day { get; }
        public int Hour { get; }
        public int Minute { get; }

        public DateTime Date
        {
            get
            {
                var hour = _myDate.Hour;
                var day = _myDate.Day;
                if (_myDate.Hour == 24)
                {
                    hour = 0;
                    day += 1;
                }

                return new DateTime(_myDate.Year, _myDate.Month, day, hour, _myDate.Minute, 0);
            }
        }

        public int TotalMinutes => _myDate.Hour * 60 + _myDate.Minute;
        public string DateAsString => $"{_myDate.Year}-{_myDate.Month}-{_myDate.Day} {_myDate.Hour:00}:{_myDate.Minute:00}";
    }

    public static class WorkingDateExtension
    {
        public static WorkingDate ConvertToEndOfDay(this WorkingDate workingDate)
        {
            return new WorkingDate(new MyDate(workingDate.Year, workingDate.Month, workingDate.Day, 24,
                0));
        }
        public static WorkingDate ConvertToStartOfDay(this WorkingDate workingDate)
        {
            return new WorkingDate(new MyDate(workingDate.Year, workingDate.Month, workingDate.Day, 0,
                0));
        }

        public static WorkingDate AddDay(this WorkingDate workingDate)
        {
            return new WorkingDate(new MyDate(workingDate.Year, workingDate.Month, workingDate.Day + 1, workingDate.Hour,
                workingDate.Minute));
        }
    }

    public class BreakTimeItem
    {
        public BreakTime BreakTime { get; set; }
        public int BreakMinutes { get; set; }
    }

    public class WorkingTimeItem
    {
        public WorkingTimeItem(WorkingDate start, WorkingDate end)
        {
            Start = start;
            End = end;
            BreakTimeItems = new List<BreakTimeItem>();
        }
        public WorkingDate Start { get; set; }
        public WorkingDate End { get; set; }
        public string DayAsString => Start.Date.ToString("yyyy-MM-dd");
        public string StartAsString => Start.Date.ToString("yyyy-MM-dd HH:mm");
        public string EndAsString => End.Date.ToString("yyyy-MM-dd HH:mm");

        /// <summary>
        /// 当天工时(分钟),不包含休息时间
        /// </summary>
        public int ActualWorkingMinutes
        {
            get
            {
                return End.TotalMinutes - Start.TotalMinutes - BreakTimeItems.Sum(x => x.BreakMinutes);
            }
        }
        /// <summary>
        /// 当天工时(分钟),包含休息时间
        /// </summary>
        public int TotalWorkingMinutes => End.TotalMinutes - Start.TotalMinutes;

        /// <summary>
        /// 当天总的休息时长
        /// </summary>
        public int TotalBreakMinutes => BreakTimeItems.Sum(x => x.BreakMinutes);

        /// <summary>
        /// 休息明细
        /// </summary>
        public List<BreakTimeItem> BreakTimeItems { get; private set; }
        /// <summary>
        /// 添加休息时间段
        /// </summary>
        /// <param name="item"></param>
        public void AddBreakTimeItem(BreakTimeItem item)
        {
            BreakTimeItems.Add(item);
        }
    }

    /// <summary>
    /// 工时计算器
    /// </summary>
    public class WorkingHoursCalculator
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="start"></param>
        /// <param name="end"></param>
        public WorkingHoursCalculator(WorkingDate start, WorkingDate end)
        {
            Start = start;
            End = end;
        }

        /// <summary>
        /// 开始的天
        /// </summary>
        public int DayOfStart { get; private set; }

        /// <summary>
        /// 结束的天
        /// </summary>
        public int DayOfEnd { get; private set; }

        /// <summary>
        /// 跨天数
        /// </summary>
        public int CrossDays { get; private set; }

        /// <summary>
        /// 两个时期间是否跨天
        /// </summary>
        public bool IsCrossDay => DayOfEnd != DayOfStart;

        /// <summary>
        /// 所有天的总工时(包含休息时间)
        /// </summary>
        public double TotalWorkingMinutes => WorkingTimeItems.Sum(x => x.TotalWorkingMinutes);

        /// <summary>
        /// 所有天的总实际工时(不包含工作时间)
        /// </summary>
        public double ActualWorkingMinutes => WorkingTimeItems.Sum(x => x.ActualWorkingMinutes);

        /// <summary>
        /// 所有天的总休息时长
        /// </summary>
        public double TotalBreakMinutes => WorkingTimeItems.Sum(x => x.TotalBreakMinutes);

        public List<WorkingTimeItem> WorkingTimeItems { get; set; }
        public WorkingDate Start { get; set; }
        public WorkingDate End { get; set; }

        public void CalculateWorkingHours()
        {
            if (Start.Date > End.Date) throw new ArgumentException("开始时间和结束时间输入错误");
            DayOfStart = Start.Date.Day;
            DayOfEnd = End.Date.Day;
            CrossDays = (End.Date - Start.Date).Days;
            WorkingTimeItems = new List<WorkingTimeItem>();
            if (!IsCrossDay)
            {
                FindWorkingMinutes(Start, End);
            }
            else
            {
                // 跨天时

                // 第一天,开始时间到24点
                FindWorkingMinutes(Start, Start.ConvertToEndOfDay());
                var days = CrossDays;
                var current = Start;
                while (days > 0)
                {
                    if (days == 1)
                    {
                        FindWorkingMinutes(End.ConvertToStartOfDay(), End);
                        break;
                    }
                    current = current.AddDay();
                    FindWorkingMinutes(current.ConvertToStartOfDay(), current.ConvertToEndOfDay());
                    days--;
                }
            }
        }

        public void FindWorkingMinutes(WorkingDate start, WorkingDate end)
        {
            var wti = new WorkingTimeItem(start, end);
            var aStart = start.TotalMinutes;
            var aEnd = end.TotalMinutes;
            foreach (var breakTime in BreakTimeRange.BreakTimes.Where(breakTime => aStart <= breakTime.BreakEnd && aEnd >= breakTime.BreakStart))
            {
                if (aStart <= breakTime.BreakStart && aEnd >= breakTime.BreakEnd)
                {
                    wti.AddBreakTimeItem(new BreakTimeItem
                    {
                        BreakTime = breakTime,
                        BreakMinutes = breakTime.BreakMinutes
                    });
                    continue;
                }
                if (aStart <= breakTime.BreakStart && aEnd <= breakTime.BreakEnd)
                {
                    wti.AddBreakTimeItem(new BreakTimeItem
                    {
                        BreakTime = breakTime,
                        BreakMinutes = aEnd - breakTime.BreakStart
                    });
                    continue;
                }
                if (aStart >= breakTime.BreakStart && aEnd >= breakTime.BreakEnd)
                {
                    wti.AddBreakTimeItem(new BreakTimeItem
                    {
                        BreakTime = breakTime,
                        BreakMinutes = breakTime.BreakEnd - aStart
                    });
                    continue;
                }
                if (aStart >= breakTime.BreakStart && aEnd <= breakTime.BreakEnd)
                {
                    wti.AddBreakTimeItem(new BreakTimeItem
                    {
                        BreakTime = breakTime,
                        BreakMinutes = aEnd - aStart
                    });
                }
            }
            WorkingTimeItems.Add(wti);
        }
    }
}

提供思路:
休息时间是固定的三个时间段,可以用开始时间去对比每一个休息的开始时间,然后用结束时间去对比每一个休息的结束时间,然后判断经历了几个休息时间即可。
如果开始时间小于的不是第一个休息的开始时间,就需要跟上一个休息的结束时间对比,以解决工作的开始时间在休息区间内的场景。结束时间同理。


import datetime

def workinghours(a,b):
    a_date = datetime.datetime.strptime(a,"%Y-%m-%d %H:%M")
    b_date = datetime.datetime.strptime(b,"%Y-%m-%d %H:%M")
    _seconds = b_date - a_date

    days, sec = _seconds.days, _seconds.seconds
    hours = days * 24 + sec // 3600
    minutes = (sec % 3600) // 60
    _sec = sec % 60
    
    if hours  >2:
        hours  -= 2
    return '{}:{}:{}'.format(hours minutes,_sec)

a = '2022-07-14 20:30'
b = '2022-7-15 8:30'
print(workinghours(a,b))

提供个思路,用list做的话,每隔0.5小时apped,如果是休息时间,则remove,最后计算list的size
如果跨天,则每天一个list

这是C语言吗

示例中使用的是分钟,需要小时可自行转换:


    class Test1
    {
        public void Test()
        {
            var breakTimes = new List<BreakTime>();
            breakTimes.Add(new BreakTime("12:00", "13:00"));
            breakTimes.Add(new BreakTime("17:30", "18:30"));
            breakTimes.Add(new BreakTime("20:30", "08:30"));
            int workStart = 11, workEnd = 19;
            //次日加24小时
            if (workEnd<workStart)
                workEnd +=24;
            workEnd*=60;
            workStart*=60;
            int workTime = workEnd-workStart;
            breakTimes.ForEach(t =>
            {
                if (t.Start>=workStart && t.Start<=workEnd
                    || t.End>=workStart && t.End <=workEnd
                    || t.Start<=workStart && t.End>=workStart
                    || t.Start<=workEnd && t.End>=workEnd)
                {
                    var start = t.Start;
                    var end = t.End;
                    if (start<workStart)
                        start = workStart;
                    if (end>workEnd)
                        end=workEnd;
                    workTime -= end-start;
                }
            });
            Console.WriteLine(workTime);
        }
    }
    class BreakTime
    {
        public BreakTime(string _Start, string _End)
        {
            var t = _Start.Split(':');
            Start =Convert.ToInt32(t[0]) *60+Convert.ToInt32(t[1]);
            t = _End.Split(':');
            End =Convert.ToInt32(t[0]) *60+Convert.ToInt32(t[1]);
            if (End<Start)
                End+=1440;
        }
        public int Start { get; set; }
        public int End { get; set; }
    }

正好比较闲,给你写个完整的

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
Console.WriteLine( WorkHour(new DateTime(2022, 7, 21, 11, 0, 0), new DateTime(2022, 7, 22, 19, 0, 0)));
Console.ReadKey();
}

    private static double WorkHour(DateTime begin_time, DateTime end_time)
    {
        double result = 0;
        //1: 12:00 - 13:00
        //2: 17:30 - 18:30
        //3: 20:30 - 08:30   00:00-8:30   20:30-24:00
        List<RestTime> rest = new List<RestTime>() {
             new RestTime{
              begin_hour = 0,begin_minute=0,end_hour=8,end_minute=30
            },

            new RestTime{
              begin_hour = 12,begin_minute=0,end_hour=13,end_minute=0
            },
             new RestTime{
              begin_hour = 17,begin_minute=30,end_hour=18,end_minute=30
            },
              new RestTime{
              begin_hour = 12,begin_minute=0,end_hour=13,end_minute=0
            },
            new RestTime{
              begin_hour = 20,begin_minute=30,end_hour=24,end_minute=0
            }
        };
        while (end_time > begin_time)
        {
            foreach (var item in rest)
            {
               
                //开始时间和结束时间在休息时间段之前
                if (begin_time.Hour <= item.begin_hour && begin_time.Minute <= item.begin_minute&&end_time<= new DateTime(begin_time.Year, begin_time.Month, begin_time.Day, item.begin_hour, item.begin_minute, 0))
                {

                    result +=(end_time - begin_time).TotalHours;
                    begin_time = end_time;//结束while
                    break;
                }
                //开始时间在休息时间段之前,结束时间在休息时间段之间
                if (begin_time.Hour <= item.begin_hour && begin_time.Minute <= item.begin_minute && end_time <= new DateTime(begin_time.Year, begin_time.Month, item.end_hour == 24 ? begin_time.Day + 1 : begin_time.Day , item.end_hour == 24 ? 0 : item.end_hour, item.end_minute, 0))
                {

                    result += (new DateTime(end_time.Year, end_time.Month, end_time.Day, item.begin_hour, item.begin_minute, 0) - begin_time).TotalHours;
                    begin_time = end_time;//结束while
                    break;
                }
                //开始时间在休息时间段之前,结束时间在休息时间之后 
                if (begin_time.Hour <= item.begin_hour && begin_time.Minute <= item.begin_minute && end_time >= new DateTime(begin_time.Year, begin_time.Month, item.end_hour == 24 ? begin_time.Day + 1 : begin_time.Day , item.end_hour == 24 ? 0 : item.end_hour, item.end_minute, 0))
                {

                    result += (new DateTime(begin_time.Year, begin_time.Month, begin_time.Day, item.begin_hour, item.begin_minute, 0) - begin_time).TotalHours;
                    begin_time = new DateTime(begin_time.Year, begin_time.Month, item.end_hour == 24 ? begin_time.Day + 1 : begin_time.Day, item.end_hour == 24 ? 0 : item.end_hour, item.end_minute, 0);
                    continue;
                }
                //开始时间在休息时间段之间
                if (begin_time.Hour >= item.begin_hour && begin_time.Minute >= item.begin_minute && begin_time.Hour <= item.end_hour && begin_time.Minute <= item.end_hour)
                { 
                    begin_time = new DateTime(begin_time.Year, begin_time.Month, item.end_hour == 24 ? begin_time.Day + 1: begin_time.Day ,item.end_hour == 24 ? 0 : item.end_hour, item.end_minute, 0);
                    if (begin_time >= end_time)
                    {
                        break;
                    }
                    continue;
                }

               
                //开始时间在休息时间段之后,不作处理
            }

        }

        return result;
    }

    public class RestTime
    {
        public int begin_hour { get; set; }
        public int begin_minute { get; set; }

        public int end_hour { get; set; }
        public int end_minute { get; set; }

    }
}

}