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