/// <summary> /// Generates a random <see cref="DateTime"></see> object based on the specified date range /// </summary> /// <param name="start">DateTime range start</param> /// <param name="end">DateTime range end</param> /// <param name="minuteRounding">Rounds time to the specified minute rounding</param> /// <param name="secondRounding">Rounds time to the specified second rounding</param> /// <param name="workingHours">Limits the time range between 8am and 6pm - Monday to Friday</param> /// <returns></returns> public static DateTime WithinRange(DateTime start, DateTime end, MinuteRounding minuteRounding = MinuteRounding.None, SecondRounding secondRounding = SecondRounding.None, bool workingHours = false) { // Assertions if (start > end) throw new ArgumentException("End date must be greater than Start"); if (minuteRounding == MinuteRounding.HalfHour && (end - start) < TimeSpan.FromMinutes(30)) throw new ArgumentException("Range must be greater than 30 minutes"); if (minuteRounding == MinuteRounding.QuarterHour && (end - start) < TimeSpan.FromMinutes(15)) throw new ArgumentException("Range must be greater than 15 minutes"); // If the range falls outside of working hours, then throw an error if (workingHours && end - start < TimeSpan.FromDays(1) && start.Intersects(start.Date.Add(WorkingDayStart), start.Date.Add(WorkingDayEnd), end - start)) throw new ArgumentException("Range falls outside of working hours"); // Create random date DateTime date; int counter = 0; do { date = new DateTime(LongRandom(start.Ticks, end.Ticks)); if (minuteRounding != MinuteRounding.None) date = date.RoundMinutes(minuteRounding); if (secondRounding != SecondRounding.None) date = date.RoundSeconds(secondRounding); if (workingHours) date = LimitToWorkingHours(date); counter++; if (counter > 100) throw new Exception("Could not create a DateTime within the specified range. Try using a larger range."); } while (date < start || date > end); return date; }
/// <summary> /// Rounds the minute component to the nearest specified time. Defaults to 1 hour /// </summary> /// <param name="source"></param> /// <param name="rounding"></param> /// <returns></returns> public static DateTime RoundMinutes(this DateTime source, MinuteRounding rounding = MinuteRounding.Hour) { if (rounding == MinuteRounding.QuarterHour) throw new NotImplementedException("Coming soon"); switch (rounding) { case MinuteRounding.Hour: if (source.Minute >= 30) return source.AddHours(1).AddMinutes(-source.Minute).TrimSeconds(); return source.AddMinutes(-source.Minute).TrimSeconds(); case MinuteRounding.HalfHour: if (source.Minute < 15) return source.AddMinutes(-source.Minute).TrimSeconds(); if (source.Minute >= 15 && source.Minute < 45) return source.AddMinutes(-source.Minute).AddMinutes(30).TrimSeconds(); return source.AddHours(1).AddMinutes(-source.Minute).TrimSeconds(); default: throw new ArgumentOutOfRangeException("rounding"); } }