/// <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_YEAR: 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); }
public DateSpecifierOrRange(DateRange range) : this() { SpecifierOrRange.SetValue(range); }