]> git.cworth.org Git - tar/blobdiff - lib/getdate.c
Imported Upstream version 1.21
[tar] / lib / getdate.c
index 07a293b66d4e99a05a7cb40599c3e0e716224e8a..2e5f210ca39bf7e664aa9335b8e0e2e728a9c498 100644 (file)
      tMINUTE_UNIT = 263,
      tSEC_UNIT = 264,
      tDAY_UNIT = 265,
-     tDAY = 266,
-     tDAYZONE = 267,
-     tLOCAL_ZONE = 268,
-     tMERIDIAN = 269,
-     tMONTH = 270,
-     tORDINAL = 271,
-     tZONE = 272,
-     tSNUMBER = 273,
-     tUNUMBER = 274,
-     tSDECIMAL_NUMBER = 275,
-     tUDECIMAL_NUMBER = 276
+     tDAY_SHIFT = 266,
+     tDAY = 267,
+     tDAYZONE = 268,
+     tLOCAL_ZONE = 269,
+     tMERIDIAN = 270,
+     tMONTH = 271,
+     tORDINAL = 272,
+     tZONE = 273,
+     tSNUMBER = 274,
+     tUNUMBER = 275,
+     tSDECIMAL_NUMBER = 276,
+     tUDECIMAL_NUMBER = 277
    };
 #endif
 /* Tokens.  */
 #define tMINUTE_UNIT 263
 #define tSEC_UNIT 264
 #define tDAY_UNIT 265
-#define tDAY 266
-#define tDAYZONE 267
-#define tLOCAL_ZONE 268
-#define tMERIDIAN 269
-#define tMONTH 270
-#define tORDINAL 271
-#define tZONE 272
-#define tSNUMBER 273
-#define tUNUMBER 274
-#define tSDECIMAL_NUMBER 275
-#define tUDECIMAL_NUMBER 276
+#define tDAY_SHIFT 266
+#define tDAY 267
+#define tDAYZONE 268
+#define tLOCAL_ZONE 269
+#define tMERIDIAN 270
+#define tMONTH 271
+#define tORDINAL 272
+#define tZONE 273
+#define tSNUMBER 274
+#define tUNUMBER 275
+#define tSDECIMAL_NUMBER 276
+#define tUDECIMAL_NUMBER 277
 
 
 
 
 /* Parse a string into an internal time stamp.
 
-   Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
-   Foundation, Inc.
+   Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 # undef static
 #endif
 
-#include <ctype.h>
+#include <c-ctype.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -320,7 +322,7 @@ typedef struct
 union YYSTYPE;
 static int yylex (union YYSTYPE *, parser_control *);
 static int yyerror (parser_control const *, char const *);
-static long int time_zone_hhmm (textint, long int);
+static long int time_zone_hhmm (parser_control *, textint, long int);
 
 /* Extract into *PC any date and time info from a string of digits
    of the form e.g., YYYYMMDD, YYMMDD, HHMM, HH (and sometimes YYY,
@@ -361,6 +363,31 @@ digits_to_date_time (parser_control *pc, textint text_int)
     }
 }
 
+/* Increment PC->rel by FACTOR * REL (FACTOR is 1 or -1).  */
+static void
+apply_relative_time (parser_control *pc, relative_time rel, int factor)
+{
+  pc->rel.ns += factor * rel.ns;
+  pc->rel.seconds += factor * rel.seconds;
+  pc->rel.minutes += factor * rel.minutes;
+  pc->rel.hour += factor * rel.hour;
+  pc->rel.day += factor * rel.day;
+  pc->rel.month += factor * rel.month;
+  pc->rel.year += factor * rel.year;
+  pc->rels_seen = true;
+}
+
+/* Set PC-> hour, minutes, seconds and nanoseconds members from arguments.  */
+static void
+set_hhmmss (parser_control *pc, long int hour, long int minutes,
+           time_t sec, long int nsec)
+{
+  pc->hour = hour;
+  pc->minutes = minutes;
+  pc->seconds.tv_sec = sec;
+  pc->seconds.tv_nsec = nsec;
+}
+
 
 
 /* Enabling traces.  */
@@ -383,7 +410,7 @@ digits_to_date_time (parser_control *pc, textint text_int)
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 261 "getdate.y"
+#line 286 "getdate.y"
 {
   long int intval;
   textint textintval;
@@ -391,7 +418,7 @@ typedef union YYSTYPE
   relative_time rel;
 }
 /* Line 187 of yacc.c.  */
-#line 395 "getdate.c"
+#line 422 "getdate.c"
        YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -404,7 +431,7 @@ typedef union YYSTYPE
 
 
 /* Line 216 of yacc.c.  */
-#line 408 "getdate.c"
+#line 435 "getdate.c"
 
 #ifdef short
 # undef short
@@ -619,20 +646,20 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  12
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   96
+#define YYLAST   98
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  26
+#define YYNTOKENS  27
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  20
+#define YYNNTS  21
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  80
+#define YYNRULES  82
 /* YYNRULES -- Number of states.  */
-#define YYNSTATES  98
+#define YYNSTATES  100
 
 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   276
+#define YYMAXUTOK   277
 
 #define YYTRANSLATE(YYX)                                               \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -644,9 +671,9 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,    24,     2,     2,    25,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    23,     2,
-       2,     2,     2,     2,    22,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,    25,     2,     2,    26,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    24,     2,
+       2,     2,     2,     2,    23,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -667,7 +694,7 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
        5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21
+      15,    16,    17,    18,    19,    20,    21,    22
 };
 
 #if YYDEBUG
@@ -679,53 +706,54 @@ static const yytype_uint8 yyprhs[] =
       20,    22,    24,    26,    28,    30,    33,    38,    44,    51,
       59,    61,    64,    66,    69,    73,    75,    78,    80,    83,
       86,    89,    93,    99,   103,   107,   111,   114,   119,   122,
