有三个时间段是工人的休息时间 如下:
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的工时计算结果:
2022-7-13 11:00到2022-7-17 19:00的工时计算结果:
以下是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; }
}
}
}