public interface ITimeRange
{
DateTime? Start { get; }
DateTime? End { get; }
}
public enum OverlapType
{
Invalid = 0,
Before = 1,
After = 2,
Contains = 3,
Contained = 4,
StartOverlaps = 5,
EndOverlaps = 6
}
public static class TimeRangeExtensions
{
public static bool HasOverlap(this ITimeRange timeRange, ITimeRange outer) => (int)GetOverlapType(timeRange, outer) > 3;
public static TimeSpan GetOverlap(this ITimeRange timeRange, ITimeRange outer) => DateRangeOverlap(timeRange.Start, timeRange.End, outer.Start, outer.End);
private static TimeSpan DateRangeOverlap(DateTime? min1, DateTime? max1, DateTime? min2, DateTime? max2)
{
return DateRangeOverlap(
min1 ?? DateTime.MinValue,
max1 ?? DateTime.MaxValue,
min2 ?? DateTime.MinValue,
max2 ?? DateTime.MaxValue);
}
private static TimeSpan DateRangeOverlap(DateTime min1, DateTime max1, DateTime min2, DateTime max2)
{
if (min1 > max1 || min2 > max2)
return new TimeSpan(0); // throw new Exception("Invalid date range");
if (max2 <= min1 || min2 >= max1)
return new TimeSpan(0);
if (min1 <= min2 && max1 >= max2)
return (max2 - min2).Duration();
if (min1 >= min2 && max1 <= max2)
return (max1 - min1).Duration();
if (min1 >= min2 && max1 >= max2 && max2 >= min1)
return (max2 - min1).Duration();
if (min1 <= min2 && max1 >= min2 && max2 >= max1)
return (max1 - min2).Duration();
return new TimeSpan(0);
}
public static OverlapType GetOverlapType(this ITimeRange timeRange, ITimeRange outer) => DateRangeOverlapType(timeRange.Start, timeRange.End, outer.Start, outer.End);
private static OverlapType DateRangeOverlapType(DateTime? min1, DateTime? max1, DateTime? min2, DateTime? max2)
{
return DateRangeOverlapType(
min1 ?? DateTime.MinValue,
max1 ?? DateTime.MaxValue,
min2 ?? DateTime.MinValue,
max2 ?? DateTime.MaxValue);
}
private static OverlapType DateRangeOverlapType(DateTime min1, DateTime max1, DateTime min2, DateTime max2)
{
if (min1 > max1 || min2 > max2)
return OverlapType.Invalid;
if (max2 <= min1)
return OverlapType.Before;
if(min2 >= max1)
return OverlapType.After;
if (min1 <= min2 && max1 >= max2)
return OverlapType.Contains;
if (min1 >= min2 && max1 <= max2)
return OverlapType.Contained;
if (min1 >= min2 && max1 >= max2 && max2 >= min1)
return OverlapType.StartOverlaps;
if (min1 <= min2 && max1 >= min2 && max2 >= max1)
return OverlapType.EndOverlaps;
return OverlapType.Invalid; // not possible
}
}
public sealed class TimeRange : ITimeRange
{
private TimeRange(DateTime? start, DateTime? end)
{
Start = start;
End = end;
}
public DateTime? Start { get; private set; }
public DateTime? End { get; private set; }
public static ITimeRange Today => new TimeRange(DateTime.Today, DateTime.Today.AddDays(1).AddSeconds(-1));
public static ITimeRange GetRelativeYear(int relative = 0)
{
var month = DateTime.Now.AddYears(relative);
var start = new DateTime(month.Year, 1, 1);
var end = start.AddYears(1).AddSeconds(-1);
return new TimeRange(start, end);
}
public static ITimeRange GetRelativeMonth(int relative = 0)
{
var month = DateTime.Now.AddMonths(relative);
var start = new DateTime(month.Year, month.Month, 1);
var end = start.AddMonths(1).AddSeconds(-1);
return new TimeRange(start, end);
}
public static ITimeRange GetRelativeWeek(int relative)
{
var date = DateTime.Now;
while (date.DayOfWeek != DayOfWeek.Monday)
date = date.AddDays(-1);
date = date.AddDays(relative * 7);
return new TimeRange(date, date.AddDays(6));
}
public static ITimeRange GetRelativeDay(int relative)
{
var date = DateTime.Today;
date = date.AddDays(relative);
return new TimeRange(date, date.AddDays(1).AddSeconds(-1));
}
}
/// Old code
using System;
namespace TimeRanges
{
public interface ITimeRange
{
DateTime Start { get; }
DateTime End { get; }
}
public class TimeRange : ITimeRange
{
private TimeRange(DateTime start, DateTime end)
{
Start = start;
End = end;
}
public DateTime Start { get; }
public DateTime End { get; }
public static ITimeRange GetTimeRange(DateTime start, DateTime end)
{
return new TimeRange(start, end);
}
public static bool IsInRange(ITimeRange timeRange, DateTime? date)
{
return date.HasValue && date >= timeRange.Start && date <= timeRange.End;
}
public static ITimeRange GetPreviousMonth()
{
var prevMonth = DateTime.Now.AddMonths(-1);
var start = new DateTime(prevMonth.Year, prevMonth.Month, 1);
var end = start.AddMonths(1).AddSeconds(-1);
return GetTimeRange(start, end);
}
public static int ISO8601WeekNumber(DateTime fromDate)
{
// Get jan 1st of the year
DateTime startOfYear = fromDate.AddDays(-fromDate.Day + 1).AddMonths(-fromDate.Month + 1);
// Get dec 31st of the year
DateTime endOfYear = startOfYear.AddYears(1).AddDays(-1);
// ISO 8601 weeks start with Monday
// The first week of a year includes the first Thursday
// DayOfWeek returns 0 for sunday up to 6 for saterday
int[] iso8601Correction = { 6, 7, 8, 9, 10, 4, 5 };
int nds = fromDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek];
int wk = nds / 7;
switch (wk)
{
case 0:
// Return weeknumber of dec 31st of the previous year
return ISO8601WeekNumber(startOfYear.AddDays(-1));
case 53:
// If dec 31st falls before thursday it is week 01 of next year
if (endOfYear.DayOfWeek < DayOfWeek.Thursday)
return 1;
else
return wk;
default: return wk;
}
}
public static ITimeRange GetRelativeMonth(int relative = 0)
{
var month = DateTime.Now.AddMonths(relative);
var start = new DateTime(month.Year, month.Month, 1);
var end = start.AddMonths(1).AddSeconds(-1);
return GetTimeRange(start, end);
}
public static ITimeRange GetRelativeWeek(int relative)
{
var date = DateTime.Now;
while (date.DayOfWeek != DayOfWeek.Monday)
date = date.AddDays(-1);
date = date.AddDays(relative * 7);
return GetTimeRange(date, date.AddDays(6));
}
public static string GetWeekDescription(DateTime dateTime)
{
var week = ISO8601WeekNumber(dateTime);
var year = dateTime.Year;
if (week == 1)
{
year = dateTime.AddMonths(1).Year;
}
else if (week >= 52)
{
year = dateTime.AddMonths(-1).Year;
}
return $"Week {week} {year}";
}
}
}
public interface IWithValidTime
{
IDateTimeRange ValidTime { get; }
}
public interface IDateTimeRange
{
DateTime? Min { get; }
DateTime? Max { get; }
}
public class TimeRange : IDateTimeRange
{
public DateTime? Min { get; }
public DateTime? Max { get; }
private TimeRange(DateTime? min, DateTime? max)
{
Min = min;
Max = max;
}
public static IDateTimeRange From(DateTime? min, DateTime? max)
{
return new TimeRange(min, max);
}
public static IDateTimeRange Now()
{
return new TimeRange(DateTime.Now, DateTime.Now);
}
public static IDateTimeRange FromDates(DateTime? from, DateTime? to)
{
var fromDate = from?.Date;
var toDate = to.HasValue ? to.Value.Date + new TimeSpan(23, 59, 59) : to;
return From(fromDate, toDate);
}
public enum OverlapType
{
Invalid = 0,
Before = 1,
After = 2,
Contains = 3,
Contained = 4,
StartOverlaps = 5,
EndOverlaps = 6
}
public static bool ObjectIsValid(IWithValidTime obj, IDateTimeRange inTime) => HasOverlap(obj.ValidTime, inTime);
public static bool ObjectIsValidNow(IWithValidTime obj) => HasOverlap(obj.ValidTime, Now());
public static bool HasOverlap(IDateTimeRange timeRange, IDateTimeRange outer) => (int)GetOverlapType(timeRange, outer) >= 3;
public static OverlapType GetOverlapType(IDateTimeRange timeRange, IDateTimeRange outer) => DateRangeOverlapType(timeRange.Min, timeRange.Max, outer.Min, outer.Max);
private static OverlapType DateRangeOverlapType(DateTime? min1, DateTime? max1, DateTime? min2, DateTime? max2)
{
return DateRangeOverlapType(
min1 ?? DateTime.MinValue,
max1 ?? DateTime.MaxValue,
min2 ?? DateTime.MinValue,
max2 ?? DateTime.MaxValue);
}
private static OverlapType DateRangeOverlapType(DateTime min1, DateTime max1, DateTime min2, DateTime max2)
{
if (min1 > max1 || min2 > max2)
return OverlapType.Invalid;
if (max2 <= min1)
return OverlapType.Before;
if (min2 >= max1)
return OverlapType.After;
if (min1 <= min2 && max1 >= max2)
return OverlapType.Contains;
if (min1 >= min2 && max1 <= max2)
return OverlapType.Contained;
if (min1 >= min2 && max1 >= max2 && max2 >= min1)
return OverlapType.StartOverlaps;
if (min1 <= min2 && max1 >= min2 && max2 >= max1)
return OverlapType.EndOverlaps;
return OverlapType.Invalid; // not possible
}
}269400cookie-checkC# TimeRange