-     126,   129,   131,   134,   137,   139,   142,   145,   147,   150,
-     153,   155,   158,   161,   163,   166,   169,   171,   174,   177,
-     180,   183,   185,   187,   190,   193,   196,   199,   202,   205,
-     207,   209,   211,   213,   215,   217,   219,   222,   223,   226,
-     227
+     126,   129,   131,   133,   136,   139,   141,   144,   147,   149,
+     152,   155,   157,   160,   163,   165,   168,   171,   173,   176,
+     179,   182,   185,   187,   189,   192,   195,   198,   201,   204,
+     207,   209,   211,   213,   215,   217,   219,   221,   223,   226,
+     227,   230,   231
 };
 
 /* YYRHS -- A `-1'-separated list of the rules' RHS.  */
 static const yytype_int8 yyrhs[] =
 {
-      27,     0,    -1,    28,    -1,    29,    -1,    22,    39,    -1,
-      -1,    29,    30,    -1,    31,    -1,    32,    -1,    33,    -1,
-      35,    -1,    34,    -1,    36,    -1,    42,    -1,    43,    -1,
-      19,    14,    -1,    19,    23,    19,    45,    -1,    19,    23,
-      19,    18,    44,    -1,    19,    23,    19,    23,    41,    45,
-      -1,    19,    23,    19,    23,    41,    18,    44,    -1,    13,
-      -1,    13,     4,    -1,    17,    -1,    17,    38,    -1,    17,
-      18,    44,    -1,    12,    -1,    17,     4,    -1,    11,    -1,
-      11,    24,    -1,    16,    11,    -1,    19,    11,    -1,    19,
-      25,    19,    -1,    19,    25,    19,    25,    19,    -1,    19,
-      18,    18,    -1,    19,    15,    18,    -1,    15,    18,    18,
-      -1,    15,    19,    -1,    15,    19,    24,    19,    -1,    19,
-      15,    -1,    19,    15,    19,    -1,    37,     3,    -1,    37,
-      -1,    16,     5,    -1,    19,     5,    -1,     5,    -1,    16,
-       6,    -1,    19,     6,    -1,     6,    -1,    16,    10,    -1,
-      19,    10,    -1,    10,    -1,    16,     7,    -1,    19,     7,
-      -1,     7,    -1,    16,     8,    -1,    19,     8,    -1,     8,
-      -1,    16,     9,    -1,    19,     9,    -1,    20,     9,    -1,
-      21,     9,    -1,     9,    -1,    38,    -1,    18,     5,    -1,
-      18,     6,    -1,    18,    10,    -1,    18,     7,    -1,    18,
-       8,    -1,    18,     9,    -1,    40,    -1,    41,    -1,    20,
-      -1,    18,    -1,    21,    -1,    19,    -1,    19,    -1,    19,
-      38,    -1,    -1,    23,    19,    -1,    -1,    14,    -1
+      28,     0,    -1,    29,    -1,    30,    -1,    23,    41,    -1,
+      -1,    30,    31,    -1,    32,    -1,    33,    -1,    34,    -1,
+      36,    -1,    35,    -1,    37,    -1,    44,    -1,    45,    -1,
+      20,    15,    -1,    20,    24,    20,    47,    -1,    20,    24,
+      20,    19,    46,    -1,    20,    24,    20,    24,    43,    47,
+      -1,    20,    24,    20,    24,    43,    19,    46,    -1,    14,
+      -1,    14,     4,    -1,    18,    -1,    18,    39,    -1,    18,
+      19,    46,    -1,    13,    -1,    18,     4,    -1,    12,    -1,
+      12,    25,    -1,    17,    12,    -1,    20,    12,    -1,    20,
+      26,    20,    -1,    20,    26,    20,    26,    20,    -1,    20,
+      19,    19,    -1,    20,    16,    19,    -1,    16,    19,    19,
+      -1,    16,    20,    -1,    16,    20,    25,    20,    -1,    20,
+      16,    -1,    20,    16,    20,    -1,    38,     3,    -1,    38,
+      -1,    40,    -1,    17,     5,    -1,    20,     5,    -1,     5,
+      -1,    17,     6,    -1,    20,     6,    -1,     6,    -1,    17,
+      10,    -1,    20,    10,    -1,    10,    -1,    17,     7,    -1,
+      20,     7,    -1,     7,    -1,    17,     8,    -1,    20,     8,
+      -1,     8,    -1,    17,     9,    -1,    20,     9,    -1,    21,
+       9,    -1,    22,     9,    -1,     9,    -1,    39,    -1,    19,
+       5,    -1,    19,     6,    -1,    19,    10,    -1,    19,     7,
+      -1,    19,     8,    -1,    19,     9,    -1,    11,    -1,    42,
+      -1,    43,    -1,    21,    -1,    19,    -1,    22,    -1,    20,
+      -1,    20,    -1,    20,    39,    -1,    -1,    24,    20,    -1,
+      -1,    15,    -1
 };
 
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   287,   287,   288,   292,   299,   301,   305,   307,   309,
-     311,   313,   315,   317,   318,   322,   330,   338,   348,   355,
-     367,   372,   380,   382,   392,   394,   396,   401,   406,   411,
-     416,   424,   429,   449,   456,   464,   472,   477,   483,   488,
-     497,   507,   520,   522,   524,   526,   528,   530,   532,   534,
-     536,   538,   540,   542,   544,   546,   548,   550,   552,   554,
-     556,   558,   560,   564,   566,   568,   570,   572,   574,   578,
-     578,   581,   582,   587,   588,   593,   598,   616,   617,   623,
-     624
+       0,   312,   312,   313,   317,   324,   326,   330,   332,   334,
+     336,   338,   340,   341,   342,   346,   351,   356,   363,   368,
+     378,   383,   391,   393,   396,   398,   400,   405,   410,   415,
+     420,   428,   433,   453,   460,   468,   476,   481,   487,   492,
+     501,   503,   505,   510,   512,   514,   516,   518,   520,   522,
+     524,   526,   528,   530,   532,   534,   536,   538,   540,   542,
+     544,   546,   548,   550,   554,   556,   558,   560,   562,   564,
+     569,   573,   573,   576,   577,   582,   583,   588,   593,   604,
+     605,   611,   612
 };
 #endif
 
@@ -736,12 +764,13 @@ static const char *const yytname[] =
 {
   "$end", "error", "$undefined", "tAGO", "tDST", "tYEAR_UNIT",
   "tMONTH_UNIT", "tHOUR_UNIT", "tMINUTE_UNIT", "tSEC_UNIT", "tDAY_UNIT",
-  "tDAY", "tDAYZONE", "tLOCAL_ZONE", "tMERIDIAN", "tMONTH", "tORDINAL",
-  "tZONE", "tSNUMBER", "tUNUMBER", "tSDECIMAL_NUMBER", "tUDECIMAL_NUMBER",
-  "'@'", "':'", "','", "'/'", "$accept", "spec", "timespec", "items",
-  "item", "time", "local_zone", "zone", "day", "date", "rel", "relunit",
-  "relunit_snumber", "seconds", "signed_seconds", "unsigned_seconds",
-  "number", "hybrid", "o_colon_minutes", "o_merid", 0
+  "tDAY_SHIFT", "tDAY", "tDAYZONE", "tLOCAL_ZONE", "tMERIDIAN", "tMONTH",
+  "tORDINAL", "tZONE", "tSNUMBER", "tUNUMBER", "tSDECIMAL_NUMBER",
+  "tUDECIMAL_NUMBER", "'@'", "':'", "','", "'/'", "$accept", "spec",
+  "timespec", "items", "item", "time", "local_zone", "zone", "day", "date",
+  "rel", "relunit", "relunit_snumber", "dayshift", "seconds",
+  "signed_seconds", "unsigned_seconds", "number", "hybrid",
+  "o_colon_minutes", "o_merid", 0
 };
 #endif
 
