Exemplo n.º 1
0
        private void DetermineWhen(ref LexerToken tok, ref DateSpecifier specifier)
        {
            Date today = TimesCommon.Current.CurrentDate;

            specifier = specifier ?? new DateSpecifier();

            switch (tok.Kind)
            {
            case LexerTokenKindEnum.TOK_DATE:
                specifier = tok.Value.GetValue <DateSpecifier>();
                break;

            case LexerTokenKindEnum.TOK_INT:
            {
                int amount = tok.Value.GetValue <int>();
                int adjust = 0;

                tok = Lexer.PeekToken();
                LexerTokenKindEnum kind = tok.Kind;
                switch (kind)
                {
                case LexerTokenKindEnum.TOK_YEAR:
                case LexerTokenKindEnum.TOK_YEARS:
                case LexerTokenKindEnum.TOK_QUARTER:
                case LexerTokenKindEnum.TOK_QUARTERS:
                case LexerTokenKindEnum.TOK_MONTH:
                case LexerTokenKindEnum.TOK_MONTHS:
                case LexerTokenKindEnum.TOK_WEEK:
                case LexerTokenKindEnum.TOK_WEEKS:
                case LexerTokenKindEnum.TOK_DAY:
                case LexerTokenKindEnum.TOK_DAYS:
                    Lexer.NextToken();
                    tok = Lexer.NextToken();
                    switch (tok.Kind)
                    {
                    case LexerTokenKindEnum.TOK_AGO:
                        adjust = -1;
                        break;

                    case LexerTokenKindEnum.TOK_HENCE:
                        adjust = 1;
                        break;

                    default:
                        tok.Unexpected();
                        break;
                    }
                    break;

                default:
                    break;
                }

                Date when = today;

                switch (kind)
                {
                case LexerTokenKindEnum.TOK_YEAR:
                case LexerTokenKindEnum.TOK_YEARS:
                    when = when.AddYears(amount * adjust);
                    break;

                case LexerTokenKindEnum.TOK_QUARTER:
                case LexerTokenKindEnum.TOK_QUARTERS:
                    when = when.AddMonths(amount * 3 * adjust);
                    break;

                case LexerTokenKindEnum.TOK_MONTH:
                case LexerTokenKindEnum.TOK_MONTHS:
                    when = when.AddMonths(amount * adjust);
                    break;

                case LexerTokenKindEnum.TOK_WEEK:
                case LexerTokenKindEnum.TOK_WEEKS:
                    when = when.AddDays(amount * 7 * adjust);
                    break;

                case LexerTokenKindEnum.TOK_DAY:
                case LexerTokenKindEnum.TOK_DAYS:
                    when = when.AddDays(amount * adjust);
                    break;

                default:
                    if (amount > 31)
                    {
                        specifier.Year = amount;
                    }
                    else
                    {
                        specifier.Day = amount;
                    }
                    break;
                }

                if (adjust != 0)
                {
                    specifier = new DateSpecifier(when);
                }
                break;
            }

            case LexerTokenKindEnum.TOK_THIS:
            case LexerTokenKindEnum.TOK_NEXT:
            case LexerTokenKindEnum.TOK_LAST:
            {
                int adjust = 0;
                if (tok.Kind == LexerTokenKindEnum.TOK_NEXT)
                {
                    adjust = 1;
                }
                else if (tok.Kind == LexerTokenKindEnum.TOK_LAST)
                {
                    adjust = -1;
                }

                tok = Lexer.NextToken();
                switch (tok.Kind)
                {
                case LexerTokenKindEnum.TOK_A_MONTH:
                {
                    Date temp = new Date(today.Year, tok.Value.GetValue <int>(), 1);
                    temp      = temp.AddYears(adjust);
                    specifier = new DateSpecifier(temp.Year, (MonthEnum)temp.Month);
                    break;
                }

                case LexerTokenKindEnum.TOK_A_WDAY:
                {
                    Date temp = DateDuration.FindNearest(today, SkipQuantumEnum.WEEKS);
                    while (temp.DayOfWeek != tok.Value.GetValue <DayOfWeek>())
                    {
                        temp = temp.AddDays(1);
                    }
                    temp      = temp.AddDays(7 * adjust);
                    specifier = new DateSpecifier(temp);
                    break;
                }

                case LexerTokenKindEnum.TOK_YEAR:
                {
                    Date temp = today;
                    temp      = temp.AddYears(adjust);
                    specifier = new DateSpecifier(temp.Year);
                    break;
                }

                case LexerTokenKindEnum.TOK_QUARTER:
                {
                    Date baseDate = DateDuration.FindNearest(today, SkipQuantumEnum.QUARTERS);
                    Date temp     = default(Date);
                    if (adjust < 0)
                    {
                        temp = baseDate.AddMonths(3 * adjust);
                    }
                    else if (adjust == 0)
                    {
                        temp = baseDate.AddMonths(3);
                    }
                    else if (adjust > 0)
                    {
                        baseDate = baseDate.AddMonths(3 * adjust);
                        temp     = baseDate.AddMonths(3 * adjust);
                    }
                    specifier = new DateSpecifier(adjust < 0 ? temp : baseDate);
                    break;
                }

                case LexerTokenKindEnum.TOK_WEEK:
                {
                    Date baseDate = DateDuration.FindNearest(today, SkipQuantumEnum.WEEKS);
                    Date temp     = default(Date);
                    if (adjust < 0)
                    {
                        temp = baseDate.AddDays(7 * adjust);
                    }
                    else if (adjust == 0)
                    {
                        temp = baseDate.AddDays(7);
                    }
                    else if (adjust > 0)
                    {
                        baseDate = baseDate.AddDays(7 * adjust);
                        temp     = baseDate.AddDays(7 * adjust);
                    }
                    specifier = new DateSpecifier(adjust < 0 ? temp : baseDate);
                    break;
                }

                case LexerTokenKindEnum.TOK_DAY:
                {
                    Date temp = today;
                    temp      = temp.AddDays(adjust);
                    specifier = new DateSpecifier(temp);
                    break;
                }

                case LexerTokenKindEnum.TOK_MONTH:
                default:
                {
                    Date temp = today;
                    temp      = temp.AddMonths(adjust);
                    specifier = new DateSpecifier(temp.Year, (MonthEnum)temp.Month);
                    break;
                }
                }
                break;
            }

            case LexerTokenKindEnum.TOK_A_MONTH:
                specifier.Month = tok.Value.GetValue <MonthEnum>();
                tok             = Lexer.PeekToken();
                switch (tok.Kind)
                {
                case LexerTokenKindEnum.TOK_INT:
                    specifier.Year = tok.Value.GetValue <int>();
                    break;

                case LexerTokenKindEnum.END_REACHED:
                    break;

                default:
                    break;
                }
                break;

            case LexerTokenKindEnum.TOK_A_WDAY:
                specifier.WDay = tok.Value.GetValue <DayOfWeek>();
                break;

            case LexerTokenKindEnum.TOK_TODAY:
                specifier = new DateSpecifier(today);
                break;

            case LexerTokenKindEnum.TOK_TOMORROW:
                specifier = new DateSpecifier(today.AddDays(1));
                break;

            case LexerTokenKindEnum.TOK_YESTERDAY:
                specifier = new DateSpecifier(today.AddDays(-1));
                break;

            default:
                tok.Unexpected();
                break;
            }
        }
