BB.Caching.Redis.Analytics.BitwiseAnalytics.DateTimeUtil.MinKeysForRange C# (CSharp) Method

MinKeysForRange() public static method

Finds the minimum subset of keys required to cover the range of time specified by start and end using the TimeInterval specified.
/// This exception should never be triggered unless a new TimeInterval is supported. ///
public static MinKeysForRange ( System.DateTime start, System.DateTime end, TimeInterval timeInterval = TimeInterval.FifteenMinutes, DayOfWeek firstDayOfWeek = DayOfWeek.Sunday ) : Tuple[]
start System.DateTime /// The start of the time range. ///
end System.DateTime /// The end of the time range. ///
timeInterval TimeInterval /// The time interval. ///
firstDayOfWeek DayOfWeek /// The first day to start each week. Defaults to Sunday which is used in the US, CA, and JP. You can /// change it to Monday to get weekly aggregates which are accurate for other countries, but it'll double /// the weekly data stored. ///
return Tuple[]
            public static Tuple<TimeInterval, string, DateTime>[] MinKeysForRange(
                DateTime start,
                DateTime end,
                TimeInterval timeInterval = TimeInterval.FifteenMinutes,
                DayOfWeek firstDayOfWeek = DayOfWeek.Sunday)
            {
                if (start > end)
                {
                    throw new Exception(
                        string.Format("expecting dateTime < end\n\tstart: {0}\n\tend: {1}", start, end));
                }

                var result = new List<Tuple<TimeInterval, string, DateTime>>();

                // round to the closest 15 minute mark
                start = start.AddMinutes(-(start.Minute % 15));
                var roundEnd = end.AddMinutes(-(end.Minute % 15));

                while (true)
                {
                    TimeSpan difference = end - start;

                    // not super accurate, but a decent approximation
                    if (difference.TotalDays >= 365)
                    {
                        // exactly one entire year
                        if (start == new DateTime(start.Year, 1, 1) && start.AddYears(1) == roundEnd)
                        {
                            for (int month = 0; month < 12; ++month)
                            {
                                var tmp = start.AddMonths(month);
                                result.Add(new Tuple<TimeInterval, string, DateTime>(
                                    TimeInterval.OneMonth, DateTimeUtil.OneMonth(tmp), tmp));
                            }

                            start = start.AddYears(1);

                            if (start == end)
                            {
                                break;
                            }
                        }
                        else
                        {
                            DateTime cutoff = new DateTime(start.Year + 1, 1, 1);
                            result.AddRange(MinKeysForRange(start, cutoff, timeInterval));
                            result.AddRange(MinKeysForRange(cutoff, end, timeInterval));
                            break;
                        }
                    }
                    else if (timeInterval == TimeInterval.Quarter)
                    {
                        while (start <= roundEnd)
                        {
                            result.AddRange(DateTimeUtil.MonthsInQuarter(start)
                                .Select(x => new Tuple<TimeInterval, string, DateTime>(
                                    TimeInterval.OneMonth,
                                    x,
                                    DateTime.ParseExact(x, "yyyyMM", CultureInfo.InvariantCulture))));
                            start = start.AddMonths(3);
                        }

                        break;
                    }
                    else if (timeInterval == TimeInterval.OneMonth)
                    {
                        while (start <= roundEnd)
                        {
                            result.Add(new Tuple<TimeInterval, string, DateTime>(
                                TimeInterval.OneMonth, DateTimeUtil.OneMonth(start), start));
                            start = start.AddMonths(1);
                        }

                        break;
                    }
                    else if (difference.TotalDays >= 28)
                    {
                        // exactly one entire month
                        if (start == new DateTime(start.Year, start.Month, 1) && start.AddMonths(1) == roundEnd)
                        {
                            result.Add(new Tuple<TimeInterval, string, DateTime>(
                                TimeInterval.OneMonth, DateTimeUtil.OneMonth(start), start));
                            start = start.AddMonths(1);

                            if (start == end)
                            {
                                break;
                            }
                        }
                        else
                        {
                            DateTime cutoff = new DateTime(start.Year, start.Month + 1, 1);
                            result.AddRange(MinKeysForRange(start, cutoff, timeInterval));
                            result.AddRange(MinKeysForRange(cutoff, end, timeInterval));
                            break;
                        }
                    }
                    else if (timeInterval == TimeInterval.Week)
                    {
                        while (start <= roundEnd)
                        {
                            result.Add(new Tuple<TimeInterval, string, DateTime>(
                                TimeInterval.Week, DateTimeUtil.WeekNumber(start, firstDayOfWeek), start));
                            start = start.AddDays(7);
                        }

                        break;
                    }
                    else if (difference.TotalDays >= 1)
                    {
                        // exactly one entire day
                        if (start == new DateTime(start.Year, start.Month, start.Day)
                            && start.AddDays(1) == roundEnd)
                        {
                            result.Add(new Tuple<TimeInterval, string, DateTime>(
                                TimeInterval.OneDay, DateTimeUtil.OneDay(start), start));
                            start = start.AddDays(1);

                            if (start == end)
                            {
                                break;
                            }
                        }
                        else
                        {
                            DateTime cutoff = new DateTime(start.Year, start.Month, start.Day + 1);
                            result.AddRange(MinKeysForRange(start, cutoff, timeInterval));
                            result.AddRange(MinKeysForRange(cutoff, end, timeInterval));
                            break;
                        }
                    }
                    else if (timeInterval == TimeInterval.OneDay)
                    {
                        result.Add(new Tuple<TimeInterval, string, DateTime>(
                            TimeInterval.OneDay, DateTimeUtil.OneDay(start), start));
                        break;
                    }
                    else if (difference.TotalHours >= 1)
                    {
                        // exactly one entire hour
                        if (start == new DateTime(start.Year, start.Month, start.Day, start.Hour, 0, 0)
                            && start.AddHours(1) == roundEnd)
                        {
                            result.Add(new Tuple<TimeInterval, string, DateTime>(
                                TimeInterval.OneHour, DateTimeUtil.OneHour(start), start));
                            start = start.AddHours(1);

                            if (start == end)
                            {
                                break;
                            }
                        }
                        else
                        {
                            DateTime cutoff = new DateTime(start.Year, start.Month, start.Day, start.Hour + 1, 0, 0);
                            result.AddRange(MinKeysForRange(start, cutoff, timeInterval));
                            result.AddRange(MinKeysForRange(cutoff, end, timeInterval));
                            break;
                        }
                    }
                    else if (timeInterval == TimeInterval.OneHour)
                    {
                        result.Add(new Tuple<TimeInterval, string, DateTime>(
                            TimeInterval.OneHour, DateTimeUtil.OneHour(start), start));
                        break;
                    }
                    else if (difference.TotalMinutes >= 15)
                    {
                        // one full hour
                        if (start == new DateTime(start.Year, start.Month, start.Day, start.Hour, 0, 0) && difference.TotalMinutes >= 45)
                        {
                            result.Add(new Tuple<TimeInterval, string, DateTime>(
                                TimeInterval.OneHour, DateTimeUtil.OneHour(start), start));
                        }
                        else
                        {
                            do
                            {
                                result.Add(
                                    new Tuple<TimeInterval, string, DateTime>(
                                        TimeInterval.FifteenMinutes,
                                        DateTimeUtil.FifteenMinutes(start),
                                        start));
                                start = start.AddMinutes(15);
                            }
                            while (start < end);
                        }

                        break;
                    }
                    else if (difference.TotalMinutes == 0)
                    {
                        break;
                    }
                    else if (difference.TotalMinutes < 15)
                    {
                        result.Add(new Tuple<TimeInterval, string, DateTime>(
                            TimeInterval.FifteenMinutes, DateTimeUtil.FifteenMinutes(start), start));
                        break;
                    }
                    else
                    {
                        throw new Exception(
                            string.Format(
                                "case not handled '{0}'\n\tstart: {1}\n\tend: {2}",
                                difference,
                                start,
                            end));
                    }
                }

                return result.ToArray();
            }
        }