@@ -752,22 +781,22 @@ static const yytype_uint16 yytoknum[] =
 {
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
-     275,   276,    64,    58,    44,    47
+     275,   276,   277,    64,    58,    44,    47
 };
 # endif
 
 /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    26,    27,    27,    28,    29,    29,    30,    30,    30,
-      30,    30,    30,    30,    30,    31,    31,    31,    31,    31,
-      32,    32,    33,    33,    33,    33,    33,    34,    34,    34,
-      34,    35,    35,    35,    35,    35,    35,    35,    35,    35,
-      36,    36,    37,    37,    37,    37,    37,    37,    37,    37,
-      37,    37,    37,    37,    37,    37,    37,    37,    37,    37,
-      37,    37,    37,    38,    38,    38,    38,    38,    38,    39,
-      39,    40,    40,    41,    41,    42,    43,    44,    44,    45,
-      45
+       0,    27,    28,    28,    29,    30,    30,    31,    31,    31,
+      31,    31,    31,    31,    31,    32,    32,    32,    32,    32,
+      33,    33,    34,    34,    34,    34,    34,    35,    35,    35,
+      35,    36,    36,    36,    36,    36,    36,    36,    36,    36,
+      37,    37,    37,    38,    38,    38,    38,    38,    38,    38,
+      38,    38,    38,    38,    38,    38,    38,    38,    38,    38,
+      38,    38,    38,    38,    39,    39,    39,    39,    39,    39,
+      40,    41,    41,    42,    42,    43,    43,    44,    45,    46,
+      46,    47,    47
 };
 
 /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
@@ -777,11 +806,11 @@ static const yytype_uint8 yyr2[] =
        1,     1,     1,     1,     1,     2,     4,     5,     6,     7,
        1,     2,     1,     2,     3,     1,     2,     1,     2,     2,
        2,     3,     5,     3,     3,     3,     2,     4,     2,     3,
+       2,     1,     1,     2,     2,     1,     2,     2,     1,     2,
        2,     1,     2,     2,     1,     2,     2,     1,     2,     2,
-       1,     2,     2,     1,     2,     2,     1,     2,     2,     2,
-       2,     1,     1,     2,     2,     2,     2,     2,     2,     1,
-       1,     1,     1,     1,     1,     1,     2,     0,     2,     0,
-       1
+       2,     2,     1,     1,     2,     2,     2,     2,     2,     2,
+       1,     1,     1,     1,     1,     1,     1,     1,     2,     0,
+       2,     0,     1
 };
 
 /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -789,47 +818,49 @@ static const yytype_uint8 yyr2[] =
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       5,     0,     0,     2,     3,    72,    74,    71,    73,     4,
-      69,    70,     1,    44,    47,    53,    56,    61,    50,    27,
-      25,    20,     0,     0,    22,     0,    75,     0,     0,     6,
-       7,     8,     9,    11,    10,    12,    41,    62,    13,    14,
-      28,    21,     0,    36,    42,    45,    51,    54,    57,    48,
-      29,    26,    77,    23,    63,    64,    66,    67,    68,    65,
-      43,    46,    52,    55,    58,    49,    30,    15,    38,     0,
-       0,     0,    76,    59,    60,    40,    35,     0,     0,    24,
-      34,    39,    33,    79,    31,    37,    78,    80,    77,     0,
-      16,     0,    17,    79,    32,    77,    18,    19
+       5,     0,     0,     2,     3,    74,    76,    73,    75,     4,
+      71,    72,     1,    45,    48,    54,    57,    62,    51,    70,
+      27,    25,    20,     0,     0,    22,     0,    77,     0,     0,
+       6,     7,     8,     9,    11,    10,    12,    41,    63,    42,
+      13,    14,    28,    21,     0,    36,    43,    46,    52,    55,
+      58,    49,    29,    26,    79,    23,    64,    65,    67,    68,
+      69,    66,    44,    47,    53,    56,    59,    50,    30,    15,
+      38,     0,     0,     0,    78,    60,    61,    40,    35,     0,
+       0,    24,    34,    39,    33,    81,    31,    37,    80,    82,
+      79,     0,    16,     0,    17,    81,    32,    79,    18,    19
 };
 
 /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int8 yydefgoto[] =
 {
-      -1,     2,     3,     4,    29,    30,    31,    32,    33,    34,
-      35,    36,    37,     9,    10,    11,    38,    39,    79,    90
+      -1,     2,     3,     4,    30,    31,    32,    33,    34,    35,
+      36,    37,    38,    39,     9,    10,    11,    40,    41,    81,
+      92
 };
 
 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    STATE-NUM.  */
