public static DateTime ToTimeFrameStart(this DateTime moment, UnitPeriod unitPeriod, uint length = 1)
        {
            // TODO (low): support offset, e.g. 1 hours that starts at 15th minute

            if (length == 0)
            {
                throw new InvalidOperationException("Length is zero");
            }
            long divisor;

            switch (unitPeriod)
            {
            case UnitPeriod.Tick:
                if (length != 1)
                {
                    throw new InvalidOperationException("Tick length != 1 is meaningless");
                }
                return(moment);

            case UnitPeriod.Millisecond:
                divisor = TimeSpan.TicksPerMillisecond * length;
                return(new DateTime((moment.Ticks / (divisor)) * (divisor), moment.Kind));

            case UnitPeriod.Second:
                divisor = TimeSpan.TicksPerSecond * length;
                return(new DateTime((moment.Ticks / (divisor)) * (divisor), moment.Kind));

            case UnitPeriod.Minute:
                divisor = TimeSpan.TicksPerMinute * length;
                return(new DateTime((moment.Ticks / (divisor)) * (divisor), moment.Kind));

            case UnitPeriod.Hour:
                divisor = TimeSpan.TicksPerHour * length;
                return(new DateTime((moment.Ticks / (divisor)) * (divisor), moment.Kind));

            case UnitPeriod.Day:
                divisor = TimeSpan.TicksPerDay * length;
                return(new DateTime((moment.Ticks / (divisor)) * (divisor), moment.Kind));

            case UnitPeriod.Month:
                if (length != 1)
                {
                    throw new NotSupportedException();
                }
                return(new DateTime(moment.Year, moment.Month, 1, 0, 0, 0, moment.Kind));

            case UnitPeriod.Eternity:
                return(DateTime.MinValue);

            default:
                throw new ArgumentOutOfRangeException(nameof(unitPeriod), unitPeriod, null);
            }
        }
 public TimeSliceAsyncEnumerable(IEnumerable <KeyValuePair <DateTime, TValue> > series, Func <TValue, TAggr> initState,
                                 Func <TAggr, TValue, TAggr> aggregator, UnitPeriod unitPeriod, int periodLength = 1, int offset = 0)
 {
     if (periodLength <= 0)
     {
         throw new ArgumentOutOfRangeException(nameof(periodLength));
     }
     if (offset < 0)
     {
         throw new ArgumentOutOfRangeException(nameof(offset));
     }
     if (offset >= periodLength)
     {
         throw new ArgumentException("Offset must be smaller that period length");
     }
     _series       = series;
     _initState    = initState;
     _aggregator   = aggregator;
     _unitPeriod   = unitPeriod;
     _periodLength = periodLength;
     _offset       = offset;
 }
 public static IAsyncEnumerable <KeyValuePair <DateTime, TAggr> > TimeSlice <TValue, TAggr>(
     this IEnumerable <KeyValuePair <DateTime, TValue> > series, Func <TValue, TAggr> initState,
     Func <TAggr, TValue, TAggr> aggregator, UnitPeriod unitPeriod, int periodLength = 1, int offset = 0)
 {
     return(new TimeSliceAsyncEnumerable <TValue, TAggr>(series, initState, aggregator, unitPeriod, periodLength, offset));
 }