]> git.armaanb.net Git - gen-shell.git/blob - src/libshared/src/Datetime.cpp
added install instructions
[gen-shell.git] / src / libshared / src / Datetime.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2006 - 2017, Paul Beckingham, Federico Hernandez.
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included
13 // in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 //
23 // http://www.opensource.org/licenses/mit-license.php
24 //
25 ////////////////////////////////////////////////////////////////////////////////
26
27 #include <cmake.h>
28 #include <Datetime.h>
29 #include <algorithm>
30 #include <iostream>
31 #include <sstream>
32 #include <iomanip>
33 #include <cassert>
34 #include <stdlib.h>
35 #include <shared.h>
36 #include <format.h>
37 #include <unicode.h>
38 #include <utf8.h>
39
40 static std::vector <std::string> dayNames {
41   "sunday",
42   "monday",
43   "tuesday",
44   "wednesday",
45   "thursday",
46   "friday",
47   "saturday"};
48
49 static std::vector <std::string> monthNames {
50   "january",
51   "february",
52   "march",
53   "april",
54   "may",
55   "june",
56   "july",
57   "august",
58   "september",
59   "october",
60   "november",
61   "december"};
62
63 int Datetime::weekstart = 1; // Monday, per ISO-8601.
64 int Datetime::minimumMatchLength = 3;
65 bool Datetime::isoEnabled            = true;
66 bool Datetime::standaloneDateEnabled = true;
67 bool Datetime::standaloneTimeEnabled = true;
68
69 ////////////////////////////////////////////////////////////////////////////////
70 Datetime::Datetime ()
71 {
72   clear ();
73   _date = time (nullptr);
74 }
75
76 ////////////////////////////////////////////////////////////////////////////////
77 Datetime::Datetime (const std::string& input, const std::string& format)
78 {
79   clear ();
80   std::string::size_type start = 0;
81   if (! parse (input, start, format))
82     throw ::format ("'{1}' is not a valid date in the '{2}' format.", input, format);
83 }
84
85 ////////////////////////////////////////////////////////////////////////////////
86 Datetime::Datetime (const time_t t)
87 {
88   clear ();
89   _date = t;
90 }
91
92 ////////////////////////////////////////////////////////////////////////////////
93 Datetime::Datetime (const int y, const int m, const int d)
94 {
95   // Protect against arguments being passed in the wrong order.
96   assert (y >= 1969 && y < 2100);
97   assert (m >= 1 && m <= 12);
98   assert (d >= 1 && d <= 31);
99
100   clear ();
101
102   // Error if not valid.
103   struct tm t {};
104   t.tm_isdst = -1;   // Requests that mktime determine summer time effect.
105   t.tm_mday  = d;
106   t.tm_mon   = m - 1;
107   t.tm_year  = y - 1900;
108
109   _date = mktime (&t);
110 }
111
112 ////////////////////////////////////////////////////////////////////////////////
113 Datetime::Datetime (const int y,  const int m,  const int d,
114                     const int hr, const int mi, const int se)
115 {
116   // Protect against arguments being passed in the wrong order.
117   assert (y >= 1969 && y < 2100);
118   assert (m >= 1 && m <= 12);
119   assert (d >= 1 && d <= 31);
120   assert (hr >= 0 && hr <= 24);
121   assert (mi >= 0 && mi < 60);
122   assert (se >= 0 && se < 60);
123
124   clear ();
125
126   // Error if not valid.
127   struct tm t {};
128   t.tm_isdst = -1;   // Requests that mktime determine summer time effect.
129   t.tm_mday  = d;
130   t.tm_mon   = m - 1;
131   t.tm_year  = y - 1900;
132   t.tm_hour  = hr;
133   t.tm_min   = mi;
134   t.tm_sec   = se;
135
136   _date = mktime (&t);
137 }
138
139 ////////////////////////////////////////////////////////////////////////////////
140 bool Datetime::parse (
141   const std::string& input,
142   std::string::size_type& start,
143   const std::string& format)
144 {
145   auto i = start;
146   Pig pig (input);
147   if (i)
148     pig.skipN (static_cast <int> (i));
149
150   auto checkpoint = pig.cursor ();
151
152   // Parse epoch first, as it's the most common scenario.
153   if (parse_epoch (pig))
154   {
155     // ::validate and ::resolve are not needed in this case.
156     start = pig.cursor ();
157     return true;
158   }
159
160   if (parse_formatted (pig, format))
161   {
162     // Check the values and determine time_t.
163     if (validate ())
164     {
165       start = pig.cursor ();
166       resolve ();
167       return true;
168     }
169   }
170
171   // Allow parse_date_time and parse_date_time_ext regardless of
172   // Datetime::isoEnabled setting, because these formats are relied upon by
173   // the 'import' command, JSON parser and hook system.
174   if (parse_date_time_ext   (pig) || // Strictest first.
175       parse_date_time       (pig) ||
176       (Datetime::isoEnabled &&
177        (                                    parse_date_ext      (pig)  ||
178         (Datetime::standaloneDateEnabled && parse_date          (pig)) ||
179                                             parse_time_utc_ext  (pig)  ||
180                                             parse_time_utc      (pig)  ||
181                                             parse_time_off_ext  (pig)  ||
182                                             parse_time_off      (pig)  ||
183                                             parse_time_ext      (pig)  ||
184         (Datetime::standaloneTimeEnabled && parse_time          (pig)) // Time last, as it is the most permissive.
185        )
186       )
187      )
188   {
189     // Check the values and determine time_t.
190     if (validate ())
191     {
192       start = pig.cursor ();
193       resolve ();
194       return true;
195     }
196   }
197
198   pig.restoreTo (checkpoint);
199
200   if (parse_named (pig))
201   {
202     // ::validate and ::resolve are not needed in this case.
203     start = pig.cursor ();
204     return true;
205   }
206
207   return false;
208 }
209
210 ////////////////////////////////////////////////////////////////////////////////
211 void Datetime::clear ()
212 {
213   _year    = 0;
214   _month   = 0;
215   _week    = 0;
216   _weekday = 0;
217   _julian  = 0;
218   _day     = 0;
219   _seconds = 0;
220   _offset  = 0;
221   _utc     = false;
222   _date    = 0;
223 }
224
225 ////////////////////////////////////////////////////////////////////////////////
226 bool Datetime::parse_formatted (Pig& pig, const std::string& format)
227 {
228   // Short-circuit on missing format.
229   if (format == "")
230     return false;
231
232   auto checkpoint = pig.cursor ();
233
234   int month  {-1};   // So we can check later.
235   int day    {-1};
236   int year   {-1};
237   int hour   {-1};
238   int minute {-1};
239   int second {-1};
240
241   // For parsing, unused.
242   int wday   {-1};
243   int week   {-1};
244
245   for (unsigned int f = 0; f < format.length (); ++f)
246   {
247     switch (format[f])
248     {
249     case 'm':
250       if (pig.getDigit (month))
251       {
252         if (month == 0)
253           pig.getDigit (month);
254
255         if (month == 1)
256           if (pig.getDigit (month))
257             month += 10;
258       }
259       else
260       {
261         pig.restoreTo (checkpoint);
262         return false;
263       }
264       break;
265
266     case 'M':
267       if (! pig.getDigit2 (month))
268       {
269         pig.restoreTo (checkpoint);
270         return false;
271       }
272       break;
273
274     case 'd':
275       if (pig.getDigit (day))
276       {
277         if (day == 0)
278           pig.getDigit (day);
279
280         if (day == 1 || day == 2 || day == 3)
281         {
282           int tens = day;
283           if (pig.getDigit (day))
284             day += 10 * tens;
285         }
286       }
287       else
288       {
289         pig.restoreTo (checkpoint);
290         return false;
291       }
292       break;
293
294     case 'D':
295       if (! pig.getDigit2 (day))
296       {
297         pig.restoreTo (checkpoint);
298         return false;
299       }
300       break;
301
302     case 'y':
303       if (! pig.getDigit2 (year))
304       {
305         pig.restoreTo (checkpoint);
306         return false;
307       }
308       year += 2000;
309       break;
310
311     case 'Y':
312       if (! pig.getDigit4 (year))
313       {
314         pig.restoreTo (checkpoint);
315         return false;
316       }
317       break;
318
319     case 'h':
320       if (pig.getDigit (hour))
321       {
322         if (hour == 0)
323           pig.getDigit (hour);
324
325         if (hour == 1 || hour == 2)
326         {
327           int tens = hour;
328           if (pig.getDigit (hour))
329             hour += 10 * tens;
330         }
331       }
332       else
333       {
334         pig.restoreTo (checkpoint);
335         return false;
336       }
337       break;
338
339     case 'H':
340       if (! pig.getDigit2 (hour))
341       {
342         pig.restoreTo (checkpoint);
343         return false;
344       }
345       break;
346
347     case 'n':
348       if (pig.getDigit (minute))
349       {
350         if (minute == 0)
351           pig.getDigit (minute);
352
353         if (minute < 6)
354         {
355           int tens = minute;
356           if (pig.getDigit (minute))
357             minute += 10 * tens;
358         }
359       }
360       else
361       {
362         pig.restoreTo (checkpoint);
363         return false;
364       }
365       break;
366
367     case 'N':
368       if (! pig.getDigit2 (minute))
369       {
370         pig.restoreTo (checkpoint);
371         return false;
372       }
373       break;
374
375     case 's':
376       if (pig.getDigit (second))
377       {
378         if (second == 0)
379           pig.getDigit (second);
380
381         if (second < 6)
382         {
383           int tens = second;
384           if (pig.getDigit (second))
385             second += 10 * tens;
386         }
387       }
388       else
389       {
390         pig.restoreTo (checkpoint);
391         return false;
392       }
393       break;
394
395     case 'S':
396       if (! pig.getDigit2 (second))
397       {
398         pig.restoreTo (checkpoint);
399         return false;
400       }
401       break;
402
403     case 'v':
404       if (pig.getDigit (week))
405       {
406         if (week == 0)
407           pig.getDigit (week);
408
409         if (week < 6)
410         {
411           int tens = week;
412           if (pig.getDigit (week))
413             week += 10 * tens;
414         }
415       }
416       else
417       {
418         pig.restoreTo (checkpoint);
419         return false;
420       }
421       break;
422
423     case 'V':
424       if (! pig.getDigit2 (week))
425       {
426         pig.restoreTo (checkpoint);
427         return false;
428       }
429       break;
430
431     case 'a':
432       wday = Datetime::dayOfWeek (pig.str ().substr (0, 3));
433       if (wday == -1)
434       {
435         pig.restoreTo (checkpoint);
436         return false;
437       }
438
439       pig.skipN (3);
440       break;
441
442     case 'A':
443       {
444         std::string dayName;
445         if (pig.getUntil (format[f + 1], dayName))
446         {
447           wday = Datetime::dayOfWeek (dayName);
448           if (wday == -1)
449           {
450             pig.restoreTo (checkpoint);
451             return false;
452           }
453         }
454       }
455       break;
456
457     case 'b':
458       month = Datetime::monthOfYear (pig.str ().substr (0, 3));
459       if (month == -1)
460       {
461         pig.restoreTo (checkpoint);
462         return false;
463       }
464
465       pig.skipN (3);
466       break;
467
468     case 'B':
469       {
470         std::string monthName;
471         if (pig.getUntil (format[f + 1], monthName))
472         {
473           month = Datetime::monthOfYear (monthName);
474           if (month == -1)
475           {
476             pig.restoreTo (checkpoint);
477             return false;
478           }
479         }
480       }
481       break;
482
483     default:
484       if (! pig.skip (format[f]))
485       {
486         pig.restoreTo (checkpoint);
487         return false;
488       }
489       break;
490     }
491   }
492
493   // It is possible that the format='Y-M-D', and the input is Y-M-DTH:N:SZ, and
494   // this should not be considered a match.
495   if (! pig.eos () && ! unicodeWhitespace (pig.peek ()))
496   {
497     pig.restoreTo (checkpoint);
498     return false;
499   }
500
501   // Missing values are filled in from the current date.
502   if (year == -1)
503   {
504     Datetime now;
505     year = now.year ();
506     if (month == -1)
507     {
508       month = now.month ();
509       if (day == -1)
510       {
511         day = now.day ();
512         if (hour == -1)
513         {
514           hour = now.hour ();
515           if (minute == -1)
516           {
517             minute = now.minute ();
518             if (second == -1)
519               second = now.second ();
520           }
521         }
522       }
523     }
524   }
525
526   // Any remaining undefined values are assigned defaults.
527   if (month  == -1) month  = 1;
528   if (day    == -1) day    = 1;
529   if (hour   == -1) hour   = 0;
530   if (minute == -1) minute = 0;
531   if (second == -1) second = 0;
532
533   _year    = year;
534   _month   = month;
535   _day     = day;
536   _seconds = (hour * 3600) + (minute * 60) + second;
537
538   return true;
539 }
540
541 ////////////////////////////////////////////////////////////////////////////////
542 // Note how these are all single words.
543 //
544 // Examples and descriptions, assuming now == 2017-03-05T12:34:56.
545 //
546 //                  Example              Notes
547 //                  -------------------  ------------------
548 //   now            2017-03-05T12:34:56  Unaffected
549 //   yesterday      2017-03-04T00:00:00  Unaffected
550 //   today          2017-03-05T00:00:00  Unaffected
551 //   tomorrow       2017-03-06T00:00:00  Unaffected
552 //   <ordinal> 12th 2017-03-12T00:00:00
553 //   <day> monday   2017-03-06T00:00:00
554 //   <month> april  2017-04-01T00:00:00
555 //   later          2038-01-18T00:00:00  Unaffected
556 //   someday        2038-01-18T00:00:00  Unaffected
557 //   sopd           2017-03-04T00:00:00  Unaffected
558 //   sod            2017-03-05T00:00:00  Unaffected
559 //   sond           2017-03-06T00:00:00  Unaffected
560 //   eopd           2017-03-05T00:00:00  Unaffected
561 //   eod            2017-03-06T00:00:00  Unaffected
562 //   eond           2017-03-07T00:00:00  Unaffected
563 //   sopw           2017-02-26T00:00:00  Unaffected
564 //   sow            2017-03-05T00:00:00  Unaffected
565 //   sonw           2017-03-12T00:00:00  Unaffected
566 //   eopw           2017-03-05T00:00:00  Unaffected
567 //   eow            2017-03-12T00:00:00  Unaffected
568 //   eonw           2017-03-19T00:00:00  Unaffected
569 //   sopww          2017-02-27T00:00:00  Unaffected
570 //   soww           2017-03-06T00:00:00
571 //   sonww          2017-03-06T00:00:00  Unaffected
572 //   eopww          2017-03-03T00:00:00  Unaffected
573 //   eoww           2017-03-10T00:00:00
574 //   eonww          2017-03-17T00:00:00  Unaffected
575 //   sopm           2017-02-01T00:00:00  Unaffected
576 //   som            2017-03-01T00:00:00  Unaffected
577 //   sonm           2017-04-01T00:00:00  Unaffected
578 //   eopm           2017-03-01T00:00:00  Unaffected
579 //   eom            2017-04-01T00:00:00  Unaffected
580 //   eonm           2017-05-01T00:00:00  Unaffected
581 //   sopq           2017-10-01T00:00:00  Unaffected
582 //   soq            2017-01-01T00:00:00  Unaffected
583 //   sonq           2017-04-01T00:00:00  Unaffected
584 //   eopq           2017-01-01T00:00:00  Unaffected
585 //   eoq            2017-04-01T00:00:00  Unaffected
586 //   eonq           2017-07-01T00:00:00  Unaffected
587 //   sopy           2016-01-01T00:00:00  Unaffected
588 //   soy            2017-01-01T00:00:00  Unaffected
589 //   sony           2018-01-01T00:00:00  Unaffected
590 //   eopy           2017-01-01T00:00:00  Unaffected
591 //   eoy            2018-01-01T00:00:00  Unaffected
592 //   eony           2019-01-01T00:00:00  Unaffected
593 //   easter         2017-04-16T00:00:00
594 //   eastermonday   2017-04-16T00:00:00
595 //   ascension      2017-05-25T00:00:00
596 //   pentecost      2017-06-04T00:00:00
597 //   goodfriday     2017-04-14T00:00:00
598 //   midsommar      2017-06-24T00:00:00  midnight, 1st Saturday after 20th June
599 //   midsommarafton 2017-06-23T00:00:00  midnight, 1st Friday after 19th June
600 //   juhannus       2017-06-23T00:00:00  midnight, 1st Friday after 19th June
601 //
602 bool Datetime::parse_named (Pig& pig)
603 {
604   auto checkpoint = pig.cursor ();
605
606   // Experimental handling of date phrases, such as "first monday in march".
607   // Note that this requires that phrases are deliminted by EOS or WS.
608   std::string token;
609   std::vector <std::string> tokens;
610   while (pig.getUntilWS (token))
611   {
612     tokens.push_back (token);
613     if (! pig.skipWS ())
614       break;
615   }
616
617 /*
618   // This grpoup contains "1st monday ..." which must be processed before
619   // initializeOrdinal below.
620   if (initializeNthDayInMonth (tokens))
621   {
622     return true;
623   }
624 */
625
626   // Restoration necessary because of the tokenization.
627   pig.restoreTo (checkpoint);
628
629   if (initializeNow            (pig) ||
630       initializeYesterday      (pig) ||
631       initializeToday          (pig) ||
632       initializeTomorrow       (pig) ||
633       initializeOrdinal        (pig) ||
634       initializeDayName        (pig) ||
635       initializeMonthName      (pig) ||
636       initializeLater          (pig) ||
637       initializeSopd           (pig) ||
638       initializeSod            (pig) ||
639       initializeSond           (pig) ||
640       initializeEopd           (pig) ||
641       initializeEod            (pig) ||
642       initializeEond           (pig) ||
643       initializeSopw           (pig) ||
644       initializeSow            (pig) ||
645       initializeSonw           (pig) ||
646       initializeEopw           (pig) ||
647       initializeEow            (pig) ||
648       initializeEonw           (pig) ||
649       initializeSopww          (pig) ||  // Must appear after sopw
650       initializeSonww          (pig) ||  // Must appear after sonw
651       initializeSoww           (pig) ||  // Must appear after sow
652       initializeEopww          (pig) ||  // Must appear after eopw
653       initializeEonww          (pig) ||  // Must appear after eonw
654       initializeEoww           (pig) ||  // Must appear after eow
655       initializeSopm           (pig) ||
656       initializeSom            (pig) ||
657       initializeSonm           (pig) ||
658       initializeEopm           (pig) ||
659       initializeEom            (pig) ||
660       initializeEonm           (pig) ||
661       initializeSopq           (pig) ||
662       initializeSoq            (pig) ||
663       initializeSonq           (pig) ||
664       initializeEopq           (pig) ||
665       initializeEoq            (pig) ||
666       initializeEonq           (pig) ||
667       initializeSopy           (pig) ||
668       initializeSoy            (pig) ||
669       initializeSony           (pig) ||
670       initializeEopy           (pig) ||
671       initializeEoy            (pig) ||
672       initializeEony           (pig) ||
673       initializeEaster         (pig) ||
674       initializeMidsommar      (pig) ||
675       initializeMidsommarafton (pig) ||
676       initializeInformalTime   (pig))
677   {
678     return true;
679   }
680
681   pig.restoreTo (checkpoint);
682   return false;
683 }
684
685 ////////////////////////////////////////////////////////////////////////////////
686 // Valid epoch values are unsigned integers after 1980-01-01T00:00:00Z. This
687 // restriction means that '12' will not be identified as an epoch date.
688 bool Datetime::parse_epoch (Pig& pig)
689 {
690   auto checkpoint = pig.cursor ();
691
692   int epoch {};
693   if (pig.getDigits (epoch)             &&
694       ! unicodeLatinAlpha (pig.peek ()) &&
695       epoch >= 315532800)
696   {
697     _date = static_cast <time_t> (epoch);
698     //std::cout << "# parse_epoch \e[33msucceed\e[0m " << pig.dump () << "\n";
699     return true;
700   }
701
702   //std::cout << "# parse_epoch fail\n";
703   pig.restoreTo (checkpoint);
704   return false;
705 }
706
707 ////////////////////////////////////////////////////////////////////////////////
708 // date_ext 'T' time_utc_ext 'Z'
709 // date_ext 'T' time_off_ext
710 // date_ext 'T' time_ext
711 bool Datetime::parse_date_time_ext (Pig& pig)
712 {
713   auto checkpoint = pig.cursor ();
714
715   if (parse_date_ext (pig) &&
716       pig.skip ('T')       &&
717       (parse_time_utc_ext (pig) ||
718        parse_time_off_ext (pig) ||
719        parse_time_ext     (pig)))
720   {
721     return true;
722   }
723
724   pig.restoreTo (checkpoint);
725   return false;
726 }
727
728 ////////////////////////////////////////////////////////////////////////////////
729 // YYYY-MM-DD
730 // YYYY-MM
731 // YYYY-DDD
732 // YYYY-Www-D
733 // YYYY-Www
734 bool Datetime::parse_date_ext (Pig& pig)
735 {
736   auto checkpoint = pig.cursor ();
737
738   int year {};
739   if (parse_year (pig, year) &&
740       pig.skip ('-'))
741   {
742     auto checkpointYear = pig.cursor ();
743
744     int month {};
745     int day {};
746     int julian {};
747
748     if (pig.skip ('W') &&
749         parse_week (pig, _week))
750     {
751       if (pig.skip ('-') &&
752           pig.getDigit (_weekday))
753       {
754         // What is happening here - must be something to do?
755       }
756
757       if (! unicodeLatinDigit (pig.peek ()))
758       {
759         _year = year;
760         return true;
761       }
762     }
763
764     pig.restoreTo (checkpointYear);
765
766     if (parse_month (pig, month) &&
767         pig.skip ('-')           &&
768         parse_day (pig, day)     &&
769         ! unicodeLatinDigit (pig.peek ()))
770     {
771       _year = year;
772       _month = month;
773       _day = day;
774       return true;
775     }
776
777     pig.restoreTo (checkpointYear);
778
779     if (parse_julian (pig, julian) &&
780         ! unicodeLatinDigit (pig.peek ()))
781     {
782       _year = year;
783       _julian = julian;
784       return true;
785     }
786
787     pig.restoreTo (checkpointYear);
788
789     if (parse_month (pig, month) &&
790         pig.peek () != '-'       &&
791         ! unicodeLatinDigit (pig.peek ()))
792     {
793       _year = year;
794       _month = month;
795       _day = 1;
796       return true;
797     }
798   }
799
800   pig.restoreTo (checkpoint);
801   return false;
802 }
803
804 ////////////////////////////////////////////////////////////////////////////////
805 // Â±hh[:mm]
806 bool Datetime::parse_off_ext (Pig& pig)
807 {
808   auto checkpoint = pig.cursor ();
809
810   int sign = pig.peek ();
811   if (sign == '+' || sign == '-')
812   {
813     pig.skipN (1);
814
815     int hour {0};
816     int minute {0};
817
818     if (parse_off_hour (pig, hour))
819     {
820       if (pig.skip (':'))
821       {
822         if (! parse_off_minute (pig, minute))
823         {
824           pig.restoreTo (checkpoint);
825           return false;
826         }
827       }
828
829       _offset = (hour * 3600) + (minute * 60);
830       if (sign == '-')
831         _offset = - _offset;
832
833       if (! unicodeLatinDigit (pig.peek ()))
834         return true;
835     }
836   }
837
838   pig.restoreTo (checkpoint);
839   return false;
840 }
841
842 ////////////////////////////////////////////////////////////////////////////////
843 // hh:mm[:ss]
844 bool Datetime::parse_time_ext (Pig& pig, bool terminated)
845 {
846   auto checkpoint = pig.cursor ();
847
848   int hour {};
849   int minute {};
850   if (parse_hour (pig, hour) &&
851       pig.skip (':')         &&
852       parse_minute (pig, minute))
853   {
854     if (pig.skip (':'))
855     {
856       int second {};
857       if (parse_second (pig, second) &&
858           ! unicodeLatinDigit (pig.peek ()) &&
859           (! terminated || (pig.peek () != '-' && pig.peek () != '+')))
860       {
861         _seconds = (hour * 3600) + (minute * 60) + second;
862         return true;
863       }
864
865       pig.restoreTo (checkpoint);
866       return false;
867     }
868
869     auto following = pig.peek ();
870     if (! unicodeLatinDigit (following)    &&
871         (! terminated || (following != '+' && following != '-')) &&
872         following != 'A'                   &&
873         following != 'a'                   &&
874         following != 'P'                   &&
875         following != 'p')
876     {
877       _seconds = (hour * 3600) + (minute * 60);
878       return true;
879     }
880   }
881
882   pig.restoreTo (checkpoint);
883   return false;
884 }
885
886 ////////////////////////////////////////////////////////////////////////////////
887 // time-ext 'Z'
888 bool Datetime::parse_time_utc_ext (Pig& pig)
889 {
890   auto checkpoint = pig.cursor ();
891
892   if (parse_time_ext (pig, false) &&
893       pig.skip ('Z'))
894   {
895     if (! unicodeLatinDigit (pig.peek ()))
896     {
897       _utc = true;
898       return true;
899     }
900   }
901
902   pig.restoreTo (checkpoint);
903   return false;
904 }
905
906 ////////////////////////////////////////////////////////////////////////////////
907 // time-ext off-ext
908 bool Datetime::parse_time_off_ext (Pig& pig)
909 {
910   auto checkpoint = pig.cursor ();
911
912   if (parse_time_ext (pig, false) &&
913       parse_off_ext (pig))
914   {
915     return true;
916   }
917
918   pig.restoreTo (checkpoint);
919   return false;
920 }
921
922 ////////////////////////////////////////////////////////////////////////////////
923 // YYYYMMDDTHHMMSSZ
924 // YYYYMMDDTHHMMSS
925 bool Datetime::parse_date_time (Pig& pig)
926 {
927   auto checkpoint = pig.cursor ();
928
929   if (parse_date (pig) &&
930       pig.skip ('T')   &&
931       (parse_time_utc (pig) ||
932        parse_time_off (pig) ||
933        parse_time     (pig)))
934   {
935     return true;
936   }
937
938   pig.restoreTo (checkpoint);
939   return false;
940 }
941
942 ////////////////////////////////////////////////////////////////////////////////
943 // YYYYWww
944 // YYYYDDD
945 // YYYYMMDD
946 // YYYYMM
947 bool Datetime::parse_date (Pig& pig)
948 {
949   auto checkpoint = pig.cursor ();
950
951   int year {};
952   int month {};
953   int julian {};
954   int week {};
955   int weekday {};
956   int day {};
957   if (parse_year (pig, year))
958   {
959     auto checkpointYear = pig.cursor ();
960
961     if (pig.skip ('W') &&
962         parse_week (pig, week))
963     {
964       if (pig.getDigit (weekday))
965         _weekday = weekday;
966
967       if (! unicodeLatinDigit (pig.peek ()))
968       {
969         _year = year;
970         _week = week;
971         return true;
972       }
973     }
974
975     pig.restoreTo (checkpointYear);
976
977     if (parse_julian (pig, julian) &&
978         ! unicodeLatinDigit (pig.peek ()))
979     {
980       _year = year;
981       _julian = julian;
982       return true;
983     }
984
985     pig.restoreTo (checkpointYear);
986
987     if (parse_month (pig, month))
988     {
989       if (parse_day (pig, day))
990       {
991         if (! unicodeLatinDigit (pig.peek ()))
992         {
993           _year = year;
994           _month = month;
995           _day = day;
996           return true;
997         }
998       }
999       else
1000       {
1001         if (! unicodeLatinDigit (pig.peek ()))
1002         {
1003           _year = year;
1004           _month = month;
1005           _day = 1;
1006           return true;
1007         }
1008       }
1009     }
1010   }
1011
1012   pig.restoreTo (checkpoint);
1013   return false;
1014 }
1015
1016 ////////////////////////////////////////////////////////////////////////////////
1017 // <time> Z
1018 bool Datetime::parse_time_utc (Pig& pig)
1019 {
1020   auto checkpoint = pig.cursor ();
1021
1022   if (parse_time (pig, false) &&
1023       pig.skip ('Z'))
1024   {
1025     _utc = true;
1026     if (! unicodeLatinDigit (pig.peek ()))
1027       return true;
1028   }
1029
1030   pig.restoreTo (checkpoint);
1031   return false;
1032 }
1033
1034 ////////////////////////////////////////////////////////////////////////////////
1035 // <time> <off>
1036 bool Datetime::parse_time_off (Pig& pig)
1037 {
1038   auto checkpoint = pig.cursor ();
1039
1040   if (parse_time (pig, false) &&
1041       parse_off (pig))
1042   {
1043     auto terminator = pig.peek ();
1044     if (terminator != '-' && ! unicodeLatinDigit (terminator))
1045     {
1046       return true;
1047     }
1048   }
1049
1050   pig.restoreTo (checkpoint);
1051   return false;
1052 }
1053
1054 ////////////////////////////////////////////////////////////////////////////////
1055 // hhmmss
1056 // hhmm
1057 bool Datetime::parse_time (Pig& pig, bool terminated)
1058 {
1059   auto checkpoint = pig.cursor ();
1060
1061   int hour {};
1062   int minute {};
1063   if (parse_hour (pig, hour) &&
1064       parse_minute (pig, minute))
1065   {
1066     int second {};
1067     parse_second (pig, second);
1068
1069     auto terminator = pig.peek ();
1070     if (! terminated ||
1071         (! unicodeLatinDigit (terminator) && terminator != '-' && terminator != '+'))
1072     {
1073       _seconds = (hour * 3600) + (minute * 60) + second;
1074       return true;
1075     }
1076   }
1077
1078   pig.restoreTo (checkpoint);
1079   return false;
1080 }
1081
1082 ////////////////////////////////////////////////////////////////////////////////
1083 // Â±hhmm
1084 // Â±hh
1085 bool Datetime::parse_off (Pig& pig)
1086 {
1087   auto checkpoint = pig.cursor ();
1088
1089   int sign = pig.peek ();
1090   if (sign == '+' || sign == '-')
1091   {
1092     pig.skipN (1);
1093
1094     int hour {};
1095     if (parse_off_hour (pig, hour))
1096     {
1097       int minute {};
1098       parse_off_minute (pig, minute);
1099
1100       if (! unicodeLatinDigit (pig.peek ()))
1101       {
1102         _offset = (hour * 3600) + (minute * 60);
1103         if (sign == '-')
1104           _offset = - _offset;
1105
1106         return true;
1107       }
1108     }
1109   }
1110
1111   pig.restoreTo (checkpoint);
1112   return false;
1113 }
1114
1115 ////////////////////////////////////////////////////////////////////////////////
1116 bool Datetime::parse_year (Pig& pig, int& value)
1117 {
1118   auto checkpoint = pig.cursor ();
1119
1120   int year;
1121   if (pig.getDigit4 (year) &&
1122       year > 1969)
1123   {
1124     value = year;
1125     return true;
1126   }
1127
1128   pig.restoreTo (checkpoint);
1129   return false;
1130 }
1131
1132 ////////////////////////////////////////////////////////////////////////////////
1133 bool Datetime::parse_month (Pig& pig, int& value)
1134 {
1135   auto checkpoint = pig.cursor ();
1136
1137   int month;
1138   if (pig.getDigit2 (month) &&
1139       month > 0             &&
1140       month <= 12)
1141   {
1142     value = month;
1143     return true;
1144   }
1145
1146   pig.restoreTo (checkpoint);
1147   return false;
1148 }
1149
1150 ////////////////////////////////////////////////////////////////////////////////
1151 bool Datetime::parse_week (Pig& pig, int& value)
1152 {
1153   auto checkpoint = pig.cursor ();
1154
1155   int week;
1156   if (pig.getDigit2 (week) &&
1157       week > 0             &&
1158       week <= 53)
1159   {
1160     value = week;
1161     return true;
1162   }
1163
1164   pig.restoreTo (checkpoint);
1165   return false;
1166 }
1167
1168 ////////////////////////////////////////////////////////////////////////////////
1169 bool Datetime::parse_julian (Pig& pig, int& value)
1170 {
1171   auto checkpoint = pig.cursor ();
1172
1173   int julian;
1174   if (pig.getDigit3 (julian) &&
1175       julian > 0             &&
1176       julian <= 366)
1177   {
1178     value = julian;
1179     return true;
1180   }
1181
1182   pig.restoreTo (checkpoint);
1183   return false;
1184 }
1185
1186 ////////////////////////////////////////////////////////////////////////////////
1187 bool Datetime::parse_day (Pig& pig, int& value)
1188 {
1189   auto checkpoint = pig.cursor ();
1190
1191   int day;
1192   if (pig.getDigit2 (day) &&
1193       day > 0             &&
1194       day <= 31)
1195   {
1196     value = day;
1197     return true;
1198   }
1199
1200   pig.restoreTo (checkpoint);
1201   return false;
1202 }
1203
1204 ////////////////////////////////////////////////////////////////////////////////
1205 bool Datetime::parse_weekday (Pig& pig, int& value)
1206 {
1207   auto checkpoint = pig.cursor ();
1208
1209   int weekday;
1210   if (pig.getDigit (weekday) &&
1211       weekday >= 1           &&
1212       weekday <= 7)
1213   {
1214     value = weekday;
1215     return true;
1216   }
1217
1218   pig.restoreTo (checkpoint);
1219   return false;
1220 }
1221
1222 ////////////////////////////////////////////////////////////////////////////////
1223 bool Datetime::parse_hour (Pig& pig, int& value)
1224 {
1225   auto checkpoint = pig.cursor ();
1226
1227   int hour;
1228   if (pig.getDigit2 (hour) &&
1229       hour >= 0            &&
1230       hour < 24)
1231   {
1232     value = hour;
1233     return true;
1234   }
1235
1236   pig.restoreTo (checkpoint);
1237   return false;
1238 }
1239
1240 ////////////////////////////////////////////////////////////////////////////////
1241 bool Datetime::parse_minute (Pig& pig, int& value)
1242 {
1243   auto checkpoint = pig.cursor ();
1244
1245   int minute;
1246   if (pig.getDigit2 (minute) &&
1247       minute >= 0            &&
1248       minute < 60)
1249   {
1250     value = minute;
1251     return true;
1252   }
1253
1254   pig.restoreTo (checkpoint);
1255   return false;
1256 }
1257
1258 ////////////////////////////////////////////////////////////////////////////////
1259 bool Datetime::parse_second (Pig& pig, int& value)
1260 {
1261   auto checkpoint = pig.cursor ();
1262
1263   int second;
1264   if (pig.getDigit2 (second) &&
1265       second >= 0            &&
1266       second < 60)
1267   {
1268     value = second;
1269     return true;
1270   }
1271
1272   pig.restoreTo (checkpoint);
1273   return false;
1274 }
1275
1276 ////////////////////////////////////////////////////////////////////////////////
1277 bool Datetime::parse_off_hour (Pig& pig, int& value)
1278 {
1279   auto checkpoint = pig.cursor ();
1280
1281   int hour;
1282   if (pig.getDigit2 (hour) &&
1283       hour >= 0            &&
1284       hour <= 12)
1285   {
1286     value = hour;
1287     return true;
1288   }
1289
1290   pig.restoreTo (checkpoint);
1291   return false;
1292 }
1293
1294 ////////////////////////////////////////////////////////////////////////////////
1295 bool Datetime::parse_off_minute (Pig& pig, int& value)
1296 {
1297   auto checkpoint = pig.cursor ();
1298
1299   int minute;
1300   if (pig.getDigit2 (minute) &&
1301       minute >= 0            &&
1302       minute < 60)
1303   {
1304     value = minute;
1305     return true;
1306   }
1307
1308   pig.restoreTo (checkpoint);
1309   return false;
1310 }
1311
1312 ////////////////////////////////////////////////////////////////////////////////
1313 // now [ !<alpha> && !<digit> ]
1314 bool Datetime::initializeNow (Pig& pig)
1315 {
1316   auto checkpoint = pig.cursor ();
1317
1318   if (pig.skipLiteral ("now"))
1319   {
1320     auto following = pig.peek ();
1321     if (! unicodeLatinAlpha (following) &&
1322         ! unicodeLatinDigit (following))
1323     {
1324       _date = time (nullptr);
1325       return true;
1326     }
1327   }
1328
1329   pig.restoreTo (checkpoint);
1330   return false;
1331 }
1332
1333 ////////////////////////////////////////////////////////////////////////////////
1334 // yesterday/abbrev  [ !<alpha> && !<digit> ]
1335 bool Datetime::initializeYesterday (Pig& pig)
1336 {
1337   auto checkpoint = pig.cursor ();
1338
1339   std::string token;
1340   if (pig.skipPartial ("yesterday", token) &&
1341       token.length () >= static_cast <std::string::size_type> (Datetime::minimumMatchLength))
1342   {
1343     auto following = pig.peek ();
1344     if (! unicodeLatinAlpha (following) &&
1345         ! unicodeLatinDigit (following))
1346     {
1347       time_t now = time (nullptr);
1348       struct tm* t = localtime (&now);
1349
1350       t->tm_hour = t->tm_min = t->tm_sec = 0;
1351       t->tm_isdst = -1;
1352       t->tm_mday -= 1;
1353       _date = mktime (t);
1354       return true;
1355     }
1356   }
1357
1358   pig.restoreTo (checkpoint);
1359   return false;
1360 }
1361
1362 ////////////////////////////////////////////////////////////////////////////////
1363 // today/abbrev  [ !<alpha> && !<digit> ]
1364 bool Datetime::initializeToday (Pig& pig)
1365 {
1366   auto checkpoint = pig.cursor ();
1367
1368   std::string token;
1369   if (pig.skipPartial ("today", token) &&
1370       token.length () >= static_cast <std::string::size_type> (Datetime::minimumMatchLength))
1371   {
1372     auto following = pig.peek ();
1373     if (! unicodeLatinAlpha (following) &&
1374         ! unicodeLatinDigit (following))
1375     {
1376       time_t now = time (nullptr);
1377       struct tm* t = localtime (&now);
1378
1379       t->tm_hour = t->tm_min = t->tm_sec = 0;
1380       t->tm_isdst = -1;
1381       _date = mktime (t);
1382
1383       return true;
1384     }
1385   }
1386
1387   pig.restoreTo (checkpoint);
1388   return false;
1389 }
1390
1391 ////////////////////////////////////////////////////////////////////////////////
1392 // tomcorrow/abbrev  [ !<alpha> && !<digit> ]
1393 bool Datetime::initializeTomorrow (Pig& pig)
1394 {
1395   auto checkpoint = pig.cursor ();
1396
1397   std::string token;
1398   if (pig.skipPartial ("tomorrow", token) &&
1399       token.length () >= static_cast <std::string::size_type> (Datetime::minimumMatchLength))
1400   {
1401     auto following = pig.peek ();
1402     if (! unicodeLatinAlpha (following) &&
1403         ! unicodeLatinDigit (following))
1404     {
1405       time_t now = time (nullptr);
1406       struct tm* t = localtime (&now);
1407
1408       t->tm_mday++;
1409       t->tm_hour = t->tm_min = t->tm_sec = 0;
1410       t->tm_isdst = -1;
1411       _date = mktime (t);
1412       return true;
1413     }
1414   }
1415
1416   pig.restoreTo (checkpoint);
1417   return false;
1418 }
1419
1420 ////////////////////////////////////////////////////////////////////////////////
1421 // <digit>+ [ "st" | "nd" | "rd" | "th" ] [ !<alpha> && !<digit> ]
1422 bool Datetime::initializeOrdinal (Pig& pig)
1423 {
1424   auto checkpoint = pig.cursor ();
1425
1426   int number = 0;
1427   if (pig.getDigits (number) &&
1428       number > 0             &&
1429       number <= 31)
1430   {
1431     int character1;
1432     int character2;
1433     if (pig.getCharacter (character1)     &&
1434         pig.getCharacter (character2)     &&
1435         ! unicodeLatinAlpha (pig.peek ()) &&
1436         ! unicodeLatinDigit (pig.peek ()))
1437     {
1438       int remainder1 = number % 10;
1439       int remainder2 = number % 100;
1440       if ((remainder2 != 11 && remainder1 == 1 && character1 == 's' && character2 == 't') ||
1441           (remainder2 != 12 && remainder1 == 2 && character1 == 'n' && character2 == 'd') ||
1442           (remainder2 != 13 && remainder1 == 3 && character1 == 'r' && character2 == 'd') ||
1443           ((remainder2 == 11 ||
1444             remainder2 == 12 ||
1445             remainder2 == 13 ||
1446             remainder1 == 0 ||
1447             remainder1 > 3) && character1 == 't' && character2 == 'h'))
1448       {
1449         time_t now = time (nullptr);
1450         struct tm* t = localtime (&now);
1451
1452         int y = t->tm_year + 1900;
1453         int m = t->tm_mon + 1;
1454         int d = t->tm_mday;
1455
1456         // If it is this month.
1457         if (d < number &&
1458             number <= daysInMonth (y, m))
1459         {
1460           t->tm_hour = t->tm_min = t->tm_sec = 0;
1461           t->tm_mon  = m - 1;
1462           t->tm_mday = number;
1463           t->tm_year = y - 1900;
1464           t->tm_isdst = -1;
1465           _date = mktime (t);
1466         }
1467         else
1468         {
1469           if (++m > 12)
1470           {
1471             m = 1;
1472             y++;
1473           }
1474
1475           t->tm_hour = t->tm_min = t->tm_sec = 0;
1476           t->tm_mon  = m - 1;
1477           t->tm_mday = number;
1478           t->tm_year = y - 1900;
1479           t->tm_isdst = -1;
1480           _date = mktime (t);
1481         }
1482
1483         return true;
1484       }
1485     }
1486   }
1487
1488   pig.restoreTo (checkpoint);
1489   return false;
1490 }
1491
1492 ////////////////////////////////////////////////////////////////////////////////
1493 // sunday/abbrev [ !<alpha> && !<digit> && !: && != ]
1494 bool Datetime::initializeDayName (Pig& pig)
1495 {
1496   auto checkpoint = pig.cursor ();
1497
1498   std::string token;
1499   for (int day = 0; day <= 7; ++day)   // Deliberate <= so that 'sunday' is either 0 or 7.
1500   {
1501     if (pig.skipPartial (dayNames[day % 7], token) &&
1502         token.length () >= static_cast <std::string::size_type> (Datetime::minimumMatchLength))
1503     {
1504       auto following = pig.peek ();
1505       if (! unicodeLatinAlpha (following) &&
1506           ! unicodeLatinDigit (following) &&
1507           following != ':' &&
1508           following != '=')
1509       {
1510         time_t now = time (nullptr);
1511         struct tm* t = localtime (&now);
1512
1513         if (t->tm_wday >= day)
1514           t->tm_mday += day - t->tm_wday + 7;
1515         else
1516           t->tm_mday += day - t->tm_wday;
1517
1518         t->tm_hour = t->tm_min = t->tm_sec = 0;
1519         t->tm_isdst = -1;
1520         _date = mktime (t);
1521         return true;
1522       }
1523     }
1524
1525     pig.restoreTo (checkpoint);
1526   }
1527
1528   return false;
1529 }
1530
1531 ////////////////////////////////////////////////////////////////////////////////
1532 // january/abbrev [ !<alpha> && !<digit> && !: && != ]
1533 bool Datetime::initializeMonthName (Pig& pig)
1534 {
1535   auto checkpoint = pig.cursor ();
1536
1537   std::string token;
1538   for (int month = 0; month < 12; ++month)
1539   {
1540     if (pig.skipPartial (monthNames[month], token) &&
1541         token.length () >= static_cast <std::string::size_type> (Datetime::minimumMatchLength))
1542     {
1543       auto following = pig.peek ();
1544       if (! unicodeLatinAlpha (following) &&
1545           ! unicodeLatinDigit (following) &&
1546           following != ':' &&
1547           following != '=')
1548       {
1549         time_t now = time (nullptr);
1550         struct tm* t = localtime (&now);
1551
1552         if (t->tm_mon >= month)
1553           t->tm_year++;
1554
1555         t->tm_mon = month;
1556         t->tm_mday = 1;
1557         t->tm_hour = t->tm_min = t->tm_sec = 0;
1558         t->tm_isdst = -1;
1559         _date = mktime (t);
1560         return true;
1561       }
1562     }
1563
1564     pig.restoreTo (checkpoint);
1565   }
1566
1567   return false;
1568 }
1569
1570 ////////////////////////////////////////////////////////////////////////////////
1571 // later/abbrev  [ !<alpha> && !<digit> ]
1572 // someday/abbrev  [ !<alpha> && !<digit> ]
1573 bool Datetime::initializeLater (Pig& pig)
1574 {
1575   auto checkpoint = pig.cursor ();
1576
1577   std::string token;
1578   if ((pig.skipPartial ("later", token) &&
1579       token.length () >= static_cast <std::string::size_type> (Datetime::minimumMatchLength))
1580
1581       ||
1582
1583      (pig.skipPartial ("someday", token) &&
1584       token.length () >= static_cast <std::string::size_type> (std::max (Datetime::minimumMatchLength, 4))))
1585   {
1586     auto following = pig.peek ();
1587     if (! unicodeLatinAlpha (following) &&
1588         ! unicodeLatinDigit (following))
1589     {
1590       time_t now = time (nullptr);
1591       struct tm* t = localtime (&now);
1592
1593       t->tm_hour = t->tm_min = t->tm_sec = 0;
1594       t->tm_year = 138;
1595       t->tm_mon = 0;
1596       t->tm_mday = 18;
1597       t->tm_isdst = -1;
1598       _date = mktime (t);
1599       return true;
1600     }
1601   }
1602
1603   pig.restoreTo (checkpoint);
1604   return false;
1605 }
1606
1607 ////////////////////////////////////////////////////////////////////////////////
1608 // sopd [ !<alpha> && !<digit> ]
1609 bool Datetime::initializeSopd (Pig& pig)
1610 {
1611   auto checkpoint = pig.cursor ();
1612
1613   if (pig.skipLiteral ("sopd"))
1614   {
1615     auto following = pig.peek ();
1616     if (! unicodeLatinAlpha (following) &&
1617         ! unicodeLatinDigit (following))
1618     {
1619       time_t now = time (nullptr);
1620       struct tm* t = localtime (&now);
1621
1622       t->tm_hour = t->tm_min = t->tm_sec = 0;
1623       t->tm_isdst = -1;
1624       t->tm_mday -= 1;
1625       _date = mktime (t);
1626       return true;
1627     }
1628   }
1629
1630   pig.restoreTo (checkpoint);
1631   return false;
1632 }
1633
1634 ////////////////////////////////////////////////////////////////////////////////
1635 // sod [ !<alpha> && !<digit> ]
1636 bool Datetime::initializeSod (Pig& pig)
1637 {
1638   auto checkpoint = pig.cursor ();
1639
1640   if (pig.skipLiteral ("sod"))
1641   {
1642     auto following = pig.peek ();
1643     if (! unicodeLatinAlpha (following) &&
1644         ! unicodeLatinDigit (following))
1645     {
1646       time_t now = time (nullptr);
1647       struct tm* t = localtime (&now);
1648
1649       t->tm_hour = t->tm_min = t->tm_sec = 0;
1650       t->tm_isdst = -1;
1651       _date = mktime (t);
1652       return true;
1653     }
1654   }
1655
1656   pig.restoreTo (checkpoint);
1657   return false;
1658 }
1659
1660 ////////////////////////////////////////////////////////////////////////////////
1661 // sond [ !<alpha> && !<digit> ]
1662 bool Datetime::initializeSond (Pig& pig)
1663 {
1664   auto checkpoint = pig.cursor ();
1665
1666   if (pig.skipLiteral ("sond"))
1667   {
1668     auto following = pig.peek ();
1669     if (! unicodeLatinAlpha (following) &&
1670         ! unicodeLatinDigit (following))
1671     {
1672       time_t now = time (nullptr);
1673       struct tm* t = localtime (&now);
1674
1675       t->tm_mday++;
1676       t->tm_hour = t->tm_min = t->tm_sec = 0;
1677       t->tm_isdst = -1;
1678       _date = mktime (t);
1679       return true;
1680     }
1681   }
1682
1683   pig.restoreTo (checkpoint);
1684   return false;
1685 }
1686
1687 ////////////////////////////////////////////////////////////////////////////////
1688 // eopd [ !<alpha> && !<digit> ]
1689 bool Datetime::initializeEopd (Pig& pig)
1690 {
1691   auto checkpoint = pig.cursor ();
1692
1693   if (pig.skipLiteral ("eopd"))
1694   {
1695     auto following = pig.peek ();
1696     if (! unicodeLatinAlpha (following) &&
1697         ! unicodeLatinDigit (following))
1698     {
1699       time_t now = time (nullptr);
1700       struct tm* t = localtime (&now);
1701
1702       t->tm_hour = t->tm_min = t->tm_sec = 0;
1703       t->tm_isdst = -1;
1704       _date = mktime (t);
1705       return true;
1706     }
1707   }
1708
1709   pig.restoreTo (checkpoint);
1710   return false;
1711 }
1712
1713 ////////////////////////////////////////////////////////////////////////////////
1714 // eod [ !<alpha> && !<digit> ]
1715 bool Datetime::initializeEod (Pig& pig)
1716 {
1717   auto checkpoint = pig.cursor ();
1718
1719   if (pig.skipLiteral ("eod"))
1720   {
1721     auto following = pig.peek ();
1722     if (! unicodeLatinAlpha (following) &&
1723         ! unicodeLatinDigit (following))
1724     {
1725       time_t now = time (nullptr);
1726       struct tm* t = localtime (&now);
1727
1728       t->tm_mday++;
1729       t->tm_hour = t->tm_min = t->tm_sec = 0;
1730       t->tm_isdst = -1;
1731       _date = mktime (t);
1732       return true;
1733     }
1734   }
1735
1736   pig.restoreTo (checkpoint);
1737   return false;
1738 }
1739
1740 ////////////////////////////////////////////////////////////////////////////////
1741 // eond [ !<alpha> && !<digit> ]
1742 bool Datetime::initializeEond (Pig& pig)
1743 {
1744   auto checkpoint = pig.cursor ();
1745
1746   if (pig.skipLiteral ("eond"))
1747   {
1748     auto following = pig.peek ();
1749     if (! unicodeLatinAlpha (following) &&
1750         ! unicodeLatinDigit (following))
1751     {
1752       time_t now = time (nullptr);
1753       struct tm* t = localtime (&now);
1754
1755       t->tm_mday += 2;
1756       t->tm_hour = t->tm_min = t->tm_sec = 0;
1757       t->tm_isdst = -1;
1758       _date = mktime (t);
1759       return true;
1760     }
1761   }
1762
1763   pig.restoreTo (checkpoint);
1764   return false;
1765 }
1766
1767 ////////////////////////////////////////////////////////////////////////////////
1768 // sopw [ !<alpha> && !<digit> ]
1769 bool Datetime::initializeSopw (Pig& pig)
1770 {
1771   auto checkpoint = pig.cursor ();
1772
1773   if (pig.skipLiteral ("sopw"))
1774   {
1775     auto following = pig.peek ();
1776     if (! unicodeLatinAlpha (following) &&
1777         ! unicodeLatinDigit (following))
1778     {
1779       time_t now = time (nullptr);
1780       struct tm* t = localtime (&now);
1781       t->tm_hour = t->tm_min = t->tm_sec = 0;
1782
1783       int extra = (t->tm_wday + 6) % 7;
1784       t->tm_mday -= extra;
1785       t->tm_mday -= 7;
1786
1787       t->tm_isdst = -1;
1788       _date = mktime (t);
1789       return true;
1790     }
1791   }
1792
1793   pig.restoreTo (checkpoint);
1794   return false;
1795 }
1796
1797 ////////////////////////////////////////////////////////////////////////////////
1798 // sow [ !<alpha> && !<digit> ]
1799 bool Datetime::initializeSow (Pig& pig)
1800 {
1801   auto checkpoint = pig.cursor ();
1802
1803   if (pig.skipLiteral ("sow"))
1804   {
1805     auto following = pig.peek ();
1806     if (! unicodeLatinAlpha (following) &&
1807         ! unicodeLatinDigit (following))
1808     {
1809       time_t now = time (nullptr);
1810       struct tm* t = localtime (&now);
1811       t->tm_hour = t->tm_min = t->tm_sec = 0;
1812
1813       int extra = (t->tm_wday + 6) % 7;
1814       t->tm_mday -= extra;
1815
1816       t->tm_isdst = -1;
1817       _date = mktime (t);
1818       return true;
1819     }
1820   }
1821
1822   pig.restoreTo (checkpoint);
1823   return false;
1824 }
1825
1826 ////////////////////////////////////////////////////////////////////////////////
1827 // sonw [ !<alpha> && !<digit> ]
1828 bool Datetime::initializeSonw (Pig& pig)
1829 {
1830   auto checkpoint = pig.cursor ();
1831
1832   if (pig.skipLiteral ("sonw"))
1833   {
1834     auto following = pig.peek ();
1835     if (! unicodeLatinAlpha (following) &&
1836         ! unicodeLatinDigit (following))
1837     {
1838       time_t now = time (nullptr);
1839       struct tm* t = localtime (&now);
1840       t->tm_hour = t->tm_min = t->tm_sec = 0;
1841
1842       int extra = (t->tm_wday + 6) % 7;
1843       t->tm_mday -= extra;
1844       t->tm_mday += 7;
1845
1846       t->tm_isdst = -1;
1847       _date = mktime (t);
1848       return true;
1849     }
1850   }
1851
1852   pig.restoreTo (checkpoint);
1853   return false;
1854 }
1855
1856 ////////////////////////////////////////////////////////////////////////////////
1857 // eopw [ !<alpha> && !<digit> ]
1858 bool Datetime::initializeEopw (Pig& pig)
1859 {
1860   auto checkpoint = pig.cursor ();
1861
1862   if (pig.skipLiteral ("eopw"))
1863   {
1864     auto following = pig.peek ();
1865     if (! unicodeLatinAlpha (following) &&
1866         ! unicodeLatinDigit (following))
1867     {
1868       time_t now = time (nullptr);
1869       struct tm* t = localtime (&now);
1870       t->tm_hour = t->tm_min = t->tm_sec = 0;
1871
1872       int extra = (t->tm_wday + 6) % 7;
1873       t->tm_mday -= extra;
1874
1875       t->tm_isdst = -1;
1876       _date = mktime (t);
1877       return true;
1878     }
1879   }
1880
1881   pig.restoreTo (checkpoint);
1882   return false;
1883 }
1884
1885 ////////////////////////////////////////////////////////////////////////////////
1886 // eow [ !<alpha> && !<digit> ]
1887 bool Datetime::initializeEow (Pig& pig)
1888 {
1889   auto checkpoint = pig.cursor ();
1890
1891   if (pig.skipLiteral ("eow"))
1892   {
1893     auto following = pig.peek ();
1894     if (! unicodeLatinAlpha (following) &&
1895         ! unicodeLatinDigit (following))
1896     {
1897       time_t now = time (nullptr);
1898       struct tm* t = localtime (&now);
1899       t->tm_hour = t->tm_min = t->tm_sec = 0;
1900
1901       int extra = (t->tm_wday + 6) % 7;
1902       t->tm_mday -= extra;
1903       t->tm_mday += 7;
1904
1905       t->tm_isdst = -1;
1906       _date = mktime (t);
1907       return true;
1908     }
1909   }
1910
1911   pig.restoreTo (checkpoint);
1912   return false;
1913 }
1914
1915 ////////////////////////////////////////////////////////////////////////////////
1916 // eonw [ !<alpha> && !<digit> ]
1917 bool Datetime::initializeEonw (Pig& pig)
1918 {
1919   auto checkpoint = pig.cursor ();
1920
1921   if (pig.skipLiteral ("eonw"))
1922   {
1923     auto following = pig.peek ();
1924     if (! unicodeLatinAlpha (following) &&
1925         ! unicodeLatinDigit (following))
1926     {
1927       time_t now = time (nullptr);
1928       struct tm* t = localtime (&now);
1929
1930       t->tm_mday += 15 - t->tm_wday;
1931       t->tm_hour = t->tm_min = t->tm_sec = 0;
1932       t->tm_isdst = -1;
1933       _date = mktime (t);
1934       return true;
1935     }
1936   }
1937
1938   pig.restoreTo (checkpoint);
1939   return false;
1940 }
1941
1942 ////////////////////////////////////////////////////////////////////////////////
1943 // sopww [ !<alpha> && !<digit> ]
1944 bool Datetime::initializeSopww (Pig& pig)
1945 {
1946   auto checkpoint = pig.cursor ();
1947
1948   if (pig.skipLiteral ("sopww"))
1949   {
1950     auto following = pig.peek ();
1951     if (! unicodeLatinAlpha (following) &&
1952         ! unicodeLatinDigit (following))
1953     {
1954       time_t now = time (nullptr);
1955       struct tm* t = localtime (&now);
1956
1957       t->tm_mday += -6 - t->tm_wday;
1958       t->tm_hour = t->tm_min = t->tm_sec = 0;
1959       t->tm_isdst = -1;
1960       _date = mktime (t);
1961       return true;
1962     }
1963   }
1964
1965   pig.restoreTo (checkpoint);
1966   return false;
1967 }
1968
1969 ////////////////////////////////////////////////////////////////////////////////
1970 // soww [ !<alpha> && !<digit> ]
1971 bool Datetime::initializeSoww (Pig& pig)
1972 {
1973   auto checkpoint = pig.cursor ();
1974
1975   if (pig.skipLiteral ("soww"))
1976   {
1977     auto following = pig.peek ();
1978     if (! unicodeLatinAlpha (following) &&
1979         ! unicodeLatinDigit (following))
1980     {
1981       time_t now = time (nullptr);
1982       struct tm* t = localtime (&now);
1983
1984       t->tm_mday += 8 - t->tm_wday;
1985       t->tm_hour = t->tm_min = t->tm_sec = 0;
1986       t->tm_isdst = -1;
1987       _date = mktime (t);
1988       return true;
1989     }
1990   }
1991
1992   pig.restoreTo (checkpoint);
1993   return false;
1994 }
1995
1996 ////////////////////////////////////////////////////////////////////////////////
1997 // sonww [ !<alpha> && !<digit> ]
1998 bool Datetime::initializeSonww (Pig& pig)
1999 {
2000   auto checkpoint = pig.cursor ();
2001
2002   if (pig.skipLiteral ("sonww"))
2003   {
2004     auto following = pig.peek ();
2005     if (! unicodeLatinAlpha (following) &&
2006         ! unicodeLatinDigit (following))
2007     {
2008       time_t now = time (nullptr);
2009       struct tm* t = localtime (&now);
2010
2011       t->tm_mday += 8 - t->tm_wday;
2012       t->tm_hour = t->tm_min = t->tm_sec = 0;
2013       t->tm_isdst = -1;
2014       _date = mktime (t);
2015       return true;
2016     }
2017   }
2018
2019   pig.restoreTo (checkpoint);
2020   return false;
2021 }
2022
2023 ////////////////////////////////////////////////////////////////////////////////
2024 // eopww [ !<alpha> && !<digit> ]
2025 bool Datetime::initializeEopww (Pig& pig)
2026 {
2027   auto checkpoint = pig.cursor ();
2028
2029   if (pig.skipLiteral ("eopww"))
2030   {
2031     auto following = pig.peek ();
2032     if (! unicodeLatinAlpha (following) &&
2033         ! unicodeLatinDigit (following))
2034     {
2035       time_t now = time (nullptr);
2036       struct tm* t = localtime (&now);
2037
2038       t->tm_mday -= (t->tm_wday + 1) % 7;
2039       t->tm_hour = t->tm_min = t->tm_sec = 0;
2040       t->tm_isdst = -1;
2041       _date = mktime (t);
2042       return true;
2043     }
2044   }
2045
2046   pig.restoreTo (checkpoint);
2047   return false;
2048 }
2049
2050 ////////////////////////////////////////////////////////////////////////////////
2051 // eoww [ !<alpha> && !<digit> ]
2052 bool Datetime::initializeEoww (Pig& pig)
2053 {
2054   auto checkpoint = pig.cursor ();
2055
2056   if (pig.skipLiteral ("eoww"))
2057   {
2058     auto following = pig.peek ();
2059     if (! unicodeLatinAlpha (following) &&
2060         ! unicodeLatinDigit (following))
2061     {
2062       time_t now = time (nullptr);
2063       struct tm* t = localtime (&now);
2064
2065       t->tm_mday += 6 - t->tm_wday;
2066       t->tm_hour = t->tm_min = t->tm_sec = 0;
2067       t->tm_isdst = -1;
2068       _date = mktime (t);
2069       return true;
2070     }
2071   }
2072
2073   pig.restoreTo (checkpoint);
2074   return false;
2075 }
2076
2077 ////////////////////////////////////////////////////////////////////////////////
2078 // eonww [ !<alpha> && !<digit> ]
2079 bool Datetime::initializeEonww (Pig& pig)
2080 {
2081   auto checkpoint = pig.cursor ();
2082
2083   if (pig.skipLiteral ("eonww"))
2084   {
2085     auto following = pig.peek ();
2086     if (! unicodeLatinAlpha (following) &&
2087         ! unicodeLatinDigit (following))
2088     {
2089       time_t now = time (nullptr);
2090       struct tm* t = localtime (&now);
2091
2092       t->tm_mday += 13 - t->tm_wday;
2093       t->tm_hour = t->tm_min = t->tm_sec = 0;
2094       t->tm_isdst = -1;
2095       _date = mktime (t);
2096       return true;
2097     }
2098   }
2099
2100   pig.restoreTo (checkpoint);
2101   return false;
2102 }
2103
2104 ////////////////////////////////////////////////////////////////////////////////
2105 // sopm [ !<alpha> && !<digit> ]
2106 bool Datetime::initializeSopm (Pig& pig)
2107 {
2108   auto checkpoint = pig.cursor ();
2109
2110   if (pig.skipLiteral ("sopm"))
2111   {
2112     auto following = pig.peek ();
2113     if (! unicodeLatinAlpha (following) &&
2114         ! unicodeLatinDigit (following))
2115     {
2116       time_t now = time (nullptr);
2117       struct tm* t = localtime (&now);
2118
2119       t->tm_hour = t->tm_min = t->tm_sec = 0;
2120
2121       if (t->tm_mon == 0)
2122       {
2123         t->tm_year--;
2124         t->tm_mon = 11;
2125       }
2126       else
2127         t->tm_mon--;
2128
2129       t->tm_mday = 1;
2130       t->tm_isdst = -1;
2131       _date = mktime (t);
2132       return true;
2133     }
2134   }
2135
2136   pig.restoreTo (checkpoint);
2137   return false;
2138 }
2139
2140 ////////////////////////////////////////////////////////////////////////////////
2141 // som [ !<alpha> && !<digit> ]
2142 bool Datetime::initializeSom (Pig& pig)
2143 {
2144   auto checkpoint = pig.cursor ();
2145
2146   if (pig.skipLiteral ("som"))
2147   {
2148     auto following = pig.peek ();
2149     if (! unicodeLatinAlpha (following) &&
2150         ! unicodeLatinDigit (following))
2151     {
2152       time_t now = time (nullptr);
2153       struct tm* t = localtime (&now);
2154
2155       t->tm_hour = t->tm_min = t->tm_sec = 0;
2156       t->tm_mday = 1;
2157       t->tm_isdst = -1;
2158       _date = mktime (t);
2159       return true;
2160     }
2161   }
2162
2163   pig.restoreTo (checkpoint);
2164   return false;
2165 }
2166
2167 ////////////////////////////////////////////////////////////////////////////////
2168 // sonm [ !<alpha> && !<digit> ]
2169 bool Datetime::initializeSonm (Pig& pig)
2170 {
2171   auto checkpoint = pig.cursor ();
2172
2173   if (pig.skipLiteral ("sonm"))
2174   {
2175     auto following = pig.peek ();
2176     if (! unicodeLatinAlpha (following) &&
2177         ! unicodeLatinDigit (following))
2178     {
2179       time_t now = time (nullptr);
2180       struct tm* t = localtime (&now);
2181
2182       t->tm_hour = t->tm_min = t->tm_sec = 0;
2183
2184       t->tm_mon++;
2185       if (t->tm_mon > 11)
2186       {
2187         t->tm_year++;
2188         t->tm_mon = 0;
2189       }
2190
2191       t->tm_mday = 1;
2192       t->tm_isdst = -1;
2193       _date = mktime (t);
2194       return true;
2195     }
2196   }
2197
2198   pig.restoreTo (checkpoint);
2199   return false;
2200 }
2201
2202 ////////////////////////////////////////////////////////////////////////////////
2203 // eopm [ !<alpha> && !<digit> ]
2204 bool Datetime::initializeEopm (Pig& pig)
2205 {
2206   auto checkpoint = pig.cursor ();
2207
2208   if (pig.skipLiteral ("eopm"))
2209   {
2210     auto following = pig.peek ();
2211     if (! unicodeLatinAlpha (following) &&
2212         ! unicodeLatinDigit (following))
2213     {
2214       time_t now = time (nullptr);
2215       struct tm* t = localtime (&now);
2216
2217       t->tm_hour = t->tm_min = t->tm_sec = 0;
2218       t->tm_mday = 1;
2219       t->tm_isdst = -1;
2220       _date = mktime (t);
2221       return true;
2222     }
2223   }
2224
2225   pig.restoreTo (checkpoint);
2226   return false;
2227 }
2228
2229 ////////////////////////////////////////////////////////////////////////////////
2230 // eom [ !<alpha> && !<digit> ]
2231 bool Datetime::initializeEom (Pig& pig)
2232 {
2233   auto checkpoint = pig.cursor ();
2234
2235   if (pig.skipLiteral ("eom"))
2236   {
2237     auto following = pig.peek ();
2238     if (! unicodeLatinAlpha (following) &&
2239         ! unicodeLatinDigit (following))
2240     {
2241       time_t now = time (nullptr);
2242       struct tm* t = localtime (&now);
2243
2244       t->tm_hour = t->tm_min = t->tm_sec = 0;
2245
2246       t->tm_mon++;
2247       if (t->tm_mon > 11)
2248       {
2249         t->tm_year++;
2250         t->tm_mon = 0;
2251       }
2252
2253       t->tm_mday = 1;
2254       t->tm_isdst = -1;
2255       _date = mktime (t);
2256       return true;
2257     }
2258   }
2259
2260   pig.restoreTo (checkpoint);
2261   return false;
2262 }
2263
2264 ////////////////////////////////////////////////////////////////////////////////
2265 // eonm [ !<alpha> && !<digit> ]
2266 bool Datetime::initializeEonm (Pig& pig)
2267 {
2268   auto checkpoint = pig.cursor ();
2269
2270   if (pig.skipLiteral ("eonm"))
2271   {
2272     auto following = pig.peek ();
2273     if (! unicodeLatinAlpha (following) &&
2274         ! unicodeLatinDigit (following))
2275     {
2276       time_t now = time (nullptr);
2277       struct tm* t = localtime (&now);
2278
2279       t->tm_hour = t->tm_min = t->tm_sec = 0;
2280       t->tm_mday = 1;
2281       t->tm_mon += 2;
2282       if (t->tm_mon > 11)
2283       {
2284         t->tm_year++;
2285         t->tm_mon -= 12;
2286       }
2287
2288       t->tm_isdst = -1;
2289       _date = mktime (t);
2290       return true;
2291     }
2292   }
2293
2294   pig.restoreTo (checkpoint);
2295   return false;
2296 }
2297
2298 ////////////////////////////////////////////////////////////////////////////////
2299 // sopq [ !<alpha> && !<digit> ]
2300 bool Datetime::initializeSopq (Pig& pig)
2301 {
2302   auto checkpoint = pig.cursor ();
2303
2304   if (pig.skipLiteral ("sopq"))
2305   {
2306     auto following = pig.peek ();
2307     if (! unicodeLatinAlpha (following) &&
2308         ! unicodeLatinDigit (following))
2309     {
2310       time_t now = time (nullptr);
2311       struct tm* t = localtime (&now);
2312
2313       t->tm_mon -= t->tm_mon % 3;
2314       t->tm_mon -= 3;
2315       if (t->tm_mon < 0)
2316       {
2317         t->tm_mon += 12;
2318         t->tm_year--;
2319       }
2320
2321       t->tm_hour = t->tm_min = t->tm_sec = 0;
2322       t->tm_mday = 1;
2323       t->tm_isdst = -1;
2324       _date = mktime (t);
2325       return true;
2326     }
2327   }
2328
2329   pig.restoreTo (checkpoint);
2330   return false;
2331 }
2332
2333 ////////////////////////////////////////////////////////////////////////////////
2334 // soq [ !<alpha> && !<digit> ]
2335 bool Datetime::initializeSoq (Pig& pig)
2336 {
2337   auto checkpoint = pig.cursor ();
2338
2339   if (pig.skipLiteral ("soq"))
2340   {
2341     auto following = pig.peek ();
2342     if (! unicodeLatinAlpha (following) &&
2343         ! unicodeLatinDigit (following))
2344     {
2345       time_t now = time (nullptr);
2346       struct tm* t = localtime (&now);
2347
2348       t->tm_hour = t->tm_min = t->tm_sec = 0;
2349       t->tm_mon -= t->tm_mon % 3;
2350       t->tm_mday = 1;
2351       t->tm_isdst = -1;
2352       _date = mktime (t);
2353       return true;
2354     }
2355   }
2356
2357   pig.restoreTo (checkpoint);
2358   return false;
2359 }
2360
2361 ////////////////////////////////////////////////////////////////////////////////
2362 // sonq [ !<alpha> && !<digit> ]
2363 bool Datetime::initializeSonq (Pig& pig)
2364 {
2365   auto checkpoint = pig.cursor ();
2366
2367   if (pig.skipLiteral ("sonq"))
2368   {
2369     auto following = pig.peek ();
2370     if (! unicodeLatinAlpha (following) &&
2371         ! unicodeLatinDigit (following))
2372     {
2373       time_t now = time (nullptr);
2374       struct tm* t = localtime (&now);
2375
2376       t->tm_mon += 3 - (t->tm_mon % 3);
2377       if (t->tm_mon > 11)
2378       {
2379         t->tm_mon -= 12;
2380         ++t->tm_year;
2381       }
2382
2383       t->tm_hour = t->tm_min = t->tm_sec = 0;
2384       t->tm_mday = 1;
2385       t->tm_isdst = -1;
2386       _date = mktime (t);
2387       return true;
2388     }
2389   }
2390
2391   pig.restoreTo (checkpoint);
2392   return false;
2393 }
2394
2395 ////////////////////////////////////////////////////////////////////////////////
2396 // eopq [ !<alpha> && !<digit> ]
2397 bool Datetime::initializeEopq (Pig& pig)
2398 {
2399   auto checkpoint = pig.cursor ();
2400
2401   if (pig.skipLiteral ("eopq"))
2402   {
2403     auto following = pig.peek ();
2404     if (! unicodeLatinAlpha (following) &&
2405         ! unicodeLatinDigit (following))
2406     {
2407       time_t now = time (nullptr);
2408       struct tm* t = localtime (&now);
2409
2410       t->tm_hour = t->tm_min = t->tm_sec = 0;
2411       t->tm_mon -= t->tm_mon % 3;
2412       t->tm_mday = 1;
2413       t->tm_isdst = -1;
2414       _date = mktime (t);
2415       return true;
2416     }
2417   }
2418
2419   pig.restoreTo (checkpoint);
2420   return false;
2421 }
2422
2423 ////////////////////////////////////////////////////////////////////////////////
2424 // eoq [ !<alpha> && !<digit> ]
2425 bool Datetime::initializeEoq (Pig& pig)
2426 {
2427   auto checkpoint = pig.cursor ();
2428
2429   if (pig.skipLiteral ("eoq"))
2430   {
2431     auto following = pig.peek ();
2432     if (! unicodeLatinAlpha (following) &&
2433         ! unicodeLatinDigit (following))
2434     {
2435       time_t now = time (nullptr);
2436       struct tm* t = localtime (&now);
2437
2438       t->tm_mon += 3 - (t->tm_mon % 3);
2439       if (t->tm_mon > 11)
2440       {
2441         t->tm_mon -= 12;
2442         ++t->tm_year;
2443       }
2444
2445       t->tm_hour = t->tm_min = t->tm_sec = 0;
2446       t->tm_mday = 1;
2447       t->tm_isdst = -1;
2448       _date = mktime (t);
2449       return true;
2450     }
2451   }
2452
2453   pig.restoreTo (checkpoint);
2454   return false;
2455 }
2456
2457 ////////////////////////////////////////////////////////////////////////////////
2458 // eonq [ !<alpha> && !<digit> ]
2459 bool Datetime::initializeEonq (Pig& pig)
2460 {
2461   auto checkpoint = pig.cursor ();
2462
2463   if (pig.skipLiteral ("eonq"))
2464   {
2465     auto following = pig.peek ();
2466     if (! unicodeLatinAlpha (following) &&
2467         ! unicodeLatinDigit (following))
2468     {
2469       time_t now = time (nullptr);
2470       struct tm* t = localtime (&now);
2471
2472       t->tm_hour = t->tm_min = t->tm_sec = 0;
2473       t->tm_mon += 6 - (t->tm_mon % 3);
2474       if (t->tm_mon > 11)
2475       {
2476         t->tm_mon -= 12;
2477         ++t->tm_year;
2478       }
2479
2480       t->tm_mday = 1;
2481       t->tm_isdst = -1;
2482       _date = mktime (t);
2483       return true;
2484     }
2485   }
2486
2487   pig.restoreTo (checkpoint);
2488   return false;
2489 }
2490
2491 ////////////////////////////////////////////////////////////////////////////////
2492 // sopy [ !<alpha> && !<digit> ]
2493 bool Datetime::initializeSopy (Pig& pig)
2494 {
2495   auto checkpoint = pig.cursor ();
2496
2497   if (pig.skipLiteral ("sopy"))
2498   {
2499     auto following = pig.peek ();
2500     if (! unicodeLatinAlpha (following) &&
2501         ! unicodeLatinDigit (following))
2502     {
2503       time_t now = time (nullptr);
2504       struct tm* t = localtime (&now);
2505
2506       t->tm_hour = t->tm_min = t->tm_sec = 0;
2507       t->tm_mon = 0;
2508       t->tm_mday = 1;
2509       t->tm_year--;
2510       t->tm_isdst = -1;
2511       _date = mktime (t);
2512       return true;
2513     }
2514   }
2515
2516   pig.restoreTo (checkpoint);
2517   return false;
2518 }
2519
2520 ////////////////////////////////////////////////////////////////////////////////
2521 // soy [ !<alpha> && !<digit> ]
2522 bool Datetime::initializeSoy (Pig& pig)
2523 {
2524   auto checkpoint = pig.cursor ();
2525
2526   if (pig.skipLiteral ("soy"))
2527   {
2528     auto following = pig.peek ();
2529     if (! unicodeLatinAlpha (following) &&
2530         ! unicodeLatinDigit (following))
2531     {
2532       time_t now = time (nullptr);
2533       struct tm* t = localtime (&now);
2534
2535       t->tm_hour = t->tm_min = t->tm_sec = 0;
2536       t->tm_mon = 0;
2537       t->tm_mday = 1;
2538       t->tm_isdst = -1;
2539       _date = mktime (t);
2540       return true;
2541     }
2542   }
2543
2544   pig.restoreTo (checkpoint);
2545   return false;
2546 }
2547
2548 ////////////////////////////////////////////////////////////////////////////////
2549 // sony [ !<alpha> && !<digit> ]
2550 bool Datetime::initializeSony (Pig& pig)
2551 {
2552   auto checkpoint = pig.cursor ();
2553
2554   if (pig.skipLiteral ("sony"))
2555   {
2556     auto following = pig.peek ();
2557     if (! unicodeLatinAlpha (following) &&
2558         ! unicodeLatinDigit (following))
2559     {
2560       time_t now = time (nullptr);
2561       struct tm* t = localtime (&now);
2562
2563       t->tm_hour = t->tm_min = t->tm_sec = 0;
2564       t->tm_mon = 0;
2565       t->tm_mday = 1;
2566       t->tm_year++;
2567       t->tm_isdst = -1;
2568       _date = mktime (t);
2569       return true;
2570     }
2571   }
2572
2573   pig.restoreTo (checkpoint);
2574   return false;
2575 }
2576
2577 ////////////////////////////////////////////////////////////////////////////////
2578 // eopy [ !<alpha> && !<digit> ]
2579 bool Datetime::initializeEopy (Pig& pig)
2580 {
2581   auto checkpoint = pig.cursor ();
2582
2583   if (pig.skipLiteral ("eopy"))
2584   {
2585     auto following = pig.peek ();
2586     if (! unicodeLatinAlpha (following) &&
2587         ! unicodeLatinDigit (following))
2588     {
2589       time_t now = time (nullptr);
2590       struct tm* t = localtime (&now);
2591
2592       t->tm_hour = t->tm_min = t->tm_sec = 0;
2593       t->tm_mon = 0;
2594       t->tm_mday = 1;
2595       t->tm_isdst = -1;
2596       _date = mktime (t);
2597       return true;
2598     }
2599   }
2600
2601   pig.restoreTo (checkpoint);
2602   return false;
2603 }
2604
2605 ////////////////////////////////////////////////////////////////////////////////
2606 // eoy [ !<alpha> && !<digit> ]
2607 bool Datetime::initializeEoy (Pig& pig)
2608 {
2609   auto checkpoint = pig.cursor ();
2610
2611   if (pig.skipLiteral ("eoy"))
2612   {
2613     auto following = pig.peek ();
2614     if (! unicodeLatinAlpha (following) &&
2615         ! unicodeLatinDigit (following))
2616     {
2617       time_t now = time (nullptr);
2618       struct tm* t = localtime (&now);
2619
2620       t->tm_hour = t->tm_min = t->tm_sec = 0;
2621       t->tm_mon = 0;
2622       t->tm_mday = 1;
2623       t->tm_year++;
2624       t->tm_isdst = -1;
2625       _date = mktime (t);
2626       return true;
2627     }
2628   }
2629
2630   pig.restoreTo (checkpoint);
2631   return false;
2632 }
2633
2634 ////////////////////////////////////////////////////////////////////////////////
2635 // eony [ !<alpha> && !<digit> ]
2636 bool Datetime::initializeEony (Pig& pig)
2637 {
2638   auto checkpoint = pig.cursor ();
2639
2640   if (pig.skipLiteral ("eony"))
2641   {
2642     auto following = pig.peek ();
2643     if (! unicodeLatinAlpha (following) &&
2644         ! unicodeLatinDigit (following))
2645     {
2646       time_t now = time (nullptr);
2647       struct tm* t = localtime (&now);
2648
2649       t->tm_hour = t->tm_min = t->tm_sec = 0;
2650       t->tm_mon = 0;
2651       t->tm_mday = 1;
2652       t->tm_year += 2;
2653       t->tm_isdst = -1;
2654       _date = mktime (t);
2655       return true;
2656     }
2657   }
2658
2659   pig.restoreTo (checkpoint);
2660   return false;
2661 }
2662
2663 ////////////////////////////////////////////////////////////////////////////////
2664 // easter       [ !<alpha> && !<digit> ]
2665 // eastermonday [ !<alpha> && !<digit> ]
2666 // ascension    [ !<alpha> && !<digit> ]
2667 // pentecost    [ !<alpha> && !<digit> ]
2668 // goodfriday   [ !<alpha> && !<digit> ]
2669 bool Datetime::initializeEaster (Pig& pig)
2670 {
2671   auto checkpoint = pig.cursor ();
2672
2673   std::vector <std::string> holidays = {"eastermonday", "easter", "ascension", "pentecost", "goodfriday"};
2674   std::vector <int>         offsets  = {             1,        0,          39,          49,           -2};
2675
2676   std::string token;
2677   for (int holiday = 0; holiday < 5; ++holiday)
2678   {
2679    if (pig.skipLiteral (holidays[holiday]) &&
2680        ! unicodeLatinAlpha (pig.peek ()) &&
2681        ! unicodeLatinDigit (pig.peek ()))
2682     {
2683       time_t now = time (nullptr);
2684       struct tm* t = localtime (&now);
2685
2686       easter (t);
2687       _date = mktime (t);
2688
2689       // If the result is earlier this year, then recalc for next year.
2690       if (_date < now)
2691       {
2692         t = localtime (&now);
2693         t->tm_year++;
2694         easter (t);
2695       }
2696
2697       // Adjust according to holiday-specific offsets.
2698       t->tm_mday += offsets[holiday];
2699
2700       _date = mktime (t);
2701       return true;
2702     }
2703   }
2704
2705   pig.restoreTo (checkpoint);
2706   return false;
2707 }
2708
2709 ////////////////////////////////////////////////////////////////////////////////
2710 // midsommar [ !<alpha> && !<digit> ]
2711 bool Datetime::initializeMidsommar (Pig& pig)
2712 {
2713   auto checkpoint = pig.cursor ();
2714
2715   if (pig.skipLiteral ("midsommar"))
2716   {
2717     auto following = pig.peek ();
2718     if (! unicodeLatinAlpha (following) &&
2719         ! unicodeLatinDigit (following))
2720     {
2721       time_t now = time (nullptr);
2722       struct tm* t = localtime (&now);
2723       midsommar (t);
2724       _date = mktime (t);
2725
2726       // If the result is earlier this year, then recalc for next year.
2727       if (_date < now)
2728       {
2729         t = localtime (&now);
2730         t->tm_year++;
2731         midsommar (t);
2732       }
2733
2734       _date = mktime (t);
2735       return true;
2736     }
2737   }
2738
2739   pig.restoreTo (checkpoint);
2740   return false;
2741 }
2742
2743 ////////////////////////////////////////////////////////////////////////////////
2744 // midsommarafton [ !<alpha> && !<digit> ]
2745 // juhannus [ !<alpha> && !<digit> ]
2746 bool Datetime::initializeMidsommarafton (Pig& pig)
2747 {
2748   auto checkpoint = pig.cursor ();
2749
2750   if (pig.skipLiteral ("midsommarafton") ||
2751       pig.skipLiteral ("juhannus"))
2752   {
2753     auto following = pig.peek ();
2754     if (! unicodeLatinAlpha (following) &&
2755         ! unicodeLatinDigit (following))
2756     {
2757       time_t now = time (nullptr);
2758       struct tm* t = localtime (&now);
2759       midsommarafton (t);
2760       _date = mktime (t);
2761
2762       // If the result is earlier this year, then recalc for next year.
2763       if (_date < now)
2764       {
2765         t = localtime (&now);
2766         t->tm_year++;
2767         midsommarafton (t);
2768       }
2769
2770       _date = mktime (t);
2771       return true;
2772     }
2773   }
2774
2775   pig.restoreTo (checkpoint);
2776   return false;
2777 }
2778
2779 ////////////////////////////////////////////////////////////////////////////////
2780 // 8am
2781 // 8a
2782 // 8:30am
2783 // 8:30a
2784 // 8:30
2785 //
2786 // \d+ [ : \d{2} ] [ am | a | pm | p ] [ !<alpha> && !<digit> && !: && !+ && !- ]
2787 //
2788 bool Datetime::initializeInformalTime (Pig& pig)
2789 {
2790   auto checkpoint = pig.cursor ();
2791
2792   int digit = 0;
2793   bool needDesignator = true;   // Require am/pm.
2794   bool haveDesignator = false;  // Provided am/pm.
2795   if (pig.getDigit (digit))
2796   {
2797     int hours = digit;
2798     if (pig.getDigit (digit))
2799       hours = 10 * hours + digit;
2800
2801     int minutes = 0;
2802     int seconds = 0;
2803     if (pig.skip (':'))
2804     {
2805       if (! pig.getDigit2 (minutes))
2806       {
2807         pig.restoreTo (checkpoint);
2808         return false;
2809       }
2810
2811       if (pig.skip (':'))
2812       {
2813         if (! pig.getDigits (seconds))
2814         {
2815           pig.restoreTo (checkpoint);
2816           return false;
2817         }
2818       }
2819
2820       needDesignator = false;
2821     }
2822
2823     if (pig.skipLiteral ("am") ||
2824         pig.skipLiteral ("a"))
2825     {
2826       haveDesignator = true;
2827       if (hours == 12)
2828         hours = 0;
2829     }
2830
2831     else if (pig.skipLiteral ("pm") ||
2832              pig.skipLiteral ("p"))
2833     {
2834       // Note: '12pm is an exception:
2835       //  12am = 0h
2836       //  11am = 11h + 12h
2837       //  12pm = 12h
2838       //  1pm  = 1h + 12h
2839       if (hours != 12)
2840         hours += 12;
2841
2842       haveDesignator = true;
2843     }
2844
2845     // Informal time needs to be terminated.
2846     auto following = pig.peek ();
2847     if (unicodeLatinAlpha (following) ||
2848         unicodeLatinDigit (following) ||
2849         following == ':'              ||
2850         following == '-'              ||
2851         following == '+')
2852     {
2853       pig.restoreTo (checkpoint);
2854       return false;
2855     }
2856
2857     if (haveDesignator || ! needDesignator)
2858     {
2859       // Midnight today + hours:minutes:seconds.
2860       time_t now = time (nullptr);
2861       struct tm* t = localtime (&now);
2862
2863       int now_seconds  = (t->tm_hour * 3600) + (t->tm_min * 60) + t->tm_sec;
2864       int calc_seconds = (hours      * 3600) + (minutes   * 60) + seconds;
2865
2866       if (calc_seconds < now_seconds)
2867         ++t->tm_mday;
2868
2869       // Basic validation.
2870       if (hours   >= 0 && hours   < 24 &&
2871           minutes >= 0 && minutes < 60 &&
2872           seconds >= 0 && seconds < 60)
2873       {
2874         t->tm_hour = hours;
2875         t->tm_min = minutes;
2876         t->tm_sec = seconds;
2877         t->tm_isdst = -1;
2878         _date = mktime (t);
2879
2880         return true;
2881       }
2882     }
2883   }
2884
2885   pig.restoreTo (checkpoint);
2886   return false;
2887 }
2888
2889 ////////////////////////////////////////////////////////////////////////////////
2890 void Datetime::easter (struct tm* t) const
2891 {
2892   int Y = t->tm_year + 1900;
2893   int a = Y % 19;
2894   int b = Y / 100;
2895   int c = Y % 100;
2896   int d = b / 4;
2897   int e = b % 4;
2898   int f = (b + 8) / 25;
2899   int g = (b - f + 1) / 3;
2900   int h = (19 * a + b - d - g + 15) % 30;
2901   int i = c / 4;
2902   int k = c % 4;
2903   int L = (32 + 2 * e + 2 * i - h - k) % 7;
2904   int m = (a + 11 * h + 22 * L) / 451;
2905   int month = (h + L - 7 * m + 114) / 31;
2906   int day = ((h + L - 7 * m + 114) % 31) + 1;
2907
2908   t->tm_isdst = -1;   // Requests that mktime determine summer time effect.
2909   t->tm_mday  = day;
2910   t->tm_mon   = month - 1;
2911   t->tm_year  = Y - 1900;
2912   t->tm_isdst = -1;
2913   t->tm_hour = t->tm_min = t->tm_sec = 0;
2914 }
2915
2916 ////////////////////////////////////////////////////////////////////////////////
2917 void Datetime::midsommar (struct tm* t) const
2918 {
2919   t->tm_mon = 5;                          // June.
2920   t->tm_mday = 20;                        // Saturday after 20th.
2921   t->tm_hour = t->tm_min = t->tm_sec = 0; // Midnight.
2922   t->tm_isdst = -1;                       // Probably DST, but check.
2923
2924   time_t then = mktime (t);               // Obtain the weekday of June 20th.
2925   struct tm* mid = localtime (&then);
2926   t->tm_mday += 6 - mid->tm_wday;         // How many days after 20th.
2927 }
2928
2929 ////////////////////////////////////////////////////////////////////////////////
2930 void Datetime::midsommarafton (struct tm* t) const
2931 {
2932   t->tm_mon = 5;                          // June.
2933   t->tm_mday = 19;                        // Saturday after 20th.
2934   t->tm_hour = t->tm_min = t->tm_sec = 0; // Midnight.
2935   t->tm_isdst = -1;                       // Probably DST, but check.
2936
2937   time_t then = mktime (t);               // Obtain the weekday of June 19th.
2938   struct tm* mid = localtime (&then);
2939   t->tm_mday += 5 - mid->tm_wday;         // How many days after 19th.
2940 }
2941
2942 ////////////////////////////////////////////////////////////////////////////////
2943 // Suggested date expressions:
2944 //   {ordinal} {day} in|of {month}
2945 //   last|past|next|this {day}
2946 //   last|past|next|this {month}
2947 //   last|past|next|this week
2948 //   last|past|next|this month
2949 //   last|past|next|this weekend
2950 //   last|past|next|this year
2951 //   {day} last|past|next|this week
2952 //   {day} [at] {time}
2953 //   {time} {day}
2954 //
2955 // Candidates:
2956 //   <dayname> <time>
2957 //   <time>
2958 //   tue 9am
2959 //   Friday before easter
2960 //   3 days before eom
2961 //   in the morning
2962 //   am|pm
2963 //   4pm
2964 //   noon
2965 //   midnight
2966 //   tomorrow in one year
2967 //   in two weeks
2968 //   2 weeks from now
2969 //   2 weeks ago tuesday
2970 //   thursday in 2 weeks
2971 //   last day next month
2972 //   10 days from today
2973 //   thursday before last weekend in may
2974 //   friday last full week in may
2975 //   3rd wednesday this month
2976 //   3 weeks after 2nd tuesday next month
2977 //   100 days from the beginning of the month
2978 //   10 days after last monday
2979 //   sunday in the evening
2980 //   in 6 hours
2981 //   6 in the morning
2982 //   kl 18
2983 //   feb 11
2984 //   11 feb
2985 //   2011-02-08
2986 //   11/19/2011
2987 //   next business day
2988 //   new moon
2989 //   full moon
2990 //   in 28 days
2991 //   3rd quarter
2992 //   week 23
2993 //   {number} {unit}
2994 //   - {number} {unit}
2995 //   {ordinal} {unit} in {larger-unit}
2996 //   end of day tomorrow
2997 //   end of {day}
2998 //   by {day}
2999 //   first thing {day}
3000 //
3001
3002 ////////////////////////////////////////////////////////////////////////////////
3003 // <ordinal> <weekday> in|of <month>
3004 bool Datetime::initializeNthDayInMonth (const std::vector <std::string>& tokens)
3005 {
3006   if (tokens.size () == 4)
3007   {
3008     int ordinal {0};
3009     if (isOrdinal (tokens[0], ordinal))
3010     {
3011       auto day = Datetime::dayOfWeek (tokens[1]);
3012       if (day != -1)
3013       {
3014         if (tokens[2] == "in" ||
3015             tokens[2] == "of")
3016         {
3017           auto month = Datetime::monthOfYear (tokens[3]);
3018           if (month != -1)
3019           {
3020             std::cout << "# ordinal=" << ordinal << " day=" << day << " in month=" << month << '\n';
3021
3022             // TODO Assume 1st of the month
3023             // TODO Assume current year
3024             // TODO Determine the day
3025             // TODO Project forwards/backwards, to the desired day
3026             // TODO Add ((ordinal - 1) * 7) days
3027
3028             return true;
3029           }
3030         }
3031       }
3032     }
3033   }
3034
3035   return false;
3036 }
3037
3038 ////////////////////////////////////////////////////////////////////////////////
3039 bool Datetime::isOrdinal (const std::string& token, int& ordinal)
3040 {
3041   Pig p (token);
3042   int number;
3043   std::string suffix;
3044   if (p.getDigits (number) &&
3045       p.getRemainder (suffix))
3046   {
3047     if (((number >= 11 || number <= 13) && suffix == "th") ||
3048         (number % 10 == 1               && suffix == "st") ||
3049         (number % 10 == 2               && suffix == "nd") ||
3050         (number % 10 == 3               && suffix == "rd") ||
3051         (                                  suffix == "th"))
3052     {
3053       ordinal = number;
3054       return true;
3055     }
3056   }
3057
3058   return false;
3059 }
3060
3061 ////////////////////////////////////////////////////////////////////////////////
3062 // Validation via simple range checking.
3063 bool Datetime::validate ()
3064 {
3065   // _year;
3066   if ((_year    && (_year    <   1900 || _year    >                                  2200)) ||
3067       (_month   && (_month   <      1 || _month   >                                    12)) ||
3068       (_week    && (_week    <      1 || _week    >                                    53)) ||
3069       (_weekday && (_weekday <      0 || _weekday >                                     6)) ||
3070       (_julian  && (_julian  <      1 || _julian  >          Datetime::daysInYear (_year))) ||
3071       (_day     && (_day     <      1 || _day     > Datetime::daysInMonth (_year, _month))) ||
3072       (_seconds && (_seconds <      1 || _seconds >                                 86400)) ||
3073       (_offset  && (_offset  < -86400 || _offset  >                                 86400)))
3074     return false;
3075
3076   return true;
3077 }
3078
3079 ////////////////////////////////////////////////////////////////////////////////
3080 // int tm_sec;       seconds (0 - 60)
3081 // int tm_min;       minutes (0 - 59)
3082 // int tm_hour;      hours (0 - 23)
3083 // int tm_mday;      day of month (1 - 31)
3084 // int tm_mon;       month of year (0 - 11)
3085 // int tm_year;      year - 1900
3086 // int tm_wday;      day of week (Sunday = 0)
3087 // int tm_yday;      day of year (0 - 365)
3088 // int tm_isdst;     is summer time in effect?
3089 // char *tm_zone;    abbreviation of timezone name
3090 // long tm_gmtoff;   offset from UTC in seconds
3091 void Datetime::resolve ()
3092 {
3093   // Don't touch the original values.
3094   int year    = _year;
3095   int month   = _month;
3096   int week    = _week;
3097   int weekday = _weekday;
3098   int julian  = _julian;
3099   int day     = _day;
3100   int seconds = _seconds;
3101   int offset  = _offset;
3102   bool utc    = _utc;
3103
3104   // Get current time.
3105   time_t now = time (nullptr);
3106
3107   // A UTC offset needs to be accommodated.  Once the offset is subtracted,
3108   // only local and UTC times remain.
3109   if (offset)
3110   {
3111     seconds -= offset;
3112     now -= offset;
3113     utc = true;
3114   }
3115
3116   // Get 'now' in the relevant location.
3117   struct tm* t_now = utc ? gmtime (&now) : localtime (&now);
3118
3119   int seconds_now = (t_now->tm_hour * 3600) +
3120                     (t_now->tm_min  *   60) +
3121                      t_now->tm_sec;
3122
3123   // Project forward one day if the specified seconds are earlier in the day
3124   // than the current seconds.
3125   // TODO This does not cover the inverse case of subtracting 86400.
3126   if (year    == 0           &&
3127       month   == 0           &&
3128       day     == 0           &&
3129       week    == 0           &&
3130       weekday == 0           &&
3131       seconds < seconds_now)
3132   {
3133     seconds += 86400;
3134   }
3135
3136   // Convert week + weekday --> julian.
3137   if (week)
3138   {
3139     julian = (week * 7) + weekday - dayOfWeek (year, 1, 4) - 3;
3140   }
3141
3142   // Provide default values for year, month, day.
3143   else
3144   {
3145     // Default values for year, month, day:
3146     //
3147     // y   m   d  -->  y   m   d
3148     // y   m   -  -->  y   m   1
3149     // y   -   -  -->  y   1   1
3150     // -   -   -  -->  now now now
3151     //
3152     if (year == 0)
3153     {
3154       year  = t_now->tm_year + 1900;
3155       month = t_now->tm_mon + 1;
3156       day   = t_now->tm_mday;
3157     }
3158     else
3159     {
3160       if (month == 0)
3161       {
3162         month = 1;
3163         day   = 1;
3164       }
3165       else if (day == 0)
3166         day = 1;
3167     }
3168   }
3169
3170   if (julian)
3171   {
3172     month = 1;
3173     day = julian;
3174   }
3175
3176   struct tm t {};
3177   t.tm_isdst = -1;  // Requests that mktime/gmtime determine summer time effect.
3178   t.tm_year = year - 1900;
3179   t.tm_mon = month - 1;
3180   t.tm_mday = day;
3181
3182   if (seconds > 86400)
3183   {
3184     int days = seconds / 86400;
3185     t.tm_mday += days;
3186     seconds %= 86400;
3187   }
3188
3189   t.tm_hour = seconds / 3600;
3190   t.tm_min = (seconds % 3600) / 60;
3191   t.tm_sec = seconds % 60;
3192
3193   _date = utc ? timegm (&t) : mktime (&t);
3194 }
3195
3196 ////////////////////////////////////////////////////////////////////////////////
3197 time_t Datetime::toEpoch () const
3198 {
3199   return _date;
3200 }
3201
3202 ////////////////////////////////////////////////////////////////////////////////
3203 std::string Datetime::toEpochString () const
3204 {
3205   return format ("{1}", _date);
3206 }
3207
3208 ////////////////////////////////////////////////////////////////////////////////
3209 // 19980119T070000Z =  YYYYMMDDThhmmssZ
3210 std::string Datetime::toISO () const
3211 {
3212   struct tm* t = gmtime (&_date);
3213
3214   std::stringstream iso;
3215   iso << std::setw (4) << std::setfill ('0') << t->tm_year + 1900
3216       << std::setw (2) << std::setfill ('0') << t->tm_mon + 1
3217       << std::setw (2) << std::setfill ('0') << t->tm_mday
3218       << 'T'
3219       << std::setw (2) << std::setfill ('0') << t->tm_hour
3220       << std::setw (2) << std::setfill ('0') << t->tm_min
3221       << std::setw (2) << std::setfill ('0') << t->tm_sec
3222       << 'Z';
3223
3224   return iso.str ();
3225 }
3226
3227 ////////////////////////////////////////////////////////////////////////////////
3228 // 1998-01-19T07:00:00 =  YYYY-MM-DDThh:mm:ss
3229 std::string Datetime::toISOLocalExtended () const
3230 {
3231   struct tm* t = localtime (&_date);
3232
3233   std::stringstream iso;
3234   iso << std::setw (4) << std::setfill ('0') << t->tm_year + 1900
3235       << '-'
3236       << std::setw (2) << std::setfill ('0') << t->tm_mon + 1
3237       << '-'
3238       << std::setw (2) << std::setfill ('0') << t->tm_mday
3239       << 'T'
3240       << std::setw (2) << std::setfill ('0') << t->tm_hour
3241       << ':'
3242       << std::setw (2) << std::setfill ('0') << t->tm_min
3243       << ':'
3244       << std::setw (2) << std::setfill ('0') << t->tm_sec;
3245
3246   return iso.str ();
3247 }
3248
3249 ////////////////////////////////////////////////////////////////////////////////
3250 double Datetime::toJulian () const
3251 {
3252   return (_date / 86400.0) + 2440587.5;
3253 }
3254
3255 ////////////////////////////////////////////////////////////////////////////////
3256 void Datetime::toYMD (int& y, int& m, int& d) const
3257 {
3258   struct tm* t = localtime (&_date);
3259
3260   m = t->tm_mon + 1;
3261   d = t->tm_mday;
3262   y = t->tm_year + 1900;
3263 }
3264
3265 ////////////////////////////////////////////////////////////////////////////////
3266 const std::string Datetime::toString (const std::string& format) const
3267 {
3268   std::stringstream formatted;
3269   for (unsigned int i = 0; i < format.length (); ++i)
3270   {
3271     int c = format[i];
3272     switch (c)
3273     {
3274     case 'm': formatted                                        << month ();               break;
3275     case 'M': formatted << std::setw (2) << std::setfill ('0') << month ();               break;
3276     case 'd': formatted                                        << day ();                 break;
3277     case 'D': formatted << std::setw (2) << std::setfill ('0') << day ();                 break;
3278     case 'y': formatted << std::setw (2) << std::setfill ('0') << (year () % 100);        break;
3279     case 'Y': formatted                                        << year ();                break;
3280     case 'a': formatted                                        << Datetime::dayNameShort (dayOfWeek ()); break;
3281     case 'A': formatted                                        << Datetime::dayName (dayOfWeek ());      break;
3282     case 'b': formatted                                        << Datetime::monthNameShort (month ());   break;
3283     case 'B': formatted                                        << Datetime::monthName (month ());        break;
3284     case 'v': formatted                                        << week ();                break;
3285     case 'V': formatted << std::setw (2) << std::setfill ('0') << week ();                break;
3286     case 'h': formatted                                        << hour ();                break;
3287     case 'H': formatted << std::setw (2) << std::setfill ('0') << hour ();                break;
3288     case 'n': formatted                                        << minute ();              break;
3289     case 'N': formatted << std::setw (2) << std::setfill ('0') << minute ();              break;
3290     case 's': formatted                                        << second ();              break;
3291     case 'S': formatted << std::setw (2) << std::setfill ('0') << second ();              break;
3292     case 'j': formatted                                        << dayOfYear ();           break;
3293     case 'J': formatted << std::setw (3) << std::setfill ('0') << dayOfYear ();           break;
3294     case 'w': formatted                                        << dayOfWeek ();           break;
3295     default:  formatted                                        << static_cast <char> (c); break;
3296     }
3297   }
3298
3299   return formatted.str ();
3300 }
3301
3302 ////////////////////////////////////////////////////////////////////////////////
3303 Datetime Datetime::startOfDay () const
3304 {
3305   return Datetime (year (), month (), day ());
3306 }
3307
3308 ////////////////////////////////////////////////////////////////////////////////
3309 Datetime Datetime::startOfWeek () const
3310 {
3311   Datetime sow (_date);
3312   sow -= (dayOfWeek () * 86400);
3313   return Datetime (sow.year (), sow.month (), sow.day ());
3314 }
3315
3316 ////////////////////////////////////////////////////////////////////////////////
3317 Datetime Datetime::startOfMonth () const
3318 {
3319   return Datetime (year (), month (), 1);
3320 }
3321
3322 ////////////////////////////////////////////////////////////////////////////////
3323 Datetime Datetime::startOfYear () const
3324 {
3325   return Datetime (year (), 1, 1);
3326 }
3327
3328 ////////////////////////////////////////////////////////////////////////////////
3329 bool Datetime::valid (const std::string& input, const std::string& format)
3330 {
3331   try
3332   {
3333     Datetime test (input, format);
3334   }
3335
3336   catch (...)
3337   {
3338     return false;
3339   }
3340
3341   return true;
3342 }
3343
3344 ////////////////////////////////////////////////////////////////////////////////
3345 bool Datetime::valid (
3346   const int y, const int m, const int d,
3347   const int hr, const int mi, const int se)
3348 {
3349   if (hr < 0 || hr > 24)
3350     return false;
3351
3352   if (mi < 0 || mi > 59)
3353     return false;
3354
3355   if (se < 0 || se > 59)
3356     return false;
3357
3358   if (hr == 24 &&
3359       (mi != 0 ||
3360        se != 0))
3361     return false;
3362
3363   return Datetime::valid (y, m, d);
3364 }
3365
3366 ////////////////////////////////////////////////////////////////////////////////
3367 bool Datetime::valid (const int y, const int m, const int d)
3368 {
3369   // Check that the year is valid.
3370   if (y < 0)
3371     return false;
3372
3373   // Check that the month is valid.
3374   if (m < 1 || m > 12)
3375     return false;
3376
3377   // Finally check that the days fall within the acceptable range for this
3378   // month, and whether or not this is a leap year.
3379   if (d < 1 || d > Datetime::daysInMonth (y, m))
3380     return false;
3381
3382   return true;
3383 }
3384
3385 ////////////////////////////////////////////////////////////////////////////////
3386 // Julian
3387 bool Datetime::valid (const int y, const int d)
3388 {
3389   // Check that the year is valid.
3390   if (y < 0)
3391     return false;
3392
3393   if (d < 1 || d > Datetime::daysInYear (y))
3394     return false;
3395
3396   return true;
3397 }
3398
3399 ////////////////////////////////////////////////////////////////////////////////
3400 // Static
3401 bool Datetime::leapYear (int year)
3402 {
3403   return ((! (year % 4)) && (year % 100)) ||
3404          ! (year % 400);
3405 }
3406
3407 ////////////////////////////////////////////////////////////////////////////////
3408 // Static
3409 int Datetime::daysInMonth (int year, int month)
3410 {
3411   // Protect against arguments being passed in the wrong order.
3412   assert (year >= 1969 && year < 2100);
3413   assert (month >= 1 && month <= 31);
3414
3415   static int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
3416
3417   if (month == 2 && Datetime::leapYear (year))
3418     return 29;
3419
3420   return days[month - 1];
3421 }
3422
3423 ////////////////////////////////////////////////////////////////////////////////
3424 // Static
3425 int Datetime::daysInYear (int year)
3426 {
3427   return Datetime::leapYear (year) ? 366 : 365;
3428 }
3429
3430 ////////////////////////////////////////////////////////////////////////////////
3431 // Static
3432 std::string Datetime::monthName (int month)
3433 {
3434   assert (month > 0);
3435   assert (month <= 12);
3436   return upperCaseFirst (monthNames[month - 1]);
3437 }
3438
3439 ////////////////////////////////////////////////////////////////////////////////
3440 // Static
3441 std::string Datetime::monthNameShort (int month)
3442 {
3443   assert (month > 0);
3444   assert (month <= 12);
3445   return upperCaseFirst (monthNames[month - 1]).substr (0, 3);
3446 }
3447
3448 ////////////////////////////////////////////////////////////////////////////////
3449 // Static
3450 std::string Datetime::dayName (int dow)
3451 {
3452   assert (dow >= 0);
3453   assert (dow <= 6);
3454   return upperCaseFirst (dayNames[dow]);
3455 }
3456
3457 ////////////////////////////////////////////////////////////////////////////////
3458 // Static
3459 std::string Datetime::dayNameShort (int dow)
3460 {
3461   assert (dow >= 0);
3462   assert (dow <= 6);
3463   return upperCaseFirst (dayNames[dow]).substr (0, 3);
3464 }
3465
3466 ////////////////////////////////////////////////////////////////////////////////
3467 // Static
3468 int Datetime::dayOfWeek (const std::string& input)
3469 {
3470   if (Datetime::minimumMatchLength== 0)
3471     Datetime::minimumMatchLength = 3;
3472
3473   for (unsigned int i = 0; i < dayNames.size (); ++i)
3474     if (closeEnough (dayNames[i], input, Datetime::minimumMatchLength))
3475        return i;
3476
3477   return -1;
3478 }
3479
3480 ////////////////////////////////////////////////////////////////////////////////
3481 // Using Zeller's Congruence.
3482 // Static
3483 int Datetime::dayOfWeek (int year, int month, int day)
3484 {
3485   int adj = (14 - month) / 12;
3486   int m = month + 12 * adj - 2;
3487   int y = year - adj;
3488   return (day + (13 * m - 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
3489 }
3490
3491 ////////////////////////////////////////////////////////////////////////////////
3492 // Static
3493 int Datetime::monthOfYear (const std::string& input)
3494 {
3495   if (Datetime::minimumMatchLength== 0)
3496     Datetime::minimumMatchLength = 3;
3497
3498   for (unsigned int i = 0; i < monthNames.size (); ++i)
3499     if (closeEnough (monthNames[i], input, Datetime::minimumMatchLength))
3500        return i + 1;
3501
3502   return -1;
3503 }
3504
3505 ////////////////////////////////////////////////////////////////////////////////
3506 // Static
3507 int Datetime::length (const std::string& format)
3508 {
3509   int len = 0;
3510   for (auto& i : format)
3511   {
3512     switch (i)
3513     {
3514     case 'm':
3515     case 'M':
3516     case 'd':
3517     case 'D':
3518     case 'y':
3519     case 'v':
3520     case 'V':
3521     case 'h':
3522     case 'H':
3523     case 'n':
3524     case 'N':
3525     case 's':
3526     case 'S': len += 2;  break;
3527     case 'b':
3528     case 'j':
3529     case 'J':
3530     case 'a': len += 3;  break;
3531     case 'Y': len += 4;  break;
3532     case 'A':
3533     case 'B': len += 10; break;
3534
3535     // Calculate the width, don't assume a single character width.
3536     default:  len += mk_wcwidth (i); break;
3537     }
3538   }
3539
3540   return len;
3541 }
3542
3543 ////////////////////////////////////////////////////////////////////////////////
3544 int Datetime::month () const
3545 {
3546   struct tm* t = localtime (&_date);
3547   return t->tm_mon + 1;
3548 }
3549
3550 ////////////////////////////////////////////////////////////////////////////////
3551 int Datetime::week () const
3552 {
3553   struct tm* t = localtime (&_date);
3554
3555   char weekStr[3];
3556   if (Datetime::weekstart == 0)
3557     strftime (weekStr, sizeof (weekStr), "%U", t);
3558   else if (Datetime::weekstart == 1)
3559     strftime (weekStr, sizeof (weekStr), "%V", t);
3560   else
3561     throw std::string ("The week may only start on a Sunday or Monday.");
3562
3563   int weekNumber = strtol (weekStr, nullptr, 10);
3564   if (weekstart == 0)
3565     weekNumber += 1;
3566
3567   return weekNumber;
3568 }
3569
3570 ////////////////////////////////////////////////////////////////////////////////
3571 int Datetime::day () const
3572 {
3573   struct tm* t = localtime (&_date);
3574   return t->tm_mday;
3575 }
3576
3577 ////////////////////////////////////////////////////////////////////////////////
3578 int Datetime::year () const
3579 {
3580   struct tm* t = localtime (&_date);
3581   return t->tm_year + 1900;
3582 }
3583
3584 ////////////////////////////////////////////////////////////////////////////////
3585 int Datetime::dayOfWeek () const
3586 {
3587   struct tm* t = localtime (&_date);
3588   return t->tm_wday;
3589 }
3590
3591 ////////////////////////////////////////////////////////////////////////////////
3592 int Datetime::dayOfYear () const
3593 {
3594   struct tm* t = localtime (&_date);
3595   return t->tm_yday + 1;
3596 }
3597
3598 ////////////////////////////////////////////////////////////////////////////////
3599 int Datetime::hour () const
3600 {
3601   struct tm* t = localtime (&_date);
3602   return t->tm_hour;
3603 }
3604
3605 ////////////////////////////////////////////////////////////////////////////////
3606 int Datetime::minute () const
3607 {
3608   struct tm* t = localtime (&_date);
3609   return t->tm_min;
3610 }
3611
3612 ////////////////////////////////////////////////////////////////////////////////
3613 int Datetime::second () const
3614 {
3615   struct tm* t = localtime (&_date);
3616   return t->tm_sec;
3617 }
3618
3619 ////////////////////////////////////////////////////////////////////////////////
3620 bool Datetime::operator== (const Datetime& rhs) const
3621 {
3622   return rhs._date == _date;
3623 }
3624
3625 ////////////////////////////////////////////////////////////////////////////////
3626 bool Datetime::operator!= (const Datetime& rhs) const
3627 {
3628   return rhs._date != _date;
3629 }
3630
3631 ////////////////////////////////////////////////////////////////////////////////
3632 bool Datetime::operator< (const Datetime& rhs) const
3633 {
3634   return _date < rhs._date;
3635 }
3636
3637 ////////////////////////////////////////////////////////////////////////////////
3638 bool Datetime::operator> (const Datetime& rhs) const
3639 {
3640   return _date > rhs._date;
3641 }
3642
3643 ////////////////////////////////////////////////////////////////////////////////
3644 bool Datetime::operator<= (const Datetime& rhs) const
3645 {
3646   return _date <= rhs._date;
3647 }
3648
3649 ////////////////////////////////////////////////////////////////////////////////
3650 bool Datetime::operator>= (const Datetime& rhs) const
3651 {
3652   return _date >= rhs._date;
3653 }
3654
3655 ////////////////////////////////////////////////////////////////////////////////
3656 bool Datetime::sameHour (const Datetime& rhs) const
3657 {
3658   return year ()  == rhs.year ()  &&
3659          month () == rhs.month () &&
3660          day ()   == rhs.day ()   &&
3661          hour ()  == rhs.hour ();
3662 }
3663
3664 ////////////////////////////////////////////////////////////////////////////////
3665 bool Datetime::sameDay (const Datetime& rhs) const
3666 {
3667   return year ()  == rhs.year ()  &&
3668          month () == rhs.month () &&
3669          day ()   == rhs.day ();
3670 }
3671
3672 ////////////////////////////////////////////////////////////////////////////////
3673 bool Datetime::sameWeek (const Datetime& rhs) const
3674 {
3675   return year () == rhs.year () &&
3676          week () == rhs.week ();
3677 }
3678
3679 ////////////////////////////////////////////////////////////////////////////////
3680 bool Datetime::sameMonth (const Datetime& rhs) const
3681 {
3682   return year ()  == rhs.year () &&
3683          month () == rhs.month ();
3684 }
3685
3686 ////////////////////////////////////////////////////////////////////////////////
3687 bool Datetime::sameQuarter (const Datetime& rhs) const
3688 {
3689   return year () == rhs.year () &&
3690          ((month () - 1) / 3) == ((rhs.month () - 1) / 3);
3691 }
3692
3693 ////////////////////////////////////////////////////////////////////////////////
3694 bool Datetime::sameYear (const Datetime& rhs) const
3695 {
3696   return year () == rhs.year ();
3697 }
3698
3699 ////////////////////////////////////////////////////////////////////////////////
3700 Datetime Datetime::operator+ (const int delta)
3701 {
3702   return Datetime (_date + delta);
3703 }
3704
3705 ////////////////////////////////////////////////////////////////////////////////
3706 Datetime Datetime::operator- (const int delta)
3707 {
3708   return Datetime (_date - delta);
3709 }
3710
3711 ////////////////////////////////////////////////////////////////////////////////
3712 Datetime& Datetime::operator+= (const int delta)
3713 {
3714   _date += (time_t) delta;
3715   return *this;
3716 }
3717
3718 ////////////////////////////////////////////////////////////////////////////////
3719 Datetime& Datetime::operator-= (const int delta)
3720 {
3721   _date -= (time_t) delta;
3722   return *this;
3723 }
3724
3725 ////////////////////////////////////////////////////////////////////////////////
3726 time_t Datetime::operator- (const Datetime& rhs)
3727 {
3728   return _date - rhs._date;
3729 }
3730
3731 ////////////////////////////////////////////////////////////////////////////////
3732 // Prefix decrement by one day.
3733 void Datetime::operator-- ()
3734 {
3735   Datetime yesterday = startOfDay () - 1;
3736   yesterday = Datetime (yesterday.year (),
3737                         yesterday.month (),
3738                         yesterday.day (),
3739                         hour (),
3740                         minute (),
3741                         second ());
3742   _date = yesterday._date;
3743 }
3744
3745 ////////////////////////////////////////////////////////////////////////////////
3746 // Postfix decrement by one day.
3747 void Datetime::operator-- (int)
3748 {
3749   Datetime yesterday = startOfDay () - 1;
3750   yesterday = Datetime (yesterday.year (),
3751                         yesterday.month (),
3752                         yesterday.day (),
3753                         hour (),
3754                         minute (),
3755                         second ());
3756   _date = yesterday._date;
3757 }
3758
3759 ////////////////////////////////////////////////////////////////////////////////
3760 // Prefix increment by one day.
3761 void Datetime::operator++ ()
3762 {
3763   Datetime tomorrow = (startOfDay () + 90001).startOfDay ();
3764   tomorrow = Datetime (tomorrow.year (),
3765                        tomorrow.month (),
3766                        tomorrow.day (),
3767                        hour (),
3768                        minute (),
3769                        second ());
3770   _date = tomorrow._date;
3771 }
3772
3773 ////////////////////////////////////////////////////////////////////////////////
3774 // Postfix increment by one day.
3775 void Datetime::operator++ (int)
3776 {
3777   Datetime tomorrow = (startOfDay () + 90001).startOfDay ();
3778   tomorrow = Datetime (tomorrow.year (),
3779                        tomorrow.month (),
3780                        tomorrow.day (),
3781                        hour (),
3782                        minute (),
3783                        second ());
3784   _date = tomorrow._date;
3785 }
3786
3787 ////////////////////////////////////////////////////////////////////////////////