-#define YYPACT_NINF -81
+#define YYPACT_NINF -82
 static const yytype_int8 yypact[] =
 {
-     -10,    54,    70,   -81,    25,   -81,   -81,   -81,   -81,   -81,
-     -81,   -81,   -81,   -81,   -81,   -81,   -81,   -81,   -81,    55,
-     -81,    74,    50,    48,    10,    56,    -5,    71,    72,   -81,
-     -81,   -81,   -81,   -81,   -81,   -81,    79,   -81,   -81,   -81,
-     -81,   -81,    65,    60,   -81,   -81,   -81,   -81,   -81,   -81,
-     -81,   -81,    16,   -81,   -81,   -81,   -81,   -81,   -81,   -81,
-     -81,   -81,   -81,   -81,   -81,   -81,   -81,   -81,    58,    42,
-      66,    67,   -81,   -81,   -81,   -81,   -81,    68,    69,   -81,
-     -81,   -81,   -81,    -7,    64,   -81,   -81,   -81,    73,    -2,
-     -81,    75,   -81,    53,   -81,    73,   -81,   -81
+     -17,    56,    15,   -82,    26,   -82,   -82,   -82,   -82,   -82,
+     -82,   -82,   -82,   -82,   -82,   -82,   -82,   -82,   -82,   -82,
+      36,   -82,    68,    10,    50,     9,    59,    -5,    72,    73,
+     -82,   -82,   -82,   -82,   -82,   -82,   -82,    80,   -82,   -82,
+     -82,   -82,   -82,   -82,    65,    61,   -82,   -82,   -82,   -82,
+     -82,   -82,   -82,   -82,    17,   -82,   -82,   -82,   -82,   -82,
+     -82,   -82,   -82,   -82,   -82,   -82,   -82,   -82,   -82,   -82,
+      60,    44,    67,    69,   -82,   -82,   -82,   -82,   -82,    70,
+      71,   -82,   -82,   -82,   -82,    -7,    62,   -82,   -82,   -82,
+      74,    -2,   -82,    75,   -82,    55,   -82,    74,   -82,   -82
 };
 
 /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int8 yypgoto[] =
 {
-     -81,   -81,   -81,   -81,   -81,   -81,   -81,   -81,   -81,   -81,
-     -81,   -81,     3,   -81,   -81,     1,   -81,   -81,   -80,    -1
+     -82,   -82,   -82,   -82,   -82,   -82,   -82,   -82,   -82,   -82,
+     -82,   -82,    46,   -82,   -82,   -82,    -6,   -82,   -82,   -81,
+      -3
 };
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
@@ -839,46 +870,46 @@ static const yytype_int8 yypgoto[] =
 #define YYTABLE_NINF -1
 static const yytype_uint8 yytable[] =
 {
-      60,    61,    62,    63,    64,    65,    66,    87,    92,    67,
-      68,    88,     1,    69,    51,    97,    89,     6,    70,     8,
-      71,    54,    55,    56,    57,    58,    59,    53,    52,    72,
-      13,    14,    15,    16,    17,    18,    19,    20,    21,    78,
-      22,    23,    24,    25,    26,    27,    28,    54,    55,    56,
-      57,    58,    59,    44,    45,    46,    47,    48,    49,    50,
-      82,    54,    55,    56,    57,    58,    59,    87,    42,    43,
-      12,    95,     5,     6,     7,     8,    80,    81,    41,    40,
-      73,    74,    75,    76,    77,    83,    84,    85,    86,    91,
-      93,     0,    96,     0,    94,     0,    78
+      62,    63,    64,    65,    66,    67,     1,    68,    89,    94,
+      69,    70,    90,    53,    71,    12,    99,    91,     6,    72,
+       8,    73,    56,    57,    58,    59,    60,    61,    54,    44,
+      45,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    80,    23,    24,    25,    26,    27,    28,    29,    56,
+      57,    58,    59,    60,    61,    46,    47,    48,    49,    50,
+      51,    42,    52,    84,    56,    57,    58,    59,    60,    61,
+      89,    55,    43,    74,    97,     5,     6,     7,     8,    82,
+      83,    75,    76,    77,    78,    95,    79,    85,    93,    86,
+      87,    88,    98,     0,     0,    96,     0,     0,    80
 };
 
 static const yytype_int8 yycheck[] =
 {
-       5,     6,     7,     8,     9,    10,    11,    14,    88,    14,
-      15,    18,    22,    18,     4,    95,    23,    19,    23,    21,
-      25,     5,     6,     7,     8,     9,    10,    24,    18,    26,
-       5,     6,     7,     8,     9,    10,    11,    12,    13,    23,
-      15,    16,    17,    18,    19,    20,    21,     5,     6,     7,
-       8,     9,    10,     5,     6,     7,     8,     9,    10,    11,
-      18,     5,     6,     7,     8,     9,    10,    14,    18,    19,
-       0,    18,    18,    19,    20,    21,    18,    19,     4,    24,
-       9,     9,     3,    18,    24,    19,    19,    19,    19,    25,
-      89,    -1,    93,    -1,    19,    -1,    23
+       5,     6,     7,     8,     9,    10,    23,    12,    15,    90,
+      15,    16,    19,     4,    19,     0,    97,    24,    20,    24,
+      22,    26,     5,     6,     7,     8,     9,    10,    19,    19,
+      20,     5,     6,     7,     8,     9,    10,    11,    12,    13,
+      14,    24,    16,    17,    18,    19,    20,    21,    22,     5,
+       6,     7,     8,     9,    10,     5,     6,     7,     8,     9,
+      10,    25,    12,    19,     5,     6,     7,     8,     9,    10,
+      15,    25,     4,    27,    19,    19,    20,    21,    22,    19,
+      20,     9,     9,     3,    19,    91,    25,    20,    26,    20,
+      20,    20,    95,    -1,    -1,    20,    -1,    -1,    24
 };
 
 /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,    22,    27,    28,    29,    18,    19,    20,    21,    39,
-      40,    41,     0,     5,     6,     7,     8,     9,    10,    11,
-      12,    13,    15,    16,    17,    18,    19,    20,    21,    30,
-      31,    32,    33,    34,    35,    36,    37,    38,    42,    43,
-      24,     4,    18,    19,     5,     6,     7,     8,     9,    10,
-      11,     4,    18,    38,     5,     6,     7,     8,     9,    10,
-       5,     6,     7,     8,     9,    10,    11,    14,    15,    18,
-      23,    25,    38,     9,     9,     3,    18,    24,    23,    44,
-      18,    19,    18,    19,    19,    19,    19,    14,    18,    23,
-      45,    25,    44,    41,    19,    18,    45,    44
+       0,    23,    28,    29,    30,    19,    20,    21,    22,    41,
+      42,    43,     0,     5,     6,     7,     8,     9,    10,    11,
+      12,    13,    14,    16,    17,    18,    19,    20,    21,    22,
+      31,    32,    33,    34,    35,    36,    37,    38,    39,    40,
+      44,    45,    25,     4,    19,    20,     5,     6,     7,     8,
+       9,    10,    12,     4,    19,    39,     5,     6,     7,     8,
+       9,    10,     5,     6,     7,     8,     9,    10,    12,    15,
+      16,    19,    24,    26,    39,     9,     9,     3,    19,    25,
+      24,    46,    19,    20,    19,    20,    20,    20,    20,    15,
+      19,    24,    47,    26,    46,    43,    20,    19,    47,    46
 };
 
 #define yyerrok                (yyerrstatus = 0)
