-////////////////////////////////////////////////////////////////////////////////
-//
-// Copyright 2006 - 2017, Paul Beckingham, Federico Hernandez.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-//
-// http://www.opensource.org/licenses/mit-license.php
-//
-////////////////////////////////////////////////////////////////////////////////
-
-#include <cmake.h>
-#include <Datetime.h>
-#include <algorithm>
-#include <iostream>
-#include <sstream>
-#include <iomanip>
-#include <cassert>
-#include <stdlib.h>
-#include <shared.h>
-#include <format.h>
-#include <unicode.h>
-#include <utf8.h>
-
-static std::vector <std::string> dayNames {
- "sunday",
- "monday",
- "tuesday",
- "wednesday",
- "thursday",
- "friday",
- "saturday"};
-
-static std::vector <std::string> monthNames {
- "january",
- "february",
- "march",
- "april",
- "may",
- "june",
- "july",
- "august",
- "september",
- "october",
- "november",
- "december"};
-
-int Datetime::weekstart = 1; // Monday, per ISO-8601.
-int Datetime::minimumMatchLength = 3;
-bool Datetime::isoEnabled = true;
-bool Datetime::standaloneDateEnabled = true;
-bool Datetime::standaloneTimeEnabled = true;
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime::Datetime ()
-{
- clear ();
- _date = time (nullptr);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime::Datetime (const std::string& input, const std::string& format)
-{
- clear ();
- std::string::size_type start = 0;
- if (! parse (input, start, format))
- throw ::format ("'{1}' is not a valid date in the '{2}' format.", input, format);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime::Datetime (const time_t t)
-{
- clear ();
- _date = t;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime::Datetime (const int y, const int m, const int d)
-{
- // Protect against arguments being passed in the wrong order.
- assert (y >= 1969 && y < 2100);
- assert (m >= 1 && m <= 12);
- assert (d >= 1 && d <= 31);
-
- clear ();
-
- // Error if not valid.
- struct tm t {};
- t.tm_isdst = -1; // Requests that mktime determine summer time effect.
- t.tm_mday = d;
- t.tm_mon = m - 1;
- t.tm_year = y - 1900;
-
- _date = mktime (&t);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime::Datetime (const int y, const int m, const int d,
- const int hr, const int mi, const int se)
-{
- // Protect against arguments being passed in the wrong order.
- assert (y >= 1969 && y < 2100);
- assert (m >= 1 && m <= 12);
- assert (d >= 1 && d <= 31);
- assert (hr >= 0 && hr <= 24);
- assert (mi >= 0 && mi < 60);
- assert (se >= 0 && se < 60);
-
- clear ();
-
- // Error if not valid.
- struct tm t {};
- t.tm_isdst = -1; // Requests that mktime determine summer time effect.
- t.tm_mday = d;
- t.tm_mon = m - 1;
- t.tm_year = y - 1900;
- t.tm_hour = hr;
- t.tm_min = mi;
- t.tm_sec = se;
-
- _date = mktime (&t);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse (
- const std::string& input,
- std::string::size_type& start,
- const std::string& format)
-{
- auto i = start;
- Pig pig (input);
- if (i)
- pig.skipN (static_cast <int> (i));
-
- auto checkpoint = pig.cursor ();
-
- // Parse epoch first, as it's the most common scenario.
- if (parse_epoch (pig))
- {
- // ::validate and ::resolve are not needed in this case.
- start = pig.cursor ();
- return true;
- }
-
- if (parse_formatted (pig, format))
- {
- // Check the values and determine time_t.
- if (validate ())
- {
- start = pig.cursor ();
- resolve ();
- return true;
- }
- }
-
- // Allow parse_date_time and parse_date_time_ext regardless of
- // Datetime::isoEnabled setting, because these formats are relied upon by
- // the 'import' command, JSON parser and hook system.
- if (parse_date_time_ext (pig) || // Strictest first.
- parse_date_time (pig) ||
- (Datetime::isoEnabled &&
- ( parse_date_ext (pig) ||
- (Datetime::standaloneDateEnabled && parse_date (pig)) ||
- parse_time_utc_ext (pig) ||
- parse_time_utc (pig) ||
- parse_time_off_ext (pig) ||
- parse_time_off (pig) ||
- parse_time_ext (pig) ||
- (Datetime::standaloneTimeEnabled && parse_time (pig)) // Time last, as it is the most permissive.
- )
- )
- )
- {
- // Check the values and determine time_t.
- if (validate ())
- {
- start = pig.cursor ();
- resolve ();
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
-
- if (parse_named (pig))
- {
- // ::validate and ::resolve are not needed in this case.
- start = pig.cursor ();
- return true;
- }
-
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-void Datetime::clear ()
-{
- _year = 0;
- _month = 0;
- _week = 0;
- _weekday = 0;
- _julian = 0;
- _day = 0;
- _seconds = 0;
- _offset = 0;
- _utc = false;
- _date = 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse_formatted (Pig& pig, const std::string& format)
-{
- // Short-circuit on missing format.
- if (format == "")
- return false;
-
- auto checkpoint = pig.cursor ();
-
- int month {-1}; // So we can check later.
- int day {-1};
- int year {-1};
- int hour {-1};
- int minute {-1};
- int second {-1};
-
- // For parsing, unused.
- int wday {-1};
- int week {-1};
-
- for (unsigned int f = 0; f < format.length (); ++f)
- {
- switch (format[f])
- {
- case 'm':
- if (pig.getDigit (month))
- {
- if (month == 0)
- pig.getDigit (month);
-
- if (month == 1)
- if (pig.getDigit (month))
- month += 10;
- }
- else
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 'M':
- if (! pig.getDigit2 (month))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 'd':
- if (pig.getDigit (day))
- {
- if (day == 0)
- pig.getDigit (day);
-
- if (day == 1 || day == 2 || day == 3)
- {
- int tens = day;
- if (pig.getDigit (day))
- day += 10 * tens;
- }
- }
- else
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 'D':
- if (! pig.getDigit2 (day))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 'y':
- if (! pig.getDigit2 (year))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- year += 2000;
- break;
-
- case 'Y':
- if (! pig.getDigit4 (year))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 'h':
- if (pig.getDigit (hour))
- {
- if (hour == 0)
- pig.getDigit (hour);
-
- if (hour == 1 || hour == 2)
- {
- int tens = hour;
- if (pig.getDigit (hour))
- hour += 10 * tens;
- }
- }
- else
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 'H':
- if (! pig.getDigit2 (hour))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 'n':
- if (pig.getDigit (minute))
- {
- if (minute == 0)
- pig.getDigit (minute);
-
- if (minute < 6)
- {
- int tens = minute;
- if (pig.getDigit (minute))
- minute += 10 * tens;
- }
- }
- else
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 'N':
- if (! pig.getDigit2 (minute))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 's':
- if (pig.getDigit (second))
- {
- if (second == 0)
- pig.getDigit (second);
-
- if (second < 6)
- {
- int tens = second;
- if (pig.getDigit (second))
- second += 10 * tens;
- }
- }
- else
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 'S':
- if (! pig.getDigit2 (second))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 'v':
- if (pig.getDigit (week))
- {
- if (week == 0)
- pig.getDigit (week);
-
- if (week < 6)
- {
- int tens = week;
- if (pig.getDigit (week))
- week += 10 * tens;
- }
- }
- else
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 'V':
- if (! pig.getDigit2 (week))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
-
- case 'a':
- wday = Datetime::dayOfWeek (pig.str ().substr (0, 3));
- if (wday == -1)
- {
- pig.restoreTo (checkpoint);
- return false;
- }
-
- pig.skipN (3);
- break;
-
- case 'A':
- {
- std::string dayName;
- if (pig.getUntil (format[f + 1], dayName))
- {
- wday = Datetime::dayOfWeek (dayName);
- if (wday == -1)
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- }
- }
- break;
-
- case 'b':
- month = Datetime::monthOfYear (pig.str ().substr (0, 3));
- if (month == -1)
- {
- pig.restoreTo (checkpoint);
- return false;
- }
-
- pig.skipN (3);
- break;
-
- case 'B':
- {
- std::string monthName;
- if (pig.getUntil (format[f + 1], monthName))
- {
- month = Datetime::monthOfYear (monthName);
- if (month == -1)
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- }
- }
- break;
-
- default:
- if (! pig.skip (format[f]))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- break;
- }
- }
-
- // It is possible that the format='Y-M-D', and the input is Y-M-DTH:N:SZ, and
- // this should not be considered a match.
- if (! pig.eos () && ! unicodeWhitespace (pig.peek ()))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
-
- // Missing values are filled in from the current date.
- if (year == -1)
- {
- Datetime now;
- year = now.year ();
- if (month == -1)
- {
- month = now.month ();
- if (day == -1)
- {
- day = now.day ();
- if (hour == -1)
- {
- hour = now.hour ();
- if (minute == -1)
- {
- minute = now.minute ();
- if (second == -1)
- second = now.second ();
- }
- }
- }
- }
- }
-
- // Any remaining undefined values are assigned defaults.
- if (month == -1) month = 1;
- if (day == -1) day = 1;
- if (hour == -1) hour = 0;
- if (minute == -1) minute = 0;
- if (second == -1) second = 0;
-
- _year = year;
- _month = month;
- _day = day;
- _seconds = (hour * 3600) + (minute * 60) + second;
-
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Note how these are all single words.
-//
-// Examples and descriptions, assuming now == 2017-03-05T12:34:56.
-//
-// Example Notes
-// ------------------- ------------------
-// now 2017-03-05T12:34:56 Unaffected
-// yesterday 2017-03-04T00:00:00 Unaffected
-// today 2017-03-05T00:00:00 Unaffected
-// tomorrow 2017-03-06T00:00:00 Unaffected
-// <ordinal> 12th 2017-03-12T00:00:00
-// <day> monday 2017-03-06T00:00:00
-// <month> april 2017-04-01T00:00:00
-// later 2038-01-18T00:00:00 Unaffected
-// someday 2038-01-18T00:00:00 Unaffected
-// sopd 2017-03-04T00:00:00 Unaffected
-// sod 2017-03-05T00:00:00 Unaffected
-// sond 2017-03-06T00:00:00 Unaffected
-// eopd 2017-03-05T00:00:00 Unaffected
-// eod 2017-03-06T00:00:00 Unaffected
-// eond 2017-03-07T00:00:00 Unaffected
-// sopw 2017-02-26T00:00:00 Unaffected
-// sow 2017-03-05T00:00:00 Unaffected
-// sonw 2017-03-12T00:00:00 Unaffected
-// eopw 2017-03-05T00:00:00 Unaffected
-// eow 2017-03-12T00:00:00 Unaffected
-// eonw 2017-03-19T00:00:00 Unaffected
-// sopww 2017-02-27T00:00:00 Unaffected
-// soww 2017-03-06T00:00:00
-// sonww 2017-03-06T00:00:00 Unaffected
-// eopww 2017-03-03T00:00:00 Unaffected
-// eoww 2017-03-10T00:00:00
-// eonww 2017-03-17T00:00:00 Unaffected
-// sopm 2017-02-01T00:00:00 Unaffected
-// som 2017-03-01T00:00:00 Unaffected
-// sonm 2017-04-01T00:00:00 Unaffected
-// eopm 2017-03-01T00:00:00 Unaffected
-// eom 2017-04-01T00:00:00 Unaffected
-// eonm 2017-05-01T00:00:00 Unaffected
-// sopq 2017-10-01T00:00:00 Unaffected
-// soq 2017-01-01T00:00:00 Unaffected
-// sonq 2017-04-01T00:00:00 Unaffected
-// eopq 2017-01-01T00:00:00 Unaffected
-// eoq 2017-04-01T00:00:00 Unaffected
-// eonq 2017-07-01T00:00:00 Unaffected
-// sopy 2016-01-01T00:00:00 Unaffected
-// soy 2017-01-01T00:00:00 Unaffected
-// sony 2018-01-01T00:00:00 Unaffected
-// eopy 2017-01-01T00:00:00 Unaffected
-// eoy 2018-01-01T00:00:00 Unaffected
-// eony 2019-01-01T00:00:00 Unaffected
-// easter 2017-04-16T00:00:00
-// eastermonday 2017-04-16T00:00:00
-// ascension 2017-05-25T00:00:00
-// pentecost 2017-06-04T00:00:00
-// goodfriday 2017-04-14T00:00:00
-// midsommar 2017-06-24T00:00:00 midnight, 1st Saturday after 20th June
-// midsommarafton 2017-06-23T00:00:00 midnight, 1st Friday after 19th June
-// juhannus 2017-06-23T00:00:00 midnight, 1st Friday after 19th June
-//
-bool Datetime::parse_named (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- // Experimental handling of date phrases, such as "first monday in march".
- // Note that this requires that phrases are deliminted by EOS or WS.
- std::string token;
- std::vector <std::string> tokens;
- while (pig.getUntilWS (token))
- {
- tokens.push_back (token);
- if (! pig.skipWS ())
- break;
- }
-
-/*
- // This grpoup contains "1st monday ..." which must be processed before
- // initializeOrdinal below.
- if (initializeNthDayInMonth (tokens))
- {
- return true;
- }
-*/
-
- // Restoration necessary because of the tokenization.
- pig.restoreTo (checkpoint);
-
- if (initializeNow (pig) ||
- initializeYesterday (pig) ||
- initializeToday (pig) ||
- initializeTomorrow (pig) ||
- initializeOrdinal (pig) ||
- initializeDayName (pig) ||
- initializeMonthName (pig) ||
- initializeLater (pig) ||
- initializeSopd (pig) ||
- initializeSod (pig) ||
- initializeSond (pig) ||
- initializeEopd (pig) ||
- initializeEod (pig) ||
- initializeEond (pig) ||
- initializeSopw (pig) ||
- initializeSow (pig) ||
- initializeSonw (pig) ||
- initializeEopw (pig) ||
- initializeEow (pig) ||
- initializeEonw (pig) ||
- initializeSopww (pig) || // Must appear after sopw
- initializeSonww (pig) || // Must appear after sonw
- initializeSoww (pig) || // Must appear after sow
- initializeEopww (pig) || // Must appear after eopw
- initializeEonww (pig) || // Must appear after eonw
- initializeEoww (pig) || // Must appear after eow
- initializeSopm (pig) ||
- initializeSom (pig) ||
- initializeSonm (pig) ||
- initializeEopm (pig) ||
- initializeEom (pig) ||
- initializeEonm (pig) ||
- initializeSopq (pig) ||
- initializeSoq (pig) ||
- initializeSonq (pig) ||
- initializeEopq (pig) ||
- initializeEoq (pig) ||
- initializeEonq (pig) ||
- initializeSopy (pig) ||
- initializeSoy (pig) ||
- initializeSony (pig) ||
- initializeEopy (pig) ||
- initializeEoy (pig) ||
- initializeEony (pig) ||
- initializeEaster (pig) ||
- initializeMidsommar (pig) ||
- initializeMidsommarafton (pig) ||
- initializeInformalTime (pig))
- {
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Valid epoch values are unsigned integers after 1980-01-01T00:00:00Z. This
-// restriction means that '12' will not be identified as an epoch date.
-bool Datetime::parse_epoch (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- int epoch {};
- if (pig.getDigits (epoch) &&
- ! unicodeLatinAlpha (pig.peek ()) &&
- epoch >= 315532800)
- {
- _date = static_cast <time_t> (epoch);
- //std::cout << "# parse_epoch \e[33msucceed\e[0m " << pig.dump () << "\n";
- return true;
- }
-
- //std::cout << "# parse_epoch fail\n";
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// date_ext 'T' time_utc_ext 'Z'
-// date_ext 'T' time_off_ext
-// date_ext 'T' time_ext
-bool Datetime::parse_date_time_ext (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (parse_date_ext (pig) &&
- pig.skip ('T') &&
- (parse_time_utc_ext (pig) ||
- parse_time_off_ext (pig) ||
- parse_time_ext (pig)))
- {
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// YYYY-MM-DD
-// YYYY-MM
-// YYYY-DDD
-// YYYY-Www-D
-// YYYY-Www
-bool Datetime::parse_date_ext (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- int year {};
- if (parse_year (pig, year) &&
- pig.skip ('-'))
- {
- auto checkpointYear = pig.cursor ();
-
- int month {};
- int day {};
- int julian {};
-
- if (pig.skip ('W') &&
- parse_week (pig, _week))
- {
- if (pig.skip ('-') &&
- pig.getDigit (_weekday))
- {
- // What is happening here - must be something to do?
- }
-
- if (! unicodeLatinDigit (pig.peek ()))
- {
- _year = year;
- return true;
- }
- }
-
- pig.restoreTo (checkpointYear);
-
- if (parse_month (pig, month) &&
- pig.skip ('-') &&
- parse_day (pig, day) &&
- ! unicodeLatinDigit (pig.peek ()))
- {
- _year = year;
- _month = month;
- _day = day;
- return true;
- }
-
- pig.restoreTo (checkpointYear);
-
- if (parse_julian (pig, julian) &&
- ! unicodeLatinDigit (pig.peek ()))
- {
- _year = year;
- _julian = julian;
- return true;
- }
-
- pig.restoreTo (checkpointYear);
-
- if (parse_month (pig, month) &&
- pig.peek () != '-' &&
- ! unicodeLatinDigit (pig.peek ()))
- {
- _year = year;
- _month = month;
- _day = 1;
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ±hh[:mm]
-bool Datetime::parse_off_ext (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- int sign = pig.peek ();
- if (sign == '+' || sign == '-')
- {
- pig.skipN (1);
-
- int hour {0};
- int minute {0};
-
- if (parse_off_hour (pig, hour))
- {
- if (pig.skip (':'))
- {
- if (! parse_off_minute (pig, minute))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- }
-
- _offset = (hour * 3600) + (minute * 60);
- if (sign == '-')
- _offset = - _offset;
-
- if (! unicodeLatinDigit (pig.peek ()))
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// hh:mm[:ss]
-bool Datetime::parse_time_ext (Pig& pig, bool terminated)
-{
- auto checkpoint = pig.cursor ();
-
- int hour {};
- int minute {};
- if (parse_hour (pig, hour) &&
- pig.skip (':') &&
- parse_minute (pig, minute))
- {
- if (pig.skip (':'))
- {
- int second {};
- if (parse_second (pig, second) &&
- ! unicodeLatinDigit (pig.peek ()) &&
- (! terminated || (pig.peek () != '-' && pig.peek () != '+')))
- {
- _seconds = (hour * 3600) + (minute * 60) + second;
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
- }
-
- auto following = pig.peek ();
- if (! unicodeLatinDigit (following) &&
- (! terminated || (following != '+' && following != '-')) &&
- following != 'A' &&
- following != 'a' &&
- following != 'P' &&
- following != 'p')
- {
- _seconds = (hour * 3600) + (minute * 60);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// time-ext 'Z'
-bool Datetime::parse_time_utc_ext (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (parse_time_ext (pig, false) &&
- pig.skip ('Z'))
- {
- if (! unicodeLatinDigit (pig.peek ()))
- {
- _utc = true;
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// time-ext off-ext
-bool Datetime::parse_time_off_ext (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (parse_time_ext (pig, false) &&
- parse_off_ext (pig))
- {
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// YYYYMMDDTHHMMSSZ
-// YYYYMMDDTHHMMSS
-bool Datetime::parse_date_time (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (parse_date (pig) &&
- pig.skip ('T') &&
- (parse_time_utc (pig) ||
- parse_time_off (pig) ||
- parse_time (pig)))
- {
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// YYYYWww
-// YYYYDDD
-// YYYYMMDD
-// YYYYMM
-bool Datetime::parse_date (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- int year {};
- int month {};
- int julian {};
- int week {};
- int weekday {};
- int day {};
- if (parse_year (pig, year))
- {
- auto checkpointYear = pig.cursor ();
-
- if (pig.skip ('W') &&
- parse_week (pig, week))
- {
- if (pig.getDigit (weekday))
- _weekday = weekday;
-
- if (! unicodeLatinDigit (pig.peek ()))
- {
- _year = year;
- _week = week;
- return true;
- }
- }
-
- pig.restoreTo (checkpointYear);
-
- if (parse_julian (pig, julian) &&
- ! unicodeLatinDigit (pig.peek ()))
- {
- _year = year;
- _julian = julian;
- return true;
- }
-
- pig.restoreTo (checkpointYear);
-
- if (parse_month (pig, month))
- {
- if (parse_day (pig, day))
- {
- if (! unicodeLatinDigit (pig.peek ()))
- {
- _year = year;
- _month = month;
- _day = day;
- return true;
- }
- }
- else
- {
- if (! unicodeLatinDigit (pig.peek ()))
- {
- _year = year;
- _month = month;
- _day = 1;
- return true;
- }
- }
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// <time> Z
-bool Datetime::parse_time_utc (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (parse_time (pig, false) &&
- pig.skip ('Z'))
- {
- _utc = true;
- if (! unicodeLatinDigit (pig.peek ()))
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// <time> <off>
-bool Datetime::parse_time_off (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (parse_time (pig, false) &&
- parse_off (pig))
- {
- auto terminator = pig.peek ();
- if (terminator != '-' && ! unicodeLatinDigit (terminator))
- {
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// hhmmss
-// hhmm
-bool Datetime::parse_time (Pig& pig, bool terminated)
-{
- auto checkpoint = pig.cursor ();
-
- int hour {};
- int minute {};
- if (parse_hour (pig, hour) &&
- parse_minute (pig, minute))
- {
- int second {};
- parse_second (pig, second);
-
- auto terminator = pig.peek ();
- if (! terminated ||
- (! unicodeLatinDigit (terminator) && terminator != '-' && terminator != '+'))
- {
- _seconds = (hour * 3600) + (minute * 60) + second;
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ±hhmm
-// ±hh
-bool Datetime::parse_off (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- int sign = pig.peek ();
- if (sign == '+' || sign == '-')
- {
- pig.skipN (1);
-
- int hour {};
- if (parse_off_hour (pig, hour))
- {
- int minute {};
- parse_off_minute (pig, minute);
-
- if (! unicodeLatinDigit (pig.peek ()))
- {
- _offset = (hour * 3600) + (minute * 60);
- if (sign == '-')
- _offset = - _offset;
-
- return true;
- }
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse_year (Pig& pig, int& value)
-{
- auto checkpoint = pig.cursor ();
-
- int year;
- if (pig.getDigit4 (year) &&
- year > 1969)
- {
- value = year;
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse_month (Pig& pig, int& value)
-{
- auto checkpoint = pig.cursor ();
-
- int month;
- if (pig.getDigit2 (month) &&
- month > 0 &&
- month <= 12)
- {
- value = month;
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse_week (Pig& pig, int& value)
-{
- auto checkpoint = pig.cursor ();
-
- int week;
- if (pig.getDigit2 (week) &&
- week > 0 &&
- week <= 53)
- {
- value = week;
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse_julian (Pig& pig, int& value)
-{
- auto checkpoint = pig.cursor ();
-
- int julian;
- if (pig.getDigit3 (julian) &&
- julian > 0 &&
- julian <= 366)
- {
- value = julian;
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse_day (Pig& pig, int& value)
-{
- auto checkpoint = pig.cursor ();
-
- int day;
- if (pig.getDigit2 (day) &&
- day > 0 &&
- day <= 31)
- {
- value = day;
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse_weekday (Pig& pig, int& value)
-{
- auto checkpoint = pig.cursor ();
-
- int weekday;
- if (pig.getDigit (weekday) &&
- weekday >= 1 &&
- weekday <= 7)
- {
- value = weekday;
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse_hour (Pig& pig, int& value)
-{
- auto checkpoint = pig.cursor ();
-
- int hour;
- if (pig.getDigit2 (hour) &&
- hour >= 0 &&
- hour < 24)
- {
- value = hour;
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse_minute (Pig& pig, int& value)
-{
- auto checkpoint = pig.cursor ();
-
- int minute;
- if (pig.getDigit2 (minute) &&
- minute >= 0 &&
- minute < 60)
- {
- value = minute;
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse_second (Pig& pig, int& value)
-{
- auto checkpoint = pig.cursor ();
-
- int second;
- if (pig.getDigit2 (second) &&
- second >= 0 &&
- second < 60)
- {
- value = second;
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse_off_hour (Pig& pig, int& value)
-{
- auto checkpoint = pig.cursor ();
-
- int hour;
- if (pig.getDigit2 (hour) &&
- hour >= 0 &&
- hour <= 12)
- {
- value = hour;
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::parse_off_minute (Pig& pig, int& value)
-{
- auto checkpoint = pig.cursor ();
-
- int minute;
- if (pig.getDigit2 (minute) &&
- minute >= 0 &&
- minute < 60)
- {
- value = minute;
- return true;
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// now [ !<alpha> && !<digit> ]
-bool Datetime::initializeNow (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("now"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- _date = time (nullptr);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// yesterday/abbrev [ !<alpha> && !<digit> ]
-bool Datetime::initializeYesterday (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- std::string token;
- if (pig.skipPartial ("yesterday", token) &&
- token.length () >= static_cast <std::string::size_type> (Datetime::minimumMatchLength))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- t->tm_mday -= 1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// today/abbrev [ !<alpha> && !<digit> ]
-bool Datetime::initializeToday (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- std::string token;
- if (pig.skipPartial ("today", token) &&
- token.length () >= static_cast <std::string::size_type> (Datetime::minimumMatchLength))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
-
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// tomcorrow/abbrev [ !<alpha> && !<digit> ]
-bool Datetime::initializeTomorrow (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- std::string token;
- if (pig.skipPartial ("tomorrow", token) &&
- token.length () >= static_cast <std::string::size_type> (Datetime::minimumMatchLength))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mday++;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// <digit>+ [ "st" | "nd" | "rd" | "th" ] [ !<alpha> && !<digit> ]
-bool Datetime::initializeOrdinal (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- int number = 0;
- if (pig.getDigits (number) &&
- number > 0 &&
- number <= 31)
- {
- int character1;
- int character2;
- if (pig.getCharacter (character1) &&
- pig.getCharacter (character2) &&
- ! unicodeLatinAlpha (pig.peek ()) &&
- ! unicodeLatinDigit (pig.peek ()))
- {
- int remainder1 = number % 10;
- int remainder2 = number % 100;
- if ((remainder2 != 11 && remainder1 == 1 && character1 == 's' && character2 == 't') ||
- (remainder2 != 12 && remainder1 == 2 && character1 == 'n' && character2 == 'd') ||
- (remainder2 != 13 && remainder1 == 3 && character1 == 'r' && character2 == 'd') ||
- ((remainder2 == 11 ||
- remainder2 == 12 ||
- remainder2 == 13 ||
- remainder1 == 0 ||
- remainder1 > 3) && character1 == 't' && character2 == 'h'))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- int y = t->tm_year + 1900;
- int m = t->tm_mon + 1;
- int d = t->tm_mday;
-
- // If it is this month.
- if (d < number &&
- number <= daysInMonth (y, m))
- {
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mon = m - 1;
- t->tm_mday = number;
- t->tm_year = y - 1900;
- t->tm_isdst = -1;
- _date = mktime (t);
- }
- else
- {
- if (++m > 12)
- {
- m = 1;
- y++;
- }
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mon = m - 1;
- t->tm_mday = number;
- t->tm_year = y - 1900;
- t->tm_isdst = -1;
- _date = mktime (t);
- }
-
- return true;
- }
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sunday/abbrev [ !<alpha> && !<digit> && !: && != ]
-bool Datetime::initializeDayName (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- std::string token;
- for (int day = 0; day <= 7; ++day) // Deliberate <= so that 'sunday' is either 0 or 7.
- {
- if (pig.skipPartial (dayNames[day % 7], token) &&
- token.length () >= static_cast <std::string::size_type> (Datetime::minimumMatchLength))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following) &&
- following != ':' &&
- following != '=')
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- if (t->tm_wday >= day)
- t->tm_mday += day - t->tm_wday + 7;
- else
- t->tm_mday += day - t->tm_wday;
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- }
-
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// january/abbrev [ !<alpha> && !<digit> && !: && != ]
-bool Datetime::initializeMonthName (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- std::string token;
- for (int month = 0; month < 12; ++month)
- {
- if (pig.skipPartial (monthNames[month], token) &&
- token.length () >= static_cast <std::string::size_type> (Datetime::minimumMatchLength))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following) &&
- following != ':' &&
- following != '=')
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- if (t->tm_mon >= month)
- t->tm_year++;
-
- t->tm_mon = month;
- t->tm_mday = 1;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- }
-
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// later/abbrev [ !<alpha> && !<digit> ]
-// someday/abbrev [ !<alpha> && !<digit> ]
-bool Datetime::initializeLater (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- std::string token;
- if ((pig.skipPartial ("later", token) &&
- token.length () >= static_cast <std::string::size_type> (Datetime::minimumMatchLength))
-
- ||
-
- (pig.skipPartial ("someday", token) &&
- token.length () >= static_cast <std::string::size_type> (std::max (Datetime::minimumMatchLength, 4))))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_year = 138;
- t->tm_mon = 0;
- t->tm_mday = 18;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sopd [ !<alpha> && !<digit> ]
-bool Datetime::initializeSopd (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sopd"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- t->tm_mday -= 1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sod [ !<alpha> && !<digit> ]
-bool Datetime::initializeSod (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sod"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sond [ !<alpha> && !<digit> ]
-bool Datetime::initializeSond (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sond"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mday++;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eopd [ !<alpha> && !<digit> ]
-bool Datetime::initializeEopd (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eopd"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eod [ !<alpha> && !<digit> ]
-bool Datetime::initializeEod (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eod"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mday++;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eond [ !<alpha> && !<digit> ]
-bool Datetime::initializeEond (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eond"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mday += 2;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sopw [ !<alpha> && !<digit> ]
-bool Datetime::initializeSopw (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sopw"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
- t->tm_hour = t->tm_min = t->tm_sec = 0;
-
- int extra = (t->tm_wday + 6) % 7;
- t->tm_mday -= extra;
- t->tm_mday -= 7;
-
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sow [ !<alpha> && !<digit> ]
-bool Datetime::initializeSow (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sow"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
- t->tm_hour = t->tm_min = t->tm_sec = 0;
-
- int extra = (t->tm_wday + 6) % 7;
- t->tm_mday -= extra;
-
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sonw [ !<alpha> && !<digit> ]
-bool Datetime::initializeSonw (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sonw"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
- t->tm_hour = t->tm_min = t->tm_sec = 0;
-
- int extra = (t->tm_wday + 6) % 7;
- t->tm_mday -= extra;
- t->tm_mday += 7;
-
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eopw [ !<alpha> && !<digit> ]
-bool Datetime::initializeEopw (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eopw"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
- t->tm_hour = t->tm_min = t->tm_sec = 0;
-
- int extra = (t->tm_wday + 6) % 7;
- t->tm_mday -= extra;
-
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eow [ !<alpha> && !<digit> ]
-bool Datetime::initializeEow (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eow"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
- t->tm_hour = t->tm_min = t->tm_sec = 0;
-
- int extra = (t->tm_wday + 6) % 7;
- t->tm_mday -= extra;
- t->tm_mday += 7;
-
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eonw [ !<alpha> && !<digit> ]
-bool Datetime::initializeEonw (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eonw"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mday += 15 - t->tm_wday;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sopww [ !<alpha> && !<digit> ]
-bool Datetime::initializeSopww (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sopww"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mday += -6 - t->tm_wday;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// soww [ !<alpha> && !<digit> ]
-bool Datetime::initializeSoww (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("soww"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mday += 8 - t->tm_wday;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sonww [ !<alpha> && !<digit> ]
-bool Datetime::initializeSonww (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sonww"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mday += 8 - t->tm_wday;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eopww [ !<alpha> && !<digit> ]
-bool Datetime::initializeEopww (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eopww"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mday -= (t->tm_wday + 1) % 7;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eoww [ !<alpha> && !<digit> ]
-bool Datetime::initializeEoww (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eoww"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mday += 6 - t->tm_wday;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eonww [ !<alpha> && !<digit> ]
-bool Datetime::initializeEonww (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eonww"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mday += 13 - t->tm_wday;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sopm [ !<alpha> && !<digit> ]
-bool Datetime::initializeSopm (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sopm"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
-
- if (t->tm_mon == 0)
- {
- t->tm_year--;
- t->tm_mon = 11;
- }
- else
- t->tm_mon--;
-
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// som [ !<alpha> && !<digit> ]
-bool Datetime::initializeSom (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("som"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sonm [ !<alpha> && !<digit> ]
-bool Datetime::initializeSonm (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sonm"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
-
- t->tm_mon++;
- if (t->tm_mon > 11)
- {
- t->tm_year++;
- t->tm_mon = 0;
- }
-
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eopm [ !<alpha> && !<digit> ]
-bool Datetime::initializeEopm (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eopm"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eom [ !<alpha> && !<digit> ]
-bool Datetime::initializeEom (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eom"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
-
- t->tm_mon++;
- if (t->tm_mon > 11)
- {
- t->tm_year++;
- t->tm_mon = 0;
- }
-
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eonm [ !<alpha> && !<digit> ]
-bool Datetime::initializeEonm (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eonm"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mday = 1;
- t->tm_mon += 2;
- if (t->tm_mon > 11)
- {
- t->tm_year++;
- t->tm_mon -= 12;
- }
-
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sopq [ !<alpha> && !<digit> ]
-bool Datetime::initializeSopq (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sopq"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mon -= t->tm_mon % 3;
- t->tm_mon -= 3;
- if (t->tm_mon < 0)
- {
- t->tm_mon += 12;
- t->tm_year--;
- }
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// soq [ !<alpha> && !<digit> ]
-bool Datetime::initializeSoq (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("soq"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mon -= t->tm_mon % 3;
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sonq [ !<alpha> && !<digit> ]
-bool Datetime::initializeSonq (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sonq"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mon += 3 - (t->tm_mon % 3);
- if (t->tm_mon > 11)
- {
- t->tm_mon -= 12;
- ++t->tm_year;
- }
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eopq [ !<alpha> && !<digit> ]
-bool Datetime::initializeEopq (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eopq"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mon -= t->tm_mon % 3;
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eoq [ !<alpha> && !<digit> ]
-bool Datetime::initializeEoq (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eoq"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_mon += 3 - (t->tm_mon % 3);
- if (t->tm_mon > 11)
- {
- t->tm_mon -= 12;
- ++t->tm_year;
- }
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eonq [ !<alpha> && !<digit> ]
-bool Datetime::initializeEonq (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eonq"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mon += 6 - (t->tm_mon % 3);
- if (t->tm_mon > 11)
- {
- t->tm_mon -= 12;
- ++t->tm_year;
- }
-
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sopy [ !<alpha> && !<digit> ]
-bool Datetime::initializeSopy (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sopy"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mon = 0;
- t->tm_mday = 1;
- t->tm_year--;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// soy [ !<alpha> && !<digit> ]
-bool Datetime::initializeSoy (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("soy"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mon = 0;
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// sony [ !<alpha> && !<digit> ]
-bool Datetime::initializeSony (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("sony"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mon = 0;
- t->tm_mday = 1;
- t->tm_year++;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eopy [ !<alpha> && !<digit> ]
-bool Datetime::initializeEopy (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eopy"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mon = 0;
- t->tm_mday = 1;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eoy [ !<alpha> && !<digit> ]
-bool Datetime::initializeEoy (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eoy"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mon = 0;
- t->tm_mday = 1;
- t->tm_year++;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// eony [ !<alpha> && !<digit> ]
-bool Datetime::initializeEony (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("eony"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- t->tm_hour = t->tm_min = t->tm_sec = 0;
- t->tm_mon = 0;
- t->tm_mday = 1;
- t->tm_year += 2;
- t->tm_isdst = -1;
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// easter [ !<alpha> && !<digit> ]
-// eastermonday [ !<alpha> && !<digit> ]
-// ascension [ !<alpha> && !<digit> ]
-// pentecost [ !<alpha> && !<digit> ]
-// goodfriday [ !<alpha> && !<digit> ]
-bool Datetime::initializeEaster (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- std::vector <std::string> holidays = {"eastermonday", "easter", "ascension", "pentecost", "goodfriday"};
- std::vector <int> offsets = { 1, 0, 39, 49, -2};
-
- std::string token;
- for (int holiday = 0; holiday < 5; ++holiday)
- {
- if (pig.skipLiteral (holidays[holiday]) &&
- ! unicodeLatinAlpha (pig.peek ()) &&
- ! unicodeLatinDigit (pig.peek ()))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- easter (t);
- _date = mktime (t);
-
- // If the result is earlier this year, then recalc for next year.
- if (_date < now)
- {
- t = localtime (&now);
- t->tm_year++;
- easter (t);
- }
-
- // Adjust according to holiday-specific offsets.
- t->tm_mday += offsets[holiday];
-
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// midsommar [ !<alpha> && !<digit> ]
-bool Datetime::initializeMidsommar (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("midsommar"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
- midsommar (t);
- _date = mktime (t);
-
- // If the result is earlier this year, then recalc for next year.
- if (_date < now)
- {
- t = localtime (&now);
- t->tm_year++;
- midsommar (t);
- }
-
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// midsommarafton [ !<alpha> && !<digit> ]
-// juhannus [ !<alpha> && !<digit> ]
-bool Datetime::initializeMidsommarafton (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- if (pig.skipLiteral ("midsommarafton") ||
- pig.skipLiteral ("juhannus"))
- {
- auto following = pig.peek ();
- if (! unicodeLatinAlpha (following) &&
- ! unicodeLatinDigit (following))
- {
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
- midsommarafton (t);
- _date = mktime (t);
-
- // If the result is earlier this year, then recalc for next year.
- if (_date < now)
- {
- t = localtime (&now);
- t->tm_year++;
- midsommarafton (t);
- }
-
- _date = mktime (t);
- return true;
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// 8am
-// 8a
-// 8:30am
-// 8:30a
-// 8:30
-//
-// \d+ [ : \d{2} ] [ am | a | pm | p ] [ !<alpha> && !<digit> && !: && !+ && !- ]
-//
-bool Datetime::initializeInformalTime (Pig& pig)
-{
- auto checkpoint = pig.cursor ();
-
- int digit = 0;
- bool needDesignator = true; // Require am/pm.
- bool haveDesignator = false; // Provided am/pm.
- if (pig.getDigit (digit))
- {
- int hours = digit;
- if (pig.getDigit (digit))
- hours = 10 * hours + digit;
-
- int minutes = 0;
- int seconds = 0;
- if (pig.skip (':'))
- {
- if (! pig.getDigit2 (minutes))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
-
- if (pig.skip (':'))
- {
- if (! pig.getDigits (seconds))
- {
- pig.restoreTo (checkpoint);
- return false;
- }
- }
-
- needDesignator = false;
- }
-
- if (pig.skipLiteral ("am") ||
- pig.skipLiteral ("a"))
- {
- haveDesignator = true;
- if (hours == 12)
- hours = 0;
- }
-
- else if (pig.skipLiteral ("pm") ||
- pig.skipLiteral ("p"))
- {
- // Note: '12pm is an exception:
- // 12am = 0h
- // 11am = 11h + 12h
- // 12pm = 12h
- // 1pm = 1h + 12h
- if (hours != 12)
- hours += 12;
-
- haveDesignator = true;
- }
-
- // Informal time needs to be terminated.
- auto following = pig.peek ();
- if (unicodeLatinAlpha (following) ||
- unicodeLatinDigit (following) ||
- following == ':' ||
- following == '-' ||
- following == '+')
- {
- pig.restoreTo (checkpoint);
- return false;
- }
-
- if (haveDesignator || ! needDesignator)
- {
- // Midnight today + hours:minutes:seconds.
- time_t now = time (nullptr);
- struct tm* t = localtime (&now);
-
- int now_seconds = (t->tm_hour * 3600) + (t->tm_min * 60) + t->tm_sec;
- int calc_seconds = (hours * 3600) + (minutes * 60) + seconds;
-
- if (calc_seconds < now_seconds)
- ++t->tm_mday;
-
- // Basic validation.
- if (hours >= 0 && hours < 24 &&
- minutes >= 0 && minutes < 60 &&
- seconds >= 0 && seconds < 60)
- {
- t->tm_hour = hours;
- t->tm_min = minutes;
- t->tm_sec = seconds;
- t->tm_isdst = -1;
- _date = mktime (t);
-
- return true;
- }
- }
- }
-
- pig.restoreTo (checkpoint);
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-void Datetime::easter (struct tm* t) const
-{
- int Y = t->tm_year + 1900;
- int a = Y % 19;
- int b = Y / 100;
- int c = Y % 100;
- int d = b / 4;
- int e = b % 4;
- int f = (b + 8) / 25;
- int g = (b - f + 1) / 3;
- int h = (19 * a + b - d - g + 15) % 30;
- int i = c / 4;
- int k = c % 4;
- int L = (32 + 2 * e + 2 * i - h - k) % 7;
- int m = (a + 11 * h + 22 * L) / 451;
- int month = (h + L - 7 * m + 114) / 31;
- int day = ((h + L - 7 * m + 114) % 31) + 1;
-
- t->tm_isdst = -1; // Requests that mktime determine summer time effect.
- t->tm_mday = day;
- t->tm_mon = month - 1;
- t->tm_year = Y - 1900;
- t->tm_isdst = -1;
- t->tm_hour = t->tm_min = t->tm_sec = 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-void Datetime::midsommar (struct tm* t) const
-{
- t->tm_mon = 5; // June.
- t->tm_mday = 20; // Saturday after 20th.
- t->tm_hour = t->tm_min = t->tm_sec = 0; // Midnight.
- t->tm_isdst = -1; // Probably DST, but check.
-
- time_t then = mktime (t); // Obtain the weekday of June 20th.
- struct tm* mid = localtime (&then);
- t->tm_mday += 6 - mid->tm_wday; // How many days after 20th.
-}
-
-////////////////////////////////////////////////////////////////////////////////
-void Datetime::midsommarafton (struct tm* t) const
-{
- t->tm_mon = 5; // June.
- t->tm_mday = 19; // Saturday after 20th.
- t->tm_hour = t->tm_min = t->tm_sec = 0; // Midnight.
- t->tm_isdst = -1; // Probably DST, but check.
-
- time_t then = mktime (t); // Obtain the weekday of June 19th.
- struct tm* mid = localtime (&then);
- t->tm_mday += 5 - mid->tm_wday; // How many days after 19th.
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Suggested date expressions:
-// {ordinal} {day} in|of {month}
-// last|past|next|this {day}
-// last|past|next|this {month}
-// last|past|next|this week
-// last|past|next|this month
-// last|past|next|this weekend
-// last|past|next|this year
-// {day} last|past|next|this week
-// {day} [at] {time}
-// {time} {day}
-//
-// Candidates:
-// <dayname> <time>
-// <time>
-// tue 9am
-// Friday before easter
-// 3 days before eom
-// in the morning
-// am|pm
-// 4pm
-// noon
-// midnight
-// tomorrow in one year
-// in two weeks
-// 2 weeks from now
-// 2 weeks ago tuesday
-// thursday in 2 weeks
-// last day next month
-// 10 days from today
-// thursday before last weekend in may
-// friday last full week in may
-// 3rd wednesday this month
-// 3 weeks after 2nd tuesday next month
-// 100 days from the beginning of the month
-// 10 days after last monday
-// sunday in the evening
-// in 6 hours
-// 6 in the morning
-// kl 18
-// feb 11
-// 11 feb
-// 2011-02-08
-// 11/19/2011
-// next business day
-// new moon
-// full moon
-// in 28 days
-// 3rd quarter
-// week 23
-// {number} {unit}
-// - {number} {unit}
-// {ordinal} {unit} in {larger-unit}
-// end of day tomorrow
-// end of {day}
-// by {day}
-// first thing {day}
-//
-
-////////////////////////////////////////////////////////////////////////////////
-// <ordinal> <weekday> in|of <month>
-bool Datetime::initializeNthDayInMonth (const std::vector <std::string>& tokens)
-{
- if (tokens.size () == 4)
- {
- int ordinal {0};
- if (isOrdinal (tokens[0], ordinal))
- {
- auto day = Datetime::dayOfWeek (tokens[1]);
- if (day != -1)
- {
- if (tokens[2] == "in" ||
- tokens[2] == "of")
- {
- auto month = Datetime::monthOfYear (tokens[3]);
- if (month != -1)
- {
- std::cout << "# ordinal=" << ordinal << " day=" << day << " in month=" << month << '\n';
-
- // TODO Assume 1st of the month
- // TODO Assume current year
- // TODO Determine the day
- // TODO Project forwards/backwards, to the desired day
- // TODO Add ((ordinal - 1) * 7) days
-
- return true;
- }
- }
- }
- }
- }
-
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::isOrdinal (const std::string& token, int& ordinal)
-{
- Pig p (token);
- int number;
- std::string suffix;
- if (p.getDigits (number) &&
- p.getRemainder (suffix))
- {
- if (((number >= 11 || number <= 13) && suffix == "th") ||
- (number % 10 == 1 && suffix == "st") ||
- (number % 10 == 2 && suffix == "nd") ||
- (number % 10 == 3 && suffix == "rd") ||
- ( suffix == "th"))
- {
- ordinal = number;
- return true;
- }
- }
-
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Validation via simple range checking.
-bool Datetime::validate ()
-{
- // _year;
- if ((_year && (_year < 1900 || _year > 2200)) ||
- (_month && (_month < 1 || _month > 12)) ||
- (_week && (_week < 1 || _week > 53)) ||
- (_weekday && (_weekday < 0 || _weekday > 6)) ||
- (_julian && (_julian < 1 || _julian > Datetime::daysInYear (_year))) ||
- (_day && (_day < 1 || _day > Datetime::daysInMonth (_year, _month))) ||
- (_seconds && (_seconds < 1 || _seconds > 86400)) ||
- (_offset && (_offset < -86400 || _offset > 86400)))
- return false;
-
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// int tm_sec; seconds (0 - 60)
-// int tm_min; minutes (0 - 59)
-// int tm_hour; hours (0 - 23)
-// int tm_mday; day of month (1 - 31)
-// int tm_mon; month of year (0 - 11)
-// int tm_year; year - 1900
-// int tm_wday; day of week (Sunday = 0)
-// int tm_yday; day of year (0 - 365)
-// int tm_isdst; is summer time in effect?
-// char *tm_zone; abbreviation of timezone name
-// long tm_gmtoff; offset from UTC in seconds
-void Datetime::resolve ()
-{
- // Don't touch the original values.
- int year = _year;
- int month = _month;
- int week = _week;
- int weekday = _weekday;
- int julian = _julian;
- int day = _day;
- int seconds = _seconds;
- int offset = _offset;
- bool utc = _utc;
-
- // Get current time.
- time_t now = time (nullptr);
-
- // A UTC offset needs to be accommodated. Once the offset is subtracted,
- // only local and UTC times remain.
- if (offset)
- {
- seconds -= offset;
- now -= offset;
- utc = true;
- }
-
- // Get 'now' in the relevant location.
- struct tm* t_now = utc ? gmtime (&now) : localtime (&now);
-
- int seconds_now = (t_now->tm_hour * 3600) +
- (t_now->tm_min * 60) +
- t_now->tm_sec;
-
- // Project forward one day if the specified seconds are earlier in the day
- // than the current seconds.
- // TODO This does not cover the inverse case of subtracting 86400.
- if (year == 0 &&
- month == 0 &&
- day == 0 &&
- week == 0 &&
- weekday == 0 &&
- seconds < seconds_now)
- {
- seconds += 86400;
- }
-
- // Convert week + weekday --> julian.
- if (week)
- {
- julian = (week * 7) + weekday - dayOfWeek (year, 1, 4) - 3;
- }
-
- // Provide default values for year, month, day.
- else
- {
- // Default values for year, month, day:
- //
- // y m d --> y m d
- // y m - --> y m 1
- // y - - --> y 1 1
- // - - - --> now now now
- //
- if (year == 0)
- {
- year = t_now->tm_year + 1900;
- month = t_now->tm_mon + 1;
- day = t_now->tm_mday;
- }
- else
- {
- if (month == 0)
- {
- month = 1;
- day = 1;
- }
- else if (day == 0)
- day = 1;
- }
- }
-
- if (julian)
- {
- month = 1;
- day = julian;
- }
-
- struct tm t {};
- t.tm_isdst = -1; // Requests that mktime/gmtime determine summer time effect.
- t.tm_year = year - 1900;
- t.tm_mon = month - 1;
- t.tm_mday = day;
-
- if (seconds > 86400)
- {
- int days = seconds / 86400;
- t.tm_mday += days;
- seconds %= 86400;
- }
-
- t.tm_hour = seconds / 3600;
- t.tm_min = (seconds % 3600) / 60;
- t.tm_sec = seconds % 60;
-
- _date = utc ? timegm (&t) : mktime (&t);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-time_t Datetime::toEpoch () const
-{
- return _date;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-std::string Datetime::toEpochString () const
-{
- return format ("{1}", _date);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// 19980119T070000Z = YYYYMMDDThhmmssZ
-std::string Datetime::toISO () const
-{
- struct tm* t = gmtime (&_date);
-
- std::stringstream iso;
- iso << std::setw (4) << std::setfill ('0') << t->tm_year + 1900
- << std::setw (2) << std::setfill ('0') << t->tm_mon + 1
- << std::setw (2) << std::setfill ('0') << t->tm_mday
- << 'T'
- << std::setw (2) << std::setfill ('0') << t->tm_hour
- << std::setw (2) << std::setfill ('0') << t->tm_min
- << std::setw (2) << std::setfill ('0') << t->tm_sec
- << 'Z';
-
- return iso.str ();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// 1998-01-19T07:00:00 = YYYY-MM-DDThh:mm:ss
-std::string Datetime::toISOLocalExtended () const
-{
- struct tm* t = localtime (&_date);
-
- std::stringstream iso;
- iso << std::setw (4) << std::setfill ('0') << t->tm_year + 1900
- << '-'
- << std::setw (2) << std::setfill ('0') << t->tm_mon + 1
- << '-'
- << std::setw (2) << std::setfill ('0') << t->tm_mday
- << 'T'
- << std::setw (2) << std::setfill ('0') << t->tm_hour
- << ':'
- << std::setw (2) << std::setfill ('0') << t->tm_min
- << ':'
- << std::setw (2) << std::setfill ('0') << t->tm_sec;
-
- return iso.str ();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-double Datetime::toJulian () const
-{
- return (_date / 86400.0) + 2440587.5;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-void Datetime::toYMD (int& y, int& m, int& d) const
-{
- struct tm* t = localtime (&_date);
-
- m = t->tm_mon + 1;
- d = t->tm_mday;
- y = t->tm_year + 1900;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-const std::string Datetime::toString (const std::string& format) const
-{
- std::stringstream formatted;
- for (unsigned int i = 0; i < format.length (); ++i)
- {
- int c = format[i];
- switch (c)
- {
- case 'm': formatted << month (); break;
- case 'M': formatted << std::setw (2) << std::setfill ('0') << month (); break;
- case 'd': formatted << day (); break;
- case 'D': formatted << std::setw (2) << std::setfill ('0') << day (); break;
- case 'y': formatted << std::setw (2) << std::setfill ('0') << (year () % 100); break;
- case 'Y': formatted << year (); break;
- case 'a': formatted << Datetime::dayNameShort (dayOfWeek ()); break;
- case 'A': formatted << Datetime::dayName (dayOfWeek ()); break;
- case 'b': formatted << Datetime::monthNameShort (month ()); break;
- case 'B': formatted << Datetime::monthName (month ()); break;
- case 'v': formatted << week (); break;
- case 'V': formatted << std::setw (2) << std::setfill ('0') << week (); break;
- case 'h': formatted << hour (); break;
- case 'H': formatted << std::setw (2) << std::setfill ('0') << hour (); break;
- case 'n': formatted << minute (); break;
- case 'N': formatted << std::setw (2) << std::setfill ('0') << minute (); break;
- case 's': formatted << second (); break;
- case 'S': formatted << std::setw (2) << std::setfill ('0') << second (); break;
- case 'j': formatted << dayOfYear (); break;
- case 'J': formatted << std::setw (3) << std::setfill ('0') << dayOfYear (); break;
- case 'w': formatted << dayOfWeek (); break;
- default: formatted << static_cast <char> (c); break;
- }
- }
-
- return formatted.str ();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime Datetime::startOfDay () const
-{
- return Datetime (year (), month (), day ());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime Datetime::startOfWeek () const
-{
- Datetime sow (_date);
- sow -= (dayOfWeek () * 86400);
- return Datetime (sow.year (), sow.month (), sow.day ());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime Datetime::startOfMonth () const
-{
- return Datetime (year (), month (), 1);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime Datetime::startOfYear () const
-{
- return Datetime (year (), 1, 1);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::valid (const std::string& input, const std::string& format)
-{
- try
- {
- Datetime test (input, format);
- }
-
- catch (...)
- {
- return false;
- }
-
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::valid (
- const int y, const int m, const int d,
- const int hr, const int mi, const int se)
-{
- if (hr < 0 || hr > 24)
- return false;
-
- if (mi < 0 || mi > 59)
- return false;
-
- if (se < 0 || se > 59)
- return false;
-
- if (hr == 24 &&
- (mi != 0 ||
- se != 0))
- return false;
-
- return Datetime::valid (y, m, d);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::valid (const int y, const int m, const int d)
-{
- // Check that the year is valid.
- if (y < 0)
- return false;
-
- // Check that the month is valid.
- if (m < 1 || m > 12)
- return false;
-
- // Finally check that the days fall within the acceptable range for this
- // month, and whether or not this is a leap year.
- if (d < 1 || d > Datetime::daysInMonth (y, m))
- return false;
-
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Julian
-bool Datetime::valid (const int y, const int d)
-{
- // Check that the year is valid.
- if (y < 0)
- return false;
-
- if (d < 1 || d > Datetime::daysInYear (y))
- return false;
-
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Static
-bool Datetime::leapYear (int year)
-{
- return ((! (year % 4)) && (year % 100)) ||
- ! (year % 400);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Static
-int Datetime::daysInMonth (int year, int month)
-{
- // Protect against arguments being passed in the wrong order.
- assert (year >= 1969 && year < 2100);
- assert (month >= 1 && month <= 31);
-
- static int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
-
- if (month == 2 && Datetime::leapYear (year))
- return 29;
-
- return days[month - 1];
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Static
-int Datetime::daysInYear (int year)
-{
- return Datetime::leapYear (year) ? 366 : 365;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Static
-std::string Datetime::monthName (int month)
-{
- assert (month > 0);
- assert (month <= 12);
- return upperCaseFirst (monthNames[month - 1]);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Static
-std::string Datetime::monthNameShort (int month)
-{
- assert (month > 0);
- assert (month <= 12);
- return upperCaseFirst (monthNames[month - 1]).substr (0, 3);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Static
-std::string Datetime::dayName (int dow)
-{
- assert (dow >= 0);
- assert (dow <= 6);
- return upperCaseFirst (dayNames[dow]);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Static
-std::string Datetime::dayNameShort (int dow)
-{
- assert (dow >= 0);
- assert (dow <= 6);
- return upperCaseFirst (dayNames[dow]).substr (0, 3);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Static
-int Datetime::dayOfWeek (const std::string& input)
-{
- if (Datetime::minimumMatchLength== 0)
- Datetime::minimumMatchLength = 3;
-
- for (unsigned int i = 0; i < dayNames.size (); ++i)
- if (closeEnough (dayNames[i], input, Datetime::minimumMatchLength))
- return i;
-
- return -1;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Using Zeller's Congruence.
-// Static
-int Datetime::dayOfWeek (int year, int month, int day)
-{
- int adj = (14 - month) / 12;
- int m = month + 12 * adj - 2;
- int y = year - adj;
- return (day + (13 * m - 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Static
-int Datetime::monthOfYear (const std::string& input)
-{
- if (Datetime::minimumMatchLength== 0)
- Datetime::minimumMatchLength = 3;
-
- for (unsigned int i = 0; i < monthNames.size (); ++i)
- if (closeEnough (monthNames[i], input, Datetime::minimumMatchLength))
- return i + 1;
-
- return -1;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Static
-int Datetime::length (const std::string& format)
-{
- int len = 0;
- for (auto& i : format)
- {
- switch (i)
- {
- case 'm':
- case 'M':
- case 'd':
- case 'D':
- case 'y':
- case 'v':
- case 'V':
- case 'h':
- case 'H':
- case 'n':
- case 'N':
- case 's':
- case 'S': len += 2; break;
- case 'b':
- case 'j':
- case 'J':
- case 'a': len += 3; break;
- case 'Y': len += 4; break;
- case 'A':
- case 'B': len += 10; break;
-
- // Calculate the width, don't assume a single character width.
- default: len += mk_wcwidth (i); break;
- }
- }
-
- return len;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-int Datetime::month () const
-{
- struct tm* t = localtime (&_date);
- return t->tm_mon + 1;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-int Datetime::week () const
-{
- struct tm* t = localtime (&_date);
-
- char weekStr[3];
- if (Datetime::weekstart == 0)
- strftime (weekStr, sizeof (weekStr), "%U", t);
- else if (Datetime::weekstart == 1)
- strftime (weekStr, sizeof (weekStr), "%V", t);
- else
- throw std::string ("The week may only start on a Sunday or Monday.");
-
- int weekNumber = strtol (weekStr, nullptr, 10);
- if (weekstart == 0)
- weekNumber += 1;
-
- return weekNumber;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-int Datetime::day () const
-{
- struct tm* t = localtime (&_date);
- return t->tm_mday;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-int Datetime::year () const
-{
- struct tm* t = localtime (&_date);
- return t->tm_year + 1900;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-int Datetime::dayOfWeek () const
-{
- struct tm* t = localtime (&_date);
- return t->tm_wday;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-int Datetime::dayOfYear () const
-{
- struct tm* t = localtime (&_date);
- return t->tm_yday + 1;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-int Datetime::hour () const
-{
- struct tm* t = localtime (&_date);
- return t->tm_hour;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-int Datetime::minute () const
-{
- struct tm* t = localtime (&_date);
- return t->tm_min;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-int Datetime::second () const
-{
- struct tm* t = localtime (&_date);
- return t->tm_sec;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::operator== (const Datetime& rhs) const
-{
- return rhs._date == _date;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::operator!= (const Datetime& rhs) const
-{
- return rhs._date != _date;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::operator< (const Datetime& rhs) const
-{
- return _date < rhs._date;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::operator> (const Datetime& rhs) const
-{
- return _date > rhs._date;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::operator<= (const Datetime& rhs) const
-{
- return _date <= rhs._date;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::operator>= (const Datetime& rhs) const
-{
- return _date >= rhs._date;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::sameHour (const Datetime& rhs) const
-{
- return year () == rhs.year () &&
- month () == rhs.month () &&
- day () == rhs.day () &&
- hour () == rhs.hour ();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::sameDay (const Datetime& rhs) const
-{
- return year () == rhs.year () &&
- month () == rhs.month () &&
- day () == rhs.day ();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::sameWeek (const Datetime& rhs) const
-{
- return year () == rhs.year () &&
- week () == rhs.week ();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::sameMonth (const Datetime& rhs) const
-{
- return year () == rhs.year () &&
- month () == rhs.month ();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::sameQuarter (const Datetime& rhs) const
-{
- return year () == rhs.year () &&
- ((month () - 1) / 3) == ((rhs.month () - 1) / 3);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool Datetime::sameYear (const Datetime& rhs) const
-{
- return year () == rhs.year ();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime Datetime::operator+ (const int delta)
-{
- return Datetime (_date + delta);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime Datetime::operator- (const int delta)
-{
- return Datetime (_date - delta);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime& Datetime::operator+= (const int delta)
-{
- _date += (time_t) delta;
- return *this;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-Datetime& Datetime::operator-= (const int delta)
-{
- _date -= (time_t) delta;
- return *this;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-time_t Datetime::operator- (const Datetime& rhs)
-{
- return _date - rhs._date;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Prefix decrement by one day.
-void Datetime::operator-- ()
-{
- Datetime yesterday = startOfDay () - 1;
- yesterday = Datetime (yesterday.year (),
- yesterday.month (),
- yesterday.day (),
- hour (),
- minute (),
- second ());
- _date = yesterday._date;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Postfix decrement by one day.
-void Datetime::operator-- (int)
-{
- Datetime yesterday = startOfDay () - 1;
- yesterday = Datetime (yesterday.year (),
- yesterday.month (),
- yesterday.day (),
- hour (),
- minute (),
- second ());
- _date = yesterday._date;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Prefix increment by one day.
-void Datetime::operator++ ()
-{
- Datetime tomorrow = (startOfDay () + 90001).startOfDay ();
- tomorrow = Datetime (tomorrow.year (),
- tomorrow.month (),
- tomorrow.day (),
- hour (),
- minute (),
- second ());
- _date = tomorrow._date;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Postfix increment by one day.
-void Datetime::operator++ (int)
-{
- Datetime tomorrow = (startOfDay () + 90001).startOfDay ();
- tomorrow = Datetime (tomorrow.year (),
- tomorrow.month (),
- tomorrow.day (),
- hour (),
- minute (),
- second ());
- _date = tomorrow._date;
-}
-
-////////////////////////////////////////////////////////////////////////////////