#c# #.net-core #intervals
#c# #.net-core #интервалы
Вопрос:
Мне интересно, может ли кто-нибудь мне помочь, у меня есть коллекция времени начала и окончания работы в течение одного дня. Я также хочу показать обратное, поэтому время, до которого человек не работал в этот день. Проблема, с которой я сталкиваюсь с моим кодом, заключается в том, что он переносится на следующий день, тогда как я просто хочу этот день.
public class WorkDay
{
public DateTime Day { get; set; }
public List<Worked> WorkingTimes { get; set; }
}
public class Worked
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
static class Program
{
static void Main()
{
var now = DateTime.Now;
var year = now.Year;
var month = now.Month;
var day = now.Day;
var Day = new WorkDay
{
Day = now,
WorkingTimes = new List<Worked>
{
new Worked { Start = new DateTime(year,month, day,8,30,0), End = new DateTime(year,month, day,10,30,0) },
new Worked { Start = new DateTime(year,month, day,10,45,0), End = new DateTime(year,month, day,14,30,0) },
new Worked { Start = new DateTime(year,month, day,14,50,0), End = new DateTime(year,month, day,14,50,0).AddHours(10) }
}
};
foreach (var time in Day.WorkingTimes)
Console.WriteLine($"Start {time.Start} " $"End {time.End}");
Day.WorkingTimes = Day.WorkingTimes.OrderBy(x => x.Start).ToList();
var opposite = Opposite(Day);
foreach (var time in opposite)
Console.WriteLine($"Start {time.Start} " $"End {time.End}");
Console.WriteLine("Hello World!");
}
public static IEnumerable<Worked> Opposite(WorkDay workDay)
{
var rested = new List<Worked>();
for (var i = workDay.WorkingTimes.Count(); i-- > 0;)
if (i - 1 != -1 amp;amp; workDay.WorkingTimes[i - 1].End != workDay.WorkingTimes[i].Start)
rested.Add(new Worked { Start = workDay.WorkingTimes[i - 1].End, End = workDay.WorkingTimes[i].Start });
rested = rested.OrderBy(x => x.Start).ToList();
var lastEntry = rested.Last().End.Date;
var lastTime = new DateTime(lastEntry.Year, lastEntry.Month, lastEntry.Day, 23, 59, 59, 59);
if (lastTime > rested.Last().End)
rested.Add(new Worked
{ Start = workDay.WorkingTimes.Last().End, End = lastTime });
return rested;
}
}
Таким образом, результат будет:
Сработало:
Start 21/09/2020 08:30:00 End 21/09/2020 10:30:00
Start 21/09/2020 10:45:00 End 21/09/2020 14:30:00
Start 21/09/2020 14:50:00 End 22/09/2020 00:50:00
Противоположное:
Start 21/09/2020 10:30:00 End 21/09/2020 10:45:00
Start 21/09/2020 14:30:00 End 21/09/2020 14:50:00
Start **22/09/2020** 00:50:00 End 21/09/2020 23:59:59
То, что я пытаюсь сделать, это не переходить на следующий день, вычисляя разницу. Итак, в классе WorkDay есть день, и все даты должны быть с этого дня.
Таким образом, учитываются 24 часа этого дня (либо отработанные, либо нет), поэтому, если они не сработали, это должно учитываться в результате противоположного метода.
Комментарии:
1. Свойство Date для DateTime урезало дату до полуночи в начале дня. Итак, вы можете использовать : WorkingTimes . GroupBy(x => x.Date). ToList();
2. Предложение для лучшего / более быстрого ответа. Сделайте так, чтобы в вашем примере было конкретное время начала / окончания и покажите, каким будет ваш ожидаемый результат
Ответ №1:
Я бы решил это, смоделировав период времени, а затем предоставил метод, который мог Cut
бы выделить отрезок времени из этого периода. Тогда становится тривиальным отработать оставшуюся часть дня.
Давайте начнем с Period
класса:
private sealed class Period : IEquatable<Period>
{
public DateTime StartTime { get; private set; }
public DateTime EndTime { get; private set; }
public Period(DateTime startTime, DateTime endTime)
{
this.StartTime = startTime;
this.EndTime = endTime;
}
public override bool Equals(object obj)
{
if (obj is Period)
return Equals((Period)obj);
return false;
}
public bool Equals(Period obj)
{
if (obj == null)
return false;
if (!EqualityComparer<DateTime>.Default.Equals(this.StartTime, obj.StartTime))
return false;
if (!EqualityComparer<DateTime>.Default.Equals(this.EndTime, obj.EndTime))
return false;
return true;
}
public override int GetHashCode()
{
int hash = 0;
hash ^= EqualityComparer<DateTime>.Default.GetHashCode(this.StartTime);
hash ^= EqualityComparer<DateTime>.Default.GetHashCode(this.EndTime);
return hash;
}
public override string ToString()
{
return String.Format("{{ StartTime = {0}, EndTime = {1} }}",
this.StartTime, this.EndTime);
}
public IEnumerable<Period> Cut(Period that)
{
if (that.StartTime <= this.StartTime)
{
if (that.EndTime <= this.StartTime)
{
yield return this;
}
else if (that.EndTime < this.EndTime)
{
yield return new Period(that.EndTime, this.EndTime);
}
}
else if (that.StartTime < this.EndTime)
{
if (that.EndTime < this.EndTime)
{
yield return new Period(this.StartTime, that.StartTime);
yield return new Period(that.EndTime, this.EndTime);
}
else
{
yield return new Period(this.StartTime, that.StartTime);
}
}
else
{
yield return this;
}
}
}
Теперь мы можем выразить текущее рабочее время следующим образом:
var workingTimes = new[]
{
new Period(new DateTime(year, month, day, 8, 30, 0), new DateTime(year, month, day, 10, 30, 0)),
new Period(new DateTime(year, month, day, 10, 45, 0), new DateTime(year, month, day, 14, 30, 0)),
new Period(new DateTime(year, month, day, 14, 50, 0), new DateTime(year, month, day, 14, 50, 0).AddHours(10)),
};
Тогда весь день:
var whole = new Period(now.Date, now.Date.AddDays(1.0));
Теперь мы можем вычислить остаток дня просто так:
var result = new [] { whole };
foreach (var d in workingTimes)
{
result = result.SelectMany(r => r.Cut(d)).ToArray();
}
Мой конечный результат:
2020/09/21 00:00 - 2020/09/21 08:30 2020/09/21 10:30 - 2020/09/21 10:45 2020/09/21 14:30 - 2020/09/21 14:50
Комментарии:
1. Спасибо. Приятное, элегантное и простое в использовании решение проблемы, я внес небольшое изменение, чтобы перестать переходить на следующий день. Спасибо за вашу помощь. если (время начала. День == Время окончания. День) возвращает возврат нового периода (это. Время окончания, это. Время окончания); иначе возвращает новый период (это. Время окончания, это. Время окончания. AddTicks(-1));
2.@JimboJones — Не беспокойтесь. На вашем месте я бы реализовал
Fragment
метод, который работает какCut
, но также возвращаетthat
Period
(фрагментируя его, если он перекрывается сthis
). Затем вы можете вызватьFragment
передачу в полном текущем дне и просто отфильтровать любые фрагменты, которые не начинаются в тот же день.
Ответ №2:
Простым решением может быть фильтрация rested
результата только по тем значениям, где Start
и End
соответствуют Day
// last line of method "Opposite"
return rested.Where(o => o.Start.Date == workDay.Day.Date amp;amp; o.End.Date == workDay.Day.Date);
Комментарии:
1. Если это не то, что вам было нужно, пожалуйста, обновите свой вопрос некоторыми конкретными примерами, включая ожидаемый результат, и я с радостью обновлю этот ответ.