@@ -1699,7 +1730,7 @@ yyreduce:
   switch (yyn)
     {
         case 4:
-#line 293 "getdate.y"
+#line 318 "getdate.y"
     {
        pc->seconds = (yyvsp[(2) - (2)].timespec);
        pc->timespec_seen = true;
@@ -1707,94 +1738,76 @@ yyreduce:
     break;
 
   case 7:
-#line 306 "getdate.y"
+#line 331 "getdate.y"
     { pc->times_seen++; }
     break;
 
   case 8:
-#line 308 "getdate.y"
+#line 333 "getdate.y"
     { pc->local_zones_seen++; }
     break;
 
   case 9:
-#line 310 "getdate.y"
+#line 335 "getdate.y"
     { pc->zones_seen++; }
     break;
 
   case 10:
-#line 312 "getdate.y"
+#line 337 "getdate.y"
     { pc->dates_seen++; }
     break;
 
   case 11:
-#line 314 "getdate.y"
+#line 339 "getdate.y"
     { pc->days_seen++; }
     break;
 
-  case 12:
-#line 316 "getdate.y"
-    { pc->rels_seen = true; }
-    break;
-
   case 15:
-#line 323 "getdate.y"
+#line 347 "getdate.y"
     {
-       pc->hour = (yyvsp[(1) - (2)].textintval).value;
-       pc->minutes = 0;
-       pc->seconds.tv_sec = 0;
-       pc->seconds.tv_nsec = 0;
+       set_hhmmss (pc, (yyvsp[(1) - (2)].textintval).value, 0, 0, 0);
        pc->meridian = (yyvsp[(2) - (2)].intval);
       }
     break;
 
   case 16:
-#line 331 "getdate.y"
+#line 352 "getdate.y"
     {
-       pc->hour = (yyvsp[(1) - (4)].textintval).value;
-       pc->minutes = (yyvsp[(3) - (4)].textintval).value;
-       pc->seconds.tv_sec = 0;
-       pc->seconds.tv_nsec = 0;
+       set_hhmmss (pc, (yyvsp[(1) - (4)].textintval).value, (yyvsp[(3) - (4)].textintval).value, 0, 0);
        pc->meridian = (yyvsp[(4) - (4)].intval);
       }
     break;
 
   case 17:
-#line 339 "getdate.y"
+#line 357 "getdate.y"
     {
-       pc->hour = (yyvsp[(1) - (5)].textintval).value;
-       pc->minutes = (yyvsp[(3) - (5)].textintval).value;
-       pc->seconds.tv_sec = 0;
-       pc->seconds.tv_nsec = 0;
+       set_hhmmss (pc, (yyvsp[(1) - (5)].textintval).value, (yyvsp[(3) - (5)].textintval).value, 0, 0);
        pc->meridian = MER24;
        pc->zones_seen++;
-       pc->time_zone = time_zone_hhmm ((yyvsp[(4) - (5)].textintval), (yyvsp[(5) - (5)].intval));
+       pc->time_zone = time_zone_hhmm (pc, (yyvsp[(4) - (5)].textintval), (yyvsp[(5) - (5)].intval));
       }
     break;
 
   case 18:
-#line 349 "getdate.y"
+#line 364 "getdate.y"
     {
-       pc->hour = (yyvsp[(1) - (6)].textintval).value;
-       pc->minutes = (yyvsp[(3) - (6)].textintval).value;
-       pc->seconds = (yyvsp[(5) - (6)].timespec);
+       set_hhmmss (pc, (yyvsp[(1) - (6)].textintval).value, (yyvsp[(3) - (6)].textintval).value, (yyvsp[(5) - (6)].timespec).tv_sec, (yyvsp[(5) - (6)].timespec).tv_nsec);
        pc->meridian = (yyvsp[(6) - (6)].intval);
       }
     break;
 
   case 19:
-#line 356 "getdate.y"
+#line 369 "getdate.y"
     {
-       pc->hour = (yyvsp[(1) - (7)].textintval).value;
-       pc->minutes = (yyvsp[(3) - (7)].textintval).value;
-       pc->seconds = (yyvsp[(5) - (7)].timespec);
+       set_hhmmss (pc, (yyvsp[(1) - (7)].textintval).value, (yyvsp[(3) - (7)].textintval).value, (yyvsp[(5) - (7)].timespec).tv_sec, (yyvsp[(5) - (7)].timespec).tv_nsec);
        pc->meridian = MER24;
        pc->zones_seen++;
-       pc->time_zone = time_zone_hhmm ((yyvsp[(6) - (7)].textintval), (yyvsp[(7) - (7)].intval));
+       pc->time_zone = time_zone_hhmm (pc, (yyvsp[(6) - (7)].textintval), (yyvsp[(7) - (7)].intval));
       }
     break;
 
   case 20:
-#line 368 "getdate.y"
+#line 379 "getdate.y"
     {
        pc->local_isdst = (yyvsp[(1) - (1)].intval);
        pc->dsts_seen += (0 < (yyvsp[(1) - (1)].intval));
@@ -1802,7 +1815,7 @@ yyreduce:
     break;
 
   case 21:
-#line 373 "getdate.y"
+#line 384 "getdate.y"
     {
        pc->local_isdst = 1;
        pc->dsts_seen += (0 < (yyvsp[(1) - (2)].intval)) + 1;
@@ -1810,40 +1823,33 @@ yyreduce:
     break;
 
   case 22:
-#line 381 "getdate.y"
+#line 392 "getdate.y"
     { pc->time_zone = (yyvsp[(1) - (1)].intval); }
     break;
 
   case 23:
-#line 383 "getdate.y"
+#line 394 "getdate.y"
     { pc->time_zone = (yyvsp[(1) - (2)].intval);
-       pc->rel.ns += (yyvsp[(2) - (2)].rel).ns;
-       pc->rel.seconds += (yyvsp[(2) - (2)].rel).seconds;
-       pc->rel.minutes += (yyvsp[(2) - (2)].rel).minutes;
-       pc->rel.hour += (yyvsp[(2) - (2)].rel).hour;
-       pc->rel.day += (yyvsp[(2) - (2)].rel).day;
-       pc->rel.month += (yyvsp[(2) - (2)].rel).month;
-       pc->rel.year += (yyvsp[(2) - (2)].rel).year;
-        pc->rels_seen = true; }
+       apply_relative_time (pc, (yyvsp[(2) - (2)].rel), 1); }
     break;
 
   case 24:
-#line 393 "getdate.y"
-    { pc->time_zone = (yyvsp[(1) - (3)].intval) + time_zone_hhmm ((yyvsp[(2) - (3)].textintval), (yyvsp[(3) - (3)].intval)); }
+#line 397 "getdate.y"
+    { pc->time_zone = (yyvsp[(1) - (3)].intval) + time_zone_hhmm (pc, (yyvsp[(2) - (3)].textintval), (yyvsp[(3) - (3)].intval)); }
     break;
 
   case 25:
-#line 395 "getdate.y"
+#line 399 "getdate.y"
     { pc->time_zone = (yyvsp[(1) - (1)].intval) + 60; }
     break;
 
   case 26:
-#line 397 "getdate.y"
+#line 401 "getdate.y"
     { pc->time_zone = (yyvsp[(1) - (2)].intval) + 60; }
     break;
 
   case 27:
-#line 402 "getdate.y"
+#line 406 "getdate.y"
     {
        pc->day_ordinal = 1;
        pc->day_number = (yyvsp[(1) - (1)].intval);
@@ -1851,7 +1857,7 @@ yyreduce:
     break;
 
   case 28:
-#line 407 "getdate.y"
+#line 411 "getdate.y"
     {
        pc->day_ordinal = 1;
        pc->day_number = (yyvsp[(1) - (2)].intval);
@@ -1859,7 +1865,7 @@ yyreduce:
     break;
 
   case 29:
-#line 412 "getdate.y"
+#line 416 "getdate.y"
     {
        pc->day_ordinal = (yyvsp[(1) - (2)].intval);
        pc->day_number = (yyvsp[(2) - (2)].intval);
@@ -1867,7 +1873,7 @@ yyreduce:
     break;
 
   case 30:
-#line 417 "getdate.y"
+#line 421 "getdate.y"
     {
        pc->day_ordinal = (yyvsp[(1) - (2)].textintval).value;
        pc->day_number = (yyvsp[(2) - (2)].intval);
@@ -1875,7 +1881,7 @@ yyreduce:
     break;
 
   case 31:
-#line 425 "getdate.y"
+#line 429 "getdate.y"
     {
        pc->month = (yyvsp[(1) - (3)].textintval).value;
        pc->day = (yyvsp[(3) - (3)].textintval).value;
@@ -1883,7 +1889,7 @@ yyreduce:
     break;
 
   case 32:
-#line 430 "getdate.y"
+#line 434 "getdate.y"
     {
        /* Interpret as YYYY/MM/DD if the first value has 4 or more digits,
           otherwise as MM/DD/YY.
@@ -1906,7 +1912,7 @@ yyreduce:
     break;
 
   case 33:
-#line 450 "getdate.y"
+#line 454 "getdate.y"
     {
        /* ISO 8601 format.  YYYY-MM-DD.  */
        pc->year = (yyvsp[(1) - (3)].textintval);
@@ -1916,7 +1922,7 @@ yyreduce:
     break;
 
   case 34:
-#line 457 "getdate.y"
+#line 461 "getdate.y"
     {
        /* e.g. 17-JUN-1992.  */
        pc->day = (yyvsp[(1) - (3)].textintval).value;
@@ -1927,7 +1933,7 @@ yyreduce:
     break;
 
   case 35:
-#line 465 "getdate.y"
+#line 469 "getdate.y"
     {
        /* e.g. JUN-17-1992.  */
        pc->month = (yyvsp[(1) - (3)].intval);
@@ -1938,7 +1944,7 @@ yyreduce:
     break;
 
   case 36:
-#line 473 "getdate.y"
+#line 477 "getdate.y"
     {
        pc->month = (yyvsp[(1) - (2)].intval);
        pc->day = (yyvsp[(2) - (2)].textintval).value;
@@ -1946,7 +1952,7 @@ yyreduce:
     break;
 
   case 37:
-#line 478 "getdate.y"
+#line 482 "getdate.y"
     {
        pc->month = (yyvsp[(1) - (4)].intval);
        pc->day = (yyvsp[(2) - (4)].textintval).value;
@@ -1955,7 +1961,7 @@ yyreduce:
     break;
 
   case 38:
-#line 484 "getdate.y"
+#line 488 "getdate.y"
     {
        pc->day = (yyvsp[(1) - (2)].textintval).value;
        pc->month = (yyvsp[(2) - (2)].intval);
@@ -1963,7 +1969,7 @@ yyreduce:
     break;
 
   case 39:
-#line 489 "getdate.y"
+#line 493 "getdate.y"
     {
        pc->day = (yyvsp[(1) - (3)].textintval).value;
        pc->month = (yyvsp[(2) - (3)].intval);
@@ -1972,216 +1978,203 @@ yyreduce:
     break;
 
   case 40:
-#line 498 "getdate.y"
-    {
-       pc->rel.ns -= (yyvsp[(1) - (2)].rel).ns;
-       pc->rel.seconds -= (yyvsp[(1) - (2)].rel).seconds;
-       pc->rel.minutes -= (yyvsp[(1) - (2)].rel).minutes;
-       pc->rel.hour -= (yyvsp[(1) - (2)].rel).hour;
-       pc->rel.day -= (yyvsp[(1) - (2)].rel).day;
-       pc->rel.month -= (yyvsp[(1) - (2)].rel).month;
-       pc->rel.year -= (yyvsp[(1) - (2)].rel).year;
-      }
+#line 502 "getdate.y"
+    { apply_relative_time (pc, (yyvsp[(1) - (2)].rel), -1); }
     break;
 
   case 41:
-#line 508 "getdate.y"
-    {
-       pc->rel.ns += (yyvsp[(1) - (1)].rel).ns;
-       pc->rel.seconds += (yyvsp[(1) - (1)].rel).seconds;
-       pc->rel.minutes += (yyvsp[(1) - (1)].rel).minutes;
-       pc->rel.hour += (yyvsp[(1) - (1)].rel).hour;
-       pc->rel.day += (yyvsp[(1) - (1)].rel).day;
-       pc->rel.month += (yyvsp[(1) - (1)].rel).month;
-       pc->rel.year += (yyvsp[(1) - (1)].rel).year;
-      }
+#line 504 "getdate.y"
+    { apply_relative_time (pc, (yyvsp[(1) - (1)].rel), 1); }
     break;
 
   case 42:
-#line 521 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).year = (yyvsp[(1) - (2)].intval); }
+#line 506 "getdate.y"
+    { apply_relative_time (pc, (yyvsp[(1) - (1)].rel), 1); }
     break;
 
   case 43:
-#line 523 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).year = (yyvsp[(1) - (2)].textintval).value; }
+#line 511 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).year = (yyvsp[(1) - (2)].intval); }
     break;
 
   case 44:
-#line 525 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).year = 1; }
+#line 513 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).year = (yyvsp[(1) - (2)].textintval).value; }
     break;
 
   case 45:
-#line 527 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).month = (yyvsp[(1) - (2)].intval); }
+#line 515 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).year = 1; }
     break;
 
   case 46:
-#line 529 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).month = (yyvsp[(1) - (2)].textintval).value; }
+#line 517 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).month = (yyvsp[(1) - (2)].intval); }
     break;
 
   case 47:
-#line 531 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).month = 1; }
+#line 519 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).month = (yyvsp[(1) - (2)].textintval).value; }
     break;
 
   case 48:
-#line 533 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).day = (yyvsp[(1) - (2)].intval) * (yyvsp[(2) - (2)].intval); }
+#line 521 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).month = 1; }
     break;
 
   case 49:
-#line 535 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).day = (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); }
+#line 523 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).day = (yyvsp[(1) - (2)].intval) * (yyvsp[(2) - (2)].intval); }
     break;
 
   case 50:
-#line 537 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).day = (yyvsp[(1) - (1)].intval); }
+#line 525 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).day = (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); }
     break;
 
   case 51:
-#line 539 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).hour = (yyvsp[(1) - (2)].intval); }
+#line 527 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).day = (yyvsp[(1) - (1)].intval); }
     break;
 
   case 52:
-#line 541 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).hour = (yyvsp[(1) - (2)].textintval).value; }
+#line 529 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).hour = (yyvsp[(1) - (2)].intval); }
     break;
 
   case 53:
-#line 543 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).hour = 1; }
+#line 531 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).hour = (yyvsp[(1) - (2)].textintval).value; }
     break;
 
   case 54:
-#line 545 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).minutes = (yyvsp[(1) - (2)].intval); }
+#line 533 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).hour = 1; }
     break;
 
   case 55:
-#line 547 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).minutes = (yyvsp[(1) - (2)].textintval).value; }
+#line 535 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).minutes = (yyvsp[(1) - (2)].intval); }
     break;
 
   case 56:
-#line 549 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).minutes = 1; }
+#line 537 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).minutes = (yyvsp[(1) - (2)].textintval).value; }
     break;
 
   case 57:
-#line 551 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).seconds = (yyvsp[(1) - (2)].intval); }
+#line 539 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).minutes = 1; }
     break;
 
   case 58:
-#line 553 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).seconds = (yyvsp[(1) - (2)].textintval).value; }
+#line 541 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).seconds = (yyvsp[(1) - (2)].intval); }
     break;
 
   case 59:
-#line 555 "getdate.y"
-    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).seconds = (yyvsp[(1) - (2)].timespec).tv_sec; (yyval.rel).ns = (yyvsp[(1) - (2)].timespec).tv_nsec; }
+#line 543 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).seconds = (yyvsp[(1) - (2)].textintval).value; }
     break;
 
   case 60:
-#line 557 "getdate.y"
+#line 545 "getdate.y"
     { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).seconds = (yyvsp[(1) - (2)].timespec).tv_sec; (yyval.rel).ns = (yyvsp[(1) - (2)].timespec).tv_nsec; }
     break;
 
   case 61:
-#line 559 "getdate.y"
+#line 547 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).seconds = (yyvsp[(1) - (2)].timespec).tv_sec; (yyval.rel).ns = (yyvsp[(1) - (2)].timespec).tv_nsec; }
+    break;
+
+  case 62:
+#line 549 "getdate.y"
     { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).seconds = 1; }
     break;
 
-  case 63:
-#line 565 "getdate.y"
+  case 64:
+#line 555 "getdate.y"
     { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).year = (yyvsp[(1) - (2)].textintval).value; }
     break;
 
-  case 64:
-#line 567 "getdate.y"
+  case 65:
+#line 557 "getdate.y"
     { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).month = (yyvsp[(1) - (2)].textintval).value; }
     break;
 
-  case 65:
-#line 569 "getdate.y"
+  case 66:
+#line 559 "getdate.y"
     { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).day = (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); }
     break;
 
-  case 66:
-#line 571 "getdate.y"
+  case 67:
+#line 561 "getdate.y"
     { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).hour = (yyvsp[(1) - (2)].textintval).value; }
     break;
 
-  case 67:
-#line 573 "getdate.y"
+  case 68:
+#line 563 "getdate.y"
     { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).minutes = (yyvsp[(1) - (2)].textintval).value; }
     break;
 
-  case 68:
-#line 575 "getdate.y"
+  case 69:
+#line 565 "getdate.y"
     { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).seconds = (yyvsp[(1) - (2)].textintval).value; }
     break;
 
-  case 72:
-#line 583 "getdate.y"
-    { (yyval.timespec).tv_sec = (yyvsp[(1) - (1)].textintval).value; (yyval.timespec).tv_nsec = 0; }
+  case 70:
+#line 570 "getdate.y"
+    { (yyval.rel) = RELATIVE_TIME_0; (yyval.rel).day = (yyvsp[(1) - (1)].intval); }
     break;
 
   case 74:
-#line 589 "getdate.y"
+#line 578 "getdate.y"
     { (yyval.timespec).tv_sec = (yyvsp[(1) - (1)].textintval).value; (yyval.timespec).tv_nsec = 0; }
     break;
 
-  case 75:
-#line 594 "getdate.y"
+  case 76:
+#line 584 "getdate.y"
+    { (yyval.timespec).tv_sec = (yyvsp[(1) - (1)].textintval).value; (yyval.timespec).tv_nsec = 0; }
+    break;
+
+  case 77:
+#line 589 "getdate.y"
     { digits_to_date_time (pc, (yyvsp[(1) - (1)].textintval)); }
     break;
 
-  case 76:
-#line 599 "getdate.y"
+  case 78:
+#line 594 "getdate.y"
     {
        /* Hybrid all-digit and relative offset, so that we accept e.g.,
           "YYYYMMDD +N days" as well as "YYYYMMDD N days".  */
        digits_to_date_time (pc, (yyvsp[(1) - (2)].textintval));
-       pc->rel.ns += (yyvsp[(2) - (2)].rel).ns;
-       pc->rel.seconds += (yyvsp[(2) - (2)].rel).seconds;
-       pc->rel.minutes += (yyvsp[(2) - (2)].rel).minutes;
-       pc->rel.hour += (yyvsp[(2) - (2)].rel).hour;
-       pc->rel.day += (yyvsp[(2) - (2)].rel).day;
-       pc->rel.month += (yyvsp[(2) - (2)].rel).month;
-       pc->rel.year += (yyvsp[(2) - (2)].rel).year;
-       pc->rels_seen = true;
+       apply_relative_time (pc, (yyvsp[(2) - (2)].rel), 1);
       }
     break;
 
-  case 77:
-#line 616 "getdate.y"
+  case 79:
+#line 604 "getdate.y"
     { (yyval.intval) = -1; }
     break;
 
-  case 78:
-#line 618 "getdate.y"
+  case 80:
+#line 606 "getdate.y"
     { (yyval.intval) = (yyvsp[(2) - (2)].textintval).value; }
     break;
 
-  case 79:
-#line 623 "getdate.y"
+  case 81:
+#line 611 "getdate.y"
     { (yyval.intval) = MER24; }
     break;
 
-  case 80:
-#line 625 "getdate.y"
+  case 82:
+#line 613 "getdate.y"
     { (yyval.intval) = (yyvsp[(1) - (1)].intval); }
     break;
 
 
 /* Line 1267 of yacc.c.  */
-#line 2185 "getdate.c"
+#line 2178 "getdate.c"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -2395,7 +2388,7 @@ yyreturn:
 }
 
 
-#line 628 "getdate.y"
+#line 616 "getdate.y"
 
 
 static table const meridian_table[] =
@@ -2459,10 +2452,10 @@ static table const time_units_table[] =
 /* Assorted relative-time words. */
 static table const relative_time_table[] =
 {
-  { "TOMORROW",        tDAY_UNIT,       1 },
-  { "YESTERDAY",tDAY_UNIT,     -1 },
-  { "TODAY",   tDAY_UNIT,       0 },
-  { "NOW",     tDAY_UNIT,       0 },
+  { "TOMORROW",        tDAY_SHIFT,      1 },
+  { "YESTERDAY",tDAY_SHIFT,    -1 },
+  { "TODAY",   tDAY_SHIFT,      0 },
+  { "NOW",     tDAY_SHIFT,      0 },
   { "LAST",    tORDINAL,       -1 },
   { "THIS",    tORDINAL,        0 },
   { "NEXT",    tORDINAL,        1 },
@@ -2585,15 +2578,33 @@ static table const military_table[] =
 
 /* Convert a time zone expressed as HH:MM into an integer count of
    minutes.  If MM is negative, then S is of the form HHMM and needs
-   to be picked apart; otherwise, S is of the form HH.  */
+   to be picked apart; otherwise, S is of the form HH.  As specified in
+   http://www.opengroup.org/susv3xbd/xbd_chap08.html#tag_08_03, allow
+   only valid TZ range, and consider first two digits as hours, if no
+   minutes specified.  */
 
 static long int
-time_zone_hhmm (textint s, long int mm)
+time_zone_hhmm (parser_control *pc, textint s, long int mm)
 {
+  long int n_minutes;
+
+  /* If the length of S is 1 or 2 and no minutes are specified,
+     interpret it as a number of hours.  */
+  if (s.digits <= 2 && mm < 0)
+    s.value *= 100;
+
   if (mm < 0)
-    return (s.value / 100) * 60 + s.value % 100;
+    n_minutes = (s.value / 100) * 60 + s.value % 100;
   else
-    return s.value * 60 + (s.negative ? -mm : mm);
+    n_minutes = s.value * 60 + (s.negative ? -mm : mm);
+
+  /* If the absolute number of minutes is larger than 24 hours,
+     arrange to reject it by incrementing pc->zones_seen.  Thus,
+     we allow only values in the range UTC-24:00 to UTC+24:00.  */
+  if (24 * 60 < abs (n_minutes))
+    pc->zones_seen++;
+
+  return n_minutes;
 }
 
 static int
@@ -2690,7 +2701,7 @@ lookup_word (parser_control const *pc, char *word)
   for (p = word; *p; p++)
     {
       unsigned char ch = *p;
-      *p = toupper (ch);
+      *p = c_toupper (ch);
     }
 
   for (tp = meridian_table; tp->name; tp++)
@@ -2755,7 +2766,7 @@ yylex (YYSTYPE *lvalp, parser_control *pc)
 
   for (;;)
     {
-      while (c = *pc->input, isspace (c))
+      while (c = *pc->input, c_isspace (c))
        pc->input++;
 
       if (ISDIGIT (c) || c == '-' || c == '+')
@@ -2766,7 +2777,7 @@ yylex (YYSTYPE *lvalp, parser_control *pc)
          if (c == '-' || c == '+')
            {
              sign = c == '-' ? -1 : 1;
-             while (c = *++pc->input, isspace (c))
+             while (c = *++pc->input, c_isspace (c))
                continue;
              if (! ISDIGIT (c))
                /* skip the '-' sign */
@@ -2870,7 +2881,7 @@ yylex (YYSTYPE *lvalp, parser_control *pc)
            }
        }
 
-      if (isalpha (c))
+      if (c_isalpha (c))
        {
          char buff[20];
          char *p = buff;
@@ -2882,7 +2893,7 @@ yylex (YYSTYPE *lvalp, parser_control *pc)
                *p++ = c;
              c = *++pc->input;
            }
-         while (isalpha (c) || c == '.');
+         while (c_isalpha (c) || c == '.');
 
          *p = '\0';
          tp = lookup_word (pc, buff);
@@ -2995,7 +3006,7 @@ get_date (struct timespec *result, char const *p, struct timespec const *now)
   if (! tmp)
     return false;
 
-  while (c = *p, isspace (c))
+  while (c = *p, c_isspace (c))
     p++;
 
   if (strncmp (p, "TZ=\"", 4) == 0)
@@ -3207,25 +3218,6 @@ get_date (struct timespec *result, char const *p, struct timespec const *now)
            goto fail;
        }
 
-      if (pc.zones_seen)
-       {
-         long int delta = pc.time_zone * 60;
-         time_t t1;
-#ifdef HAVE_TM_GMTOFF
-         delta -= tm.tm_gmtoff;
-#else
-         time_t t = Start;
-         struct tm const *gmt = gmtime (&t);
-         if (! gmt)
-           goto fail;
-         delta -= tm_diff (&tm, gmt);
-#endif
-         t1 = Start - delta;
-         if ((Start < t1) != (delta < 0))
-           goto fail;  /* time_t overflow */
-         Start = t1;
-       }
-
       /* Add relative date.  */
       if (pc.rel.year | pc.rel.month | pc.rel.day)
        {
@@ -3248,6 +3240,27 @@ get_date (struct timespec *result, char const *p, struct timespec const *now)
            goto fail;
        }
 
+      /* The only "output" of this if-block is an updated Start value,
+        so this block must follow others that clobber Start.  */
+      if (pc.zones_seen)
+       {
+         long int delta = pc.time_zone * 60;
+         time_t t1;
+#ifdef HAVE_TM_GMTOFF
+         delta -= tm.tm_gmtoff;
+#else
+         time_t t = Start;
+         struct tm const *gmt = gmtime (&t);
+         if (! gmt)
+           goto fail;
+         delta -= tm_diff (&tm, gmt);
+#endif
+         t1 = Start - delta;
+         if ((Start < t1) != (delta < 0))
+           goto fail;  /* time_t overflow */
+         Start = t1;
+       }
+
       /* Add relative hours, minutes, and seconds.  On hosts that support
         leap seconds, ignore the possibility of leap seconds; e.g.,
         "+ 10 minutes" adds 600 seconds, even if one of them is a