Exemplo n.º 2
0
        public void Stabilize(Date?date = null)
        {
            if (date.HasValue)
            {
                Logger.Current.Debug("times.interval", () => String.Format("stabilize: with date = {0}", date));
            }

            if (date.HasValue & !Aligned)
            {
                Logger.Current.Debug("times.interval", () => "stabilize: date passed, but not aligned");
                if (Duration != null)
                {
                    Logger.Current.Debug("times.interval", () => String.Format("stabilize: aligning with a duration: {0}", Duration));

                    // The interval object has not been seeded with a start date yet, so
                    // find the nearest period before on on date which fits, if possible.
                    //
                    // Find an efficient starting point for the upcoming while loop.  We
                    // want a date early enough that the range will be correct, but late
                    // enough that we don't spend hundreds of thousands of loops skipping
                    // through time.
                    Date?initialStart  = Start ?? Begin;
                    Date?initialFinish = Finish ?? End;

                    if (initialStart.HasValue)
                    {
                        Logger.Current.Debug("times.interval", () => String.Format("stabilize: initial_start  = {0}", initialStart));
                    }
                    if (initialFinish.HasValue)
                    {
                        Logger.Current.Debug("times.interval", () => String.Format("stabilize: initial_finish = {0}", initialFinish));
                    }

                    Date when = Start ?? date.Value;

                    switch (Duration.Quantum)
                    {
                    case SkipQuantumEnum.MONTHS:
                    case SkipQuantumEnum.QUARTERS:
                    case SkipQuantumEnum.YEARS:
                        Logger.Current.Debug("times.interval", () => "stabilize: monthly, quarterly or yearly duration");
                        // These start on most recent period start quantum before when
                        // DEBUG("times.interval", "stabilize: monthly, quarterly or yearly duration");
                        Start = DateDuration.FindNearest(when, Duration.Quantum);
                        break;

                    case SkipQuantumEnum.WEEKS:
                        // Weeks start on the beginning of week prior to 400 remainder period length
                        // Either the first quanta of the period or the last quanta of the period seems more sensible
                        // implies period is never less than 400 days not too unreasonable
                        // DEBUG("times.interval", "stabilize: weekly duration");
                        Logger.Current.Debug("times.interval", () => "stabilize: weekly duration");
                        int period = Duration.Length * 7;
                        Start = DateDuration.FindNearest(when.AddDays(-(period + 400 % period)), Duration.Quantum);
                        break;

                    default:
                        // multiples of days have a quanta of 1 day so should not have the start date adjusted to a quanta
                        Logger.Current.Debug("times.interval", () => "stabilize: daily duration - stable by definition");
                        Start = when;
                        break;
                    }
                    Logger.Current.Debug("times.interval", () => String.Format("stabilize: beginning start date = {0}", Start));

                    while (Start < date)
                    {
                        DateInterval nextInterval = new DateInterval(this);
                        nextInterval++;

                        if (nextInterval.Start.HasValue && nextInterval.Start <= date)
                        {
                            Assign(nextInterval);
                        }
                        else
                        {
                            EndOfDuration = null;
                            Next          = null;
                            break;
                        }
                    }

                    Logger.Current.Debug("times.interval", () => String.Format("stabilize: proposed start date = {0}", Start));

                    if (initialStart.HasValue && (!Start.HasValue || Start < initialStart))
                    {
                        // Using the discovered start, find the end of the period
                        ResolveEnd();
                        Start = initialStart;
                        Logger.Current.Debug("times.interval", () => "stabilize: start reset to initial start");
                    }
                    if (initialFinish.HasValue && (!Finish.HasValue || Finish > initialFinish))
                    {
                        Finish = initialFinish;
                        Logger.Current.Debug("times.interval", () => "stabilize: finish reset to initial finish");
                    }

                    if (Start.HasValue)
                    {
                        Logger.Current.Debug("times.interval", () => String.Format("stabilize: final start  = {0}", Start));
                    }
                    if (Finish.HasValue)
                    {
                        Logger.Current.Debug("times.interval", () => String.Format("stabilize: final finish = {0}", Finish));
                    }
                }
                else if (Range != null)
                {
                    Start  = Range.Begin;
                    Finish = Range.End;
                }
                Aligned = true;
            }

            // If there is no duration, then if we've reached here the date falls
            // between start and finish.
            if (Duration == null)
            {
                Logger.Current.Debug("times.interval", () => "stabilize: there was no duration given");
                if (!Start.HasValue && !Finish.HasValue)
                {
                    throw new DateError(DateError.ErrorMessageInvalidDateIntervalNeitherStartNorFinishNorDuration);
                }
            }
            else
            {
                ResolveEnd();
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Ported from date_parser_t::parse()
        /// </summary>
        public DateInterval Parse()
        {
            DateSpecifier sinceSpecifier     = null;
            DateSpecifier untilSpecifier     = null;
            DateSpecifier inclusionSpecifier = null;

            DateInterval period       = new DateInterval();
            Date         today        = TimesCommon.Current.CurrentDate;
            bool         endInclusive = false;

            for (LexerToken tok = Lexer.NextToken(); tok.Kind != LexerTokenKindEnum.END_REACHED; tok = Lexer.NextToken())
            {
                switch (tok.Kind)
                {
                case LexerTokenKindEnum.TOK_DATE:
                case LexerTokenKindEnum.TOK_INT:
                case LexerTokenKindEnum.TOK_A_MONTH:
                case LexerTokenKindEnum.TOK_A_WDAY:
                    DetermineWhen(ref tok, ref inclusionSpecifier);
                    break;

                case LexerTokenKindEnum.TOK_DASH:
                    if (inclusionSpecifier != null)
                    {
                        sinceSpecifier     = inclusionSpecifier;
                        inclusionSpecifier = null;
                        tok = Lexer.NextToken();
                        DetermineWhen(ref tok, ref untilSpecifier);

                        // The dash operator is special: it has an _inclusive_ end.
                        endInclusive = true;
                    }
                    else
                    {
                        tok.Unexpected();
                    }
                    break;

                case LexerTokenKindEnum.TOK_SINCE:
                    if (sinceSpecifier != null)
                    {
                        tok.Unexpected();
                    }
                    else
                    {
                        tok = Lexer.NextToken();
                        DetermineWhen(ref tok, ref sinceSpecifier);
                    }
                    break;

                case LexerTokenKindEnum.TOK_UNTIL:
                    if (untilSpecifier != null)
                    {
                        tok.Unexpected();
                    }
                    else
                    {
                        tok = Lexer.NextToken();
                        DetermineWhen(ref tok, ref untilSpecifier);
                    }
                    break;

                case LexerTokenKindEnum.TOK_IN:
                    if (inclusionSpecifier != null)
                    {
                        tok.Unexpected();
                    }
                    else
                    {
                        tok = Lexer.NextToken();
                        DetermineWhen(ref tok, ref inclusionSpecifier);
                    }
                    break;

                case LexerTokenKindEnum.TOK_THIS:
                case LexerTokenKindEnum.TOK_NEXT:
                case LexerTokenKindEnum.TOK_LAST:
                {
                    int adjust = 0;
                    if (tok.Kind == LexerTokenKindEnum.TOK_NEXT)
                    {
                        adjust = 1;
                    }
                    else if (tok.Kind == LexerTokenKindEnum.TOK_LAST)
                    {
                        adjust = -1;
                    }

                    tok = Lexer.NextToken();
                    switch (tok.Kind)
                    {
                    case LexerTokenKindEnum.TOK_INT:
                    {
                        int amount = tok.Value.GetValue <int>();

                        Date baseDate = today;
                        Date end      = today;

                        if (adjust == 0)
                        {
                            adjust = 1;
                        }

                        tok = Lexer.NextToken();
                        switch (tok.Kind)
                        {
                        case LexerTokenKindEnum.TOK_YEARS:
                            baseDate = baseDate.AddYears(amount * adjust);
                            break;

                        case LexerTokenKindEnum.TOK_QUARTERS:
                            baseDate = baseDate.AddMonths(amount * adjust * 3);
                            break;

                        case LexerTokenKindEnum.TOK_MONTHS:
                            baseDate = baseDate.AddMonths(amount * adjust);
                            break;

                        case LexerTokenKindEnum.TOK_WEEKS:
                            baseDate = baseDate.AddDays(amount * adjust * 7);
                            break;

                        case LexerTokenKindEnum.TOK_DAYS:
                            baseDate = baseDate.AddDays(amount * adjust);
                            break;

                        default:
                            tok.Unexpected();
                            break;
                        }

                        if (adjust > 0)
                        {
                            Date temp = baseDate;
                            baseDate = end;
                            end      = temp;
                        }

                        sinceSpecifier = new DateSpecifier(baseDate);
                        untilSpecifier = new DateSpecifier(end);
                        break;
                    }

                    case LexerTokenKindEnum.TOK_A_MONTH:
                    {
                        DetermineWhen(ref tok, ref inclusionSpecifier);

                        Date temp = new Date(today.Year, (int)inclusionSpecifier.Month, 1);
                        temp = temp.AddYears(adjust);
                        inclusionSpecifier = new DateSpecifier(temp.Year, (MonthEnum)temp.Month);
                        break;
                    }

                    case LexerTokenKindEnum.TOK_A_WDAY:
                    {
                        DetermineWhen(ref tok, ref inclusionSpecifier);

                        Date temp = DateDuration.FindNearest(today, SkipQuantumEnum.WEEKS);
                        while (temp.DayOfWeek != inclusionSpecifier.WDay)
                        {
                            temp = temp.AddDays(1);
                        }
                        temp = temp.AddDays(7 * adjust);
                        inclusionSpecifier = new DateSpecifier(temp);
                        break;
                    }

                    case LexerTokenKindEnum.TOK_YEAR:
                    {
                        Date temp = today;
                        temp = temp.AddYears(adjust);
                        inclusionSpecifier = new DateSpecifier(temp.Year);
                        break;
                    }

                    case LexerTokenKindEnum.TOK_QUARTER:
                    {
                        Date baseDate = DateDuration.FindNearest(today, SkipQuantumEnum.QUARTERS);
                        Date temp;
                        if (adjust < 0)
                        {
                            temp = baseDate.AddMonths(3 * adjust);
                        }
                        else if (adjust == 0)
                        {
                            temp = baseDate.AddMonths(3);
                        }
                        else
                        {
                            baseDate = baseDate.AddMonths(3 * adjust);
                            temp     = baseDate.AddMonths(3 * adjust);
                        }
                        sinceSpecifier = new DateSpecifier(adjust < 0 ? temp : baseDate);
                        untilSpecifier = new DateSpecifier(adjust < 0 ? baseDate : temp);
                        break;
                    }

                    case LexerTokenKindEnum.TOK_WEEK:
                    {
                        Date baseDate = DateDuration.FindNearest(today, SkipQuantumEnum.WEEKS);
                        Date temp;
                        if (adjust < 0)
                        {
                            temp = baseDate.AddDays(7 * adjust);
                        }
                        else if (adjust == 0)
                        {
                            temp = baseDate.AddDays(7);
                        }
                        else
                        {
                            baseDate = baseDate.AddDays(7 * adjust);
                            temp     = baseDate.AddDays(7 * adjust);
                        }
                        sinceSpecifier = new DateSpecifier(adjust < 0 ? temp : baseDate);
                        untilSpecifier = new DateSpecifier(adjust < 0 ? baseDate : temp);
                        break;
                    }

                    case LexerTokenKindEnum.TOK_DAY:
                    {
                        Date temp = today;
                        temp = temp.AddDays(adjust);
                        inclusionSpecifier = new DateSpecifier(temp);
                        break;
                    }

                    case LexerTokenKindEnum.TOK_MONTH:
                    default:
                    {
                        Date temp = today;
                        temp = temp.AddMonths(adjust);
                        inclusionSpecifier = new DateSpecifier(temp.Year, (MonthEnum)temp.Month);
                        break;
                    }
                    }
                    break;
                }

                case LexerTokenKindEnum.TOK_TODAY:
                    inclusionSpecifier = new DateSpecifier(today);
                    break;

                case LexerTokenKindEnum.TOK_TOMORROW:
                    inclusionSpecifier = new DateSpecifier(today.AddDays(1));
                    break;

                case LexerTokenKindEnum.TOK_YESTERDAY:
                    inclusionSpecifier = new DateSpecifier(today.AddDays(-1));
                    break;

                case LexerTokenKindEnum.TOK_EVERY:
                    tok = Lexer.NextToken();
                    if (tok.Kind == LexerTokenKindEnum.TOK_INT)
                    {
                        int quantity = tok.Value.GetValue <int>();
                        tok = Lexer.NextToken();
                        switch (tok.Kind)
                        {
                        case LexerTokenKindEnum.TOK_YEARS:
                            period.Duration = new DateDuration(SkipQuantumEnum.YEARS, quantity);
                            break;

                        case LexerTokenKindEnum.TOK_QUARTERS:
                            period.Duration = new DateDuration(SkipQuantumEnum.QUARTERS, quantity);
                            break;

                        case LexerTokenKindEnum.TOK_MONTHS:
                            period.Duration = new DateDuration(SkipQuantumEnum.MONTHS, quantity);
                            break;

                        case LexerTokenKindEnum.TOK_WEEKS:
                            period.Duration = new DateDuration(SkipQuantumEnum.WEEKS, quantity);
                            break;

                        case LexerTokenKindEnum.TOK_DAYS:
                            period.Duration = new DateDuration(SkipQuantumEnum.DAYS, quantity);
                            break;

                        default:
                            tok.Unexpected();
                            break;
                        }
                    }
                    else
                    {
                        switch (tok.Kind)
                        {
                        case LexerTokenKindEnum.TOK_YEAR:
                            period.Duration = new DateDuration(SkipQuantumEnum.YEARS, 1);
                            break;

                        case LexerTokenKindEnum.TOK_QUARTER:
                            period.Duration = new DateDuration(SkipQuantumEnum.QUARTERS, 1);
                            break;

                        case LexerTokenKindEnum.TOK_MONTH:
                            period.Duration = new DateDuration(SkipQuantumEnum.MONTHS, 1);
                            break;

                        case LexerTokenKindEnum.TOK_WEEK:
                            period.Duration = new DateDuration(SkipQuantumEnum.WEEKS, 1);
                            break;

                        case LexerTokenKindEnum.TOK_DAY:
                            period.Duration = new DateDuration(SkipQuantumEnum.DAYS, 1);
                            break;

                        default:
                            tok.Unexpected();
                            break;
                        }
                    }
                    break;

                case LexerTokenKindEnum.TOK_YEARLY:
                    period.Duration = new DateDuration(SkipQuantumEnum.YEARS, 1);
                    break;

                case LexerTokenKindEnum.TOK_QUARTERLY:
                    period.Duration = new DateDuration(SkipQuantumEnum.QUARTERS, 1);
                    break;

                case LexerTokenKindEnum.TOK_BIMONTHLY:
                    period.Duration = new DateDuration(SkipQuantumEnum.MONTHS, 2);
                    break;

                case LexerTokenKindEnum.TOK_MONTHLY:
                    period.Duration = new DateDuration(SkipQuantumEnum.MONTHS, 1);
                    break;

                case LexerTokenKindEnum.TOK_BIWEEKLY:
                    period.Duration = new DateDuration(SkipQuantumEnum.WEEKS, 2);
                    break;

                case LexerTokenKindEnum.TOK_WEEKLY:
                    period.Duration = new DateDuration(SkipQuantumEnum.WEEKS, 1);
                    break;

                case LexerTokenKindEnum.TOK_DAILY:
                    period.Duration = new DateDuration(SkipQuantumEnum.DAYS, 1);
                    break;

                default:
                    tok.Unexpected();
                    break;
                }
            }

            if (sinceSpecifier != null || untilSpecifier != null)
            {
                DateRange range = new DateRange(sinceSpecifier, untilSpecifier)
                {
                    EndExclusive = endInclusive
                };
                period.Range = new DateSpecifierOrRange(range);
            }
            else if (inclusionSpecifier != null)
            {
                period.Range = new DateSpecifierOrRange(inclusionSpecifier);
            }
            else
            {
                /* otherwise, it's something like "monthly", with no date reference */
            }

            return(period);
        }