Blob Blame History Raw
diff -u at-3.1.8-orig/parsetime.l at-3.1.8/parsetime.l
--- at-3.1.8-orig/parsetime.l	Sun Sep 28 13:26:30 1997
+++ at-3.1.8/parsetime.l	Sat Jan 26 14:18:10 2002
@@ -32,7 +32,6 @@
     } while(0)
 %}
 
-WORD		[a-z][a-z0-9]+
 %%
 
 now		{ COPY_TOK ; return NOW; }
@@ -57,6 +56,7 @@
 day(s)?		{ COPY_TOK ; return DAY; }
 week(s)?	{ COPY_TOK ; return WEEK; }
 month(s)?	{ COPY_TOK ; return MONTH; }
+year(s)?	{ COPY_TOK ; return YEAR; }
 jan(uary)?	{ COPY_TOK ; return JAN; }
 feb(ruary)?	{ COPY_TOK ; return FEB; }
 mar(ch)?	{ COPY_TOK ; return MAR; }
@@ -69,9 +69,16 @@
 oct(ober)?	{ COPY_TOK ; return OCT; }
 nov(ember)?	{ COPY_TOK ; return NOV; }
 dec(ember)?	{ COPY_TOK ; return DEC; }
+utc		{ COPY_TOK ; return UTC; }
+[0-9]{1}	{ COPY_TOK ; COPY_VAL; return INT1DIGIT; }
+[0-9]{2}	{ COPY_TOK ; COPY_VAL; return INT2DIGIT; }
+[0-9]{4}	{ COPY_TOK ; COPY_VAL; return INT4DIGIT; }
+[0-9]{5,8}	{ COPY_TOK ; COPY_VAL; return INT5_8DIGIT; }
 [0-9]+		{ COPY_TOK ; COPY_VAL; return INT; }
+[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{2}([0-9]{2})?	{ COPY_TOK ; COPY_VAL; return DOTTEDDATE; }
+[0-9]{2}([0-9]{2})?-[0-9]{1,2}-[0-9]{1,2}	{ COPY_TOK ; COPY_VAL; return HYPHENDATE; }
+[012]?[0-9][:'h,.][0-9]{2}	{ COPY_TOK ; COPY_VAL; return HOURMIN; }
 [ \t\n]		;
-{WORD}		{ COPY_TOK ; COPY_VAL; return WORD; }
 .		{ COPY_TOK ; return yytext[0]; }
 
 %%
diff -u at-3.1.8-orig/parsetime.y at-3.1.8/parsetime.y
--- at-3.1.8-orig/parsetime.y	Thu Jan 17 22:15:27 2002
+++ at-3.1.8/parsetime.y	Sat Jan 26 14:25:25 2002
@@ -22,6 +22,13 @@
 	int		intval;
 }
 
+%token  <charval> DOTTEDDATE
+%token  <charval> HYPHENDATE
+%token  <charval> HOURMIN
+%token  <charval> INT1DIGIT
+%token  <charval> INT2DIGIT
+%token  <charval> INT4DIGIT
+%token  <charval> INT5_8DIGIT
 %token  <charval> INT
 %token  NOW
 %token  AM PM
@@ -31,48 +38,61 @@
 %token  NEXT
 %token  MINUTE HOUR DAY WEEK MONTH YEAR
 %token  JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
-%token  <charval> WORD
+%token  UTC
 
-%type <intval> inc_period
-%type <intval> inc_number
+%type <charval> concatenated_date
+%type <charval> hr24clock_hr_min
+%type <charval> int1_2digit
+%type <charval> int2_or_4digit
+%type <charval> integer
+%type <intval> inc_dec_period
+%type <intval> inc_dec_number
 %type <intval> day_of_week
 
 %start timespec
 %%
-timespec        : date
+timespec        : spec_base
+		| spec_base inc_or_dec
+		    {
+			time_only = 0;
+
+		    }
+                ;
+
+spec_base	: date
 		| time
 		    {
 			time_only = 1;
 		    }
                 | time date
-                | time_or_not inc_or_dec
-                | time_or_not date inc_or_dec
-                | nowspec
-                ;
+                | NOW
+		;
 
-nowspec         : now
-                | now inc_or_dec
+time		: time_base
+		| time_base timezone_name
                 ;
 
-now		: NOW 
-                | TOMORROW
-		   {
-			add_date(1, DAY);
-		   }
-		;
-
-time_or_not     : time
-		|
+time_base	: hr24clock_hr_min
+		    {
+			exectm.tm_min = -1;
+			exectm.tm_hour = -1;
+			sscanf($1, "%2d %2d", &exectm.tm_hour,
+			    &exectm.tm_min);
+			free($1);
 
-time            : hr24clock_hr_min
-                | hr24clock_hr_min timezone_name
-                | hr24clock_hour time_sep minute
-                | hr24clock_hour time_sep minute timezone_name
-                | hr24clock_hour am_pm
-                | hr24clock_hour am_pm timezone_name
-                | hr24clock_hour time_sep minute am_pm
-                | hr24clock_hour time_sep minute am_pm timezone_name
-                | NOON
+			if (exectm.tm_min > 60 || exectm.tm_min < 0) {
+			    yyerror("Problem in minutes specification");
+			    YYERROR;
+			}
+			if (exectm.tm_hour > 24 || exectm.tm_hour < 0) {
+			    yyerror("Problem in hours specification");
+			    YYERROR;
+		        }
+		    }
+		| time_hour am_pm
+		| time_hour_min
+		| time_hour_min am_pm
+		| NOON
 		    {
 			exectm.tm_hour = 12;
 			exectm.tm_min = 0;
@@ -81,128 +101,23 @@
 		    {
 			exectm.tm_hour = 0;
 			exectm.tm_min = 0;
-			add_date(1, DAY);
 		    }
 		| TEATIME
 		    {
 			exectm.tm_hour = 16;
 			exectm.tm_min = 0;
 		    }
-                ;
-
-date            : month_name day_number
-                | month_name day_number year_number
-                | month_name day_number ',' year_number
-                | day_of_week
-		   {
-		       add_date ((6 + $1 - exectm.tm_wday) %7 + 1, DAY);
-		   }
-                | TODAY
-                | TOMORROW
-		   {
-			add_date(1, DAY);
-		   }
-		| year_number '-' month_number '-' day_number
-		| day_number '.' month_number '.' year_number
-		| day_number '.' month_number
-		| day_number month_name
-		| day_number month_name year_number
-		| month_number '/' day_number '/' year_number
-                ;
-
-inc_or_dec	: increment
-		| decrement
-
-increment       : '+' inc_number inc_period
-		    {
-		        add_date($2, $3);
-		    }
-                | NEXT inc_period		
-		    {
-			add_date(1, $2);
-		    }
-		| NEXT day_of_week
-		    {
-			add_date ((6 + $2 - exectm.tm_wday) %7 +1, DAY);
-		    }
-                ;
-
-decrement	: '-' inc_number inc_period
-		    {
-			add_date(-$2, $3);
-		    }
 		;
 
-inc_period      : MINUTE { $$ = MINUTE ; }
-                | HOUR	 { $$ = HOUR ; }
-                | DAY	 { $$ = DAY ; }
-                | WEEK   { $$ = WEEK ; }
-                | MONTH  { $$ = MONTH ; }
-                | YEAR   { $$ = YEAR ; }
-                ;
+hr24clock_hr_min: INT4DIGIT
+		;
 
-hr24clock_hr_min: INT
+time_hour	: int1_2digit
 		    {
-			if (strlen($1) == 4) {
-			    exectm.tm_min = -1;
-			    exectm.tm_hour = -1;
-			    sscanf($1, "%2d %2d", &exectm.tm_hour,
-				&exectm.tm_min);
-			} else if (strlen($1) >= 5 && strlen($1) <= 8) {
-				/* Ok, this is a kluge.  I hate design errors...  -Joey */
-				char shallot[5];
-				char *onion;
-
-				onion=$1;
-				memset (shallot, 0, sizeof (shallot));
-				if (strlen($1) == 5 || strlen($1) == 7) {
-				    strncpy (shallot,onion,1);
-				    onion++;
-				} else {
-				    strncpy (shallot,onion,2);
-				    onion+=2;
-				}
-				sscanf(shallot, "%d", &exectm.tm_mon);
-
-				if (exectm.tm_mon < 1 || exectm.tm_mon > 12) {
-				    yyerror("Error in month number");
-				    YYERROR;
-				}
-				exectm.tm_mon--;
-
-				memset (shallot, 0, sizeof (shallot));
-				strncpy (shallot,onion,2);
-			    	sscanf(shallot, "%d", &exectm.tm_mday);
-				if (exectm.tm_mday < 0 || exectm.tm_mday > 31)
-				{
-				    yyerror("Error in day of month");
-				    YYERROR;
-				}
-
-				onion+=2;
-				memset (shallot, 0, sizeof (shallot));
-				strncpy (shallot,onion,4);
-				if ( sscanf(shallot, "%d", &exectm.tm_year) != 1) {
-				    yyerror("Error in year");
-				    YYERROR;
-				}
-				if (exectm.tm_year < 70) {
-				    exectm.tm_year += 100;
-				}
-				else if (exectm.tm_year > 1900) {
-				    exectm.tm_year -= 1900;
-				}
-			}
-			else {
-			    sscanf($1, "%d", &exectm.tm_hour);
-			    exectm.tm_min = 0;
-			}
+			sscanf($1, "%d", &exectm.tm_hour);
+			exectm.tm_min = 0;
 			free($1);
 
-			if (exectm.tm_min > 60 || exectm.tm_min < 0) {
-			    yyerror("Problem in minutes specification");
-			    YYERROR;
-			}
 			if (exectm.tm_hour > 24 || exectm.tm_hour < 0) {
 			    yyerror("Problem in hours specification");
 			    YYERROR;
@@ -210,29 +125,22 @@
 		    }
 		;
 
-timezone_name	: WORD
+time_hour_min	: HOURMIN
 		    {
-			if (strcasecmp($1,"utc") == 0) {
-			    isgmt = 1;
-			}
-			else {
-			    yyerror("Only UTC timezone is supported");
-			    YYERROR;
-			}
+			exectm.tm_min = -1;
+			exectm.tm_hour = -1;
+			sscanf($1, "%d %*c %d", &exectm.tm_hour,
+			    &exectm.tm_min);
 			free($1);
-		    }
-		;
-
-hr24clock_hour	: hr24clock_hr_min
-		;
 
-minute		: INT
-                    {
-			if (sscanf($1, "%d", &exectm.tm_min) != 1) {
-			    yyerror("Error in minute");
+			if (exectm.tm_min > 60 || exectm.tm_min < 0) {
+			    yyerror("Problem in minutes specification");
+			    YYERROR;
+			}
+			if (exectm.tm_hour > 24 || exectm.tm_hour < 0) {
+			    yyerror("Problem in hours specification");
 			    YYERROR;
 		        }
-			free($1);
 		    }
 		;
 
@@ -258,6 +166,171 @@
 		    }
 		;
 
+timezone_name	: UTC
+		    {
+			isgmt = 1;
+		    }
+		;
+
+date            : month_name day_number
+                | month_name day_number year_number
+                | month_name day_number ',' year_number
+                | day_of_week
+		   {
+		       add_date ((6 + $1 - exectm.tm_wday) %7 + 1, DAY);
+		   }
+                | TODAY
+                | TOMORROW
+		   {
+			add_date(1, DAY);
+		   }
+		| HYPHENDATE
+		   {
+			int ynum = -1;
+			int mnum = -1;
+			int dnum = -1;
+
+			if (sscanf($1, "%d %*c %d %*c %d", &ynum, &mnum, &dnum) != 3) {
+			    yyerror("Error in hypenated date");
+			    YYERROR;
+			}
+
+			if (mnum < 1 || mnum > 12) {
+			    yyerror("Error in month number");
+			    YYERROR;
+			}
+			exectm.tm_mon = mnum -1;
+
+			if (ynum < 70) {
+			    ynum += 100;
+			}
+			else if (ynum > 1900) {
+			    ynum -= 1900;
+			}
+			exectm.tm_year = ynum ;
+
+			if (   dnum < 0
+			    || ((mnum ==  1 || mnum ==  3 || mnum ==  5 ||
+			         mnum ==  7 || mnum ==  8 || mnum == 10 ||
+				 mnum == 12) && dnum > 31)
+			    || ((mnum ==  4 || mnum ==  6 || mnum ==  9 ||
+			         mnum == 11) && dnum > 30)
+			    || (mnum ==  2 && dnum > 29 &&  __isleap(ynum+1900))
+			    || (mnum ==  2 && dnum > 28 && !__isleap(ynum+1900))
+			   )
+			{
+			    yyerror("Error in day of month");
+			    YYERROR; 
+			}
+			exectm.tm_mday = dnum;
+
+			free($1);
+		   }
+		| DOTTEDDATE
+		   {
+			int ynum = -1;
+			int mnum = -1;
+			int dnum = -1;
+
+			if (sscanf($1, "%d %*c %d %*c %d", &dnum, &mnum, &ynum) != 3) {
+			    yyerror("Error in dotted date");
+			    YYERROR;
+			}
+
+			if (mnum < 1 || mnum > 12) {
+			    yyerror("Error in month number");
+			    YYERROR;
+			}
+			exectm.tm_mon = mnum -1;
+
+			if (ynum < 70) {
+			    ynum += 100;
+			}
+			else if (ynum > 1900) {
+			    ynum -= 1900;
+			}
+			exectm.tm_year = ynum ;
+
+			if (   dnum < 0
+			    || ((mnum ==  1 || mnum ==  3 || mnum ==  5 ||
+			         mnum ==  7 || mnum ==  8 || mnum == 10 ||
+				 mnum == 12) && dnum > 31)
+			    || ((mnum ==  4 || mnum ==  6 || mnum ==  9 ||
+			         mnum == 11) && dnum > 30)
+			    || (mnum ==  2 && dnum > 29 &&  __isleap(ynum+1900))
+			    || (mnum ==  2 && dnum > 28 && !__isleap(ynum+1900))
+			   )
+			{
+			    yyerror("Error in day of month");
+			    YYERROR; 
+			}
+			exectm.tm_mday = dnum;
+
+			free($1);
+		   }
+		| day_number month_name
+		| day_number month_name year_number
+		| month_number '/' day_number '/' year_number
+		| concatenated_date
+		    {
+			/* Ok, this is a kluge.  I hate design errors...  -Joey */
+			char shallot[5];
+			char *onion;
+
+			onion=$1;
+			memset (shallot, 0, sizeof (shallot));
+			if (strlen($1) == 5 || strlen($1) == 7) {
+			    strncpy (shallot,onion,1);
+			    onion++;
+			} else {
+			    strncpy (shallot,onion,2);
+			    onion+=2;
+			}
+			sscanf(shallot, "%d", &exectm.tm_mon);
+
+			if (exectm.tm_mon < 1 || exectm.tm_mon > 12) {
+			    yyerror("Error in month number");
+			    YYERROR;
+			}
+			exectm.tm_mon--;
+
+			memset (shallot, 0, sizeof (shallot));
+			strncpy (shallot,onion,2);
+		    	sscanf(shallot, "%d", &exectm.tm_mday);
+			if (exectm.tm_mday < 0 || exectm.tm_mday > 31)
+			{
+			    yyerror("Error in day of month");
+			    YYERROR;
+			}
+
+			onion+=2;
+			memset (shallot, 0, sizeof (shallot));
+			strncpy (shallot,onion,4);
+			if ( sscanf(shallot, "%d", &exectm.tm_year) != 1) {
+			    yyerror("Error in year");
+			    YYERROR;
+			}
+			if (exectm.tm_year < 70) {
+			    exectm.tm_year += 100;
+			}
+			else if (exectm.tm_year > 1900) {
+			    exectm.tm_year -= 1900;
+			}
+
+			free ($1);
+		    }
+                | NEXT inc_dec_period		
+		    {
+			add_date(1, $2);
+		    }
+		| NEXT day_of_week
+		    {
+			add_date ((6 + $2 - exectm.tm_wday) %7 +1, DAY);
+		    }
+                ;
+
+concatenated_date: INT5_8DIGIT
+		;
 
 month_name	: JAN { exectm.tm_mon = 0; }
 		| FEB { exectm.tm_mon = 1; }
@@ -273,7 +346,7 @@
 		| DEC { exectm.tm_mon =11; }
 		;
 
-month_number	: INT
+month_number	: int1_2digit
 		    {
 			{
 			    int mnum = -1;
@@ -287,7 +360,9 @@
 			    free($1);
 			}
 		    }
-day_number	: INT
+		;
+
+day_number	: int1_2digit
                      {
 			exectm.tm_mday = -1;
 			sscanf($1, "%d", &exectm.tm_mday);
@@ -300,7 +375,7 @@
 		     }
 		;
 
-year_number	: INT
+year_number	: int2_or_4digit
 		    { 
 			{
 			    int ynum;
@@ -322,7 +397,6 @@
 		    }
 		;
 
-
 day_of_week	: SUN { $$ = 0; }
 		| MON { $$ = 1; }
 		| TUE { $$ = 2; }
@@ -332,7 +406,23 @@
 		| SAT { $$ = 6; }
 		;
 
-inc_number	: INT
+inc_or_dec	: increment
+		| decrement
+		;
+
+increment       : '+' inc_dec_number inc_dec_period
+		    {
+		        add_date($2, $3);
+		    }
+                ;
+
+decrement	: '-' inc_dec_number inc_dec_period
+		    {
+			add_date(-$2, $3);
+		    }
+		;
+
+inc_dec_number	: integer
 		    {
 			if (sscanf($1, "%d", &$$) != 1) {
 			    yyerror("Unknown increment");
@@ -342,11 +432,27 @@
 		    }
 		;
 
-time_sep	: ':'
-		| '\''
-		| '.'
-		| 'h'
-		| ','
+inc_dec_period	: MINUTE { $$ = MINUTE ; }
+		| HOUR	 { $$ = HOUR   ; }
+		| DAY	 { $$ = DAY    ; }
+		| WEEK   { $$ = WEEK   ; }
+		| MONTH  { $$ = MONTH  ; }
+		| YEAR   { $$ = YEAR   ; }
+		;
+
+int1_2digit	: INT1DIGIT
+		| INT2DIGIT
+		;
+
+int2_or_4digit	: INT2DIGIT
+		| INT4DIGIT
+		;
+
+integer		: INT
+		| INT1DIGIT
+		| INT2DIGIT
+		| INT4DIGIT
+		| INT5_8DIGIT
 		;
 
 %%
@@ -370,10 +476,7 @@
 	if (exectime == (time_t)-1)
 	    return 0;
 	if (isgmt) {
-	    exectime += timezone;
-	    if (daylight) {
-		exectime -= 3600;
-	    }
+	    exectime -= timezone;
 	}
 	if (time_only && (currtime > exectime)) {
 	    exectime += 24*3600;
@@ -386,39 +489,29 @@
 }
 
 #ifdef TEST_PARSER
-/*
-
-Here are some lines to test:
-
-./parsetest 7AM Mar 24 2000
-./parsetest 7AM Mar 24 00
-./parsetest 7AM 032400
-./parsetest 7AM 03/24/00
-./parsetest 7AM 24.03.00
-./parsetest 7AM Mar 24
-
-./parsetest 03242000
-./parsetest noon 03242000
-./parsetest 5:30
-./parsetest 4pm + 3 days
-./parsetest 10am Jul 31
-
- */
+ 
 int
 main(int argc, char **argv)
 {
+    int retval = 1;
     time_t res;
     res = parsetime(argc-1, &argv[1]);
+    if (time_only) {
+	fprintf(stderr, "time_only = 1\n");
+    }
     if (res > 0) {
 	printf("%s",ctime(&res));
+	retval = 0;
     }
     else {
 	printf("Ooops...\n");
+	retval = 1;
     }
-    return 0;
+    return retval;
 }
 
 #endif
+
 int yyerror(char *s)
 {
     if (last_token == NULL)
@@ -430,12 +523,36 @@
 void
 add_seconds(struct tm *tm, long numsec)
 {
+    struct tm basetm = *tm;
     time_t timeval;
+
     timeval = mktime(tm);
     if (timeval == (time_t)-1)
         timeval = (time_t)0;
     timeval += numsec;
     *tm = *localtime(&timeval);
+
+    /*
+     * Adjust +-1 hour when moving in or out of DST
+     */
+
+    if (daylight > 0)	/* Only check if DST is used here */
+    {
+	/* Set tm_isdst on &basetm and tm */
+	(void) mktime(&basetm);
+	(void) mktime(tm);
+
+	if      (basetm.tm_isdst > 0 && tm->tm_isdst < 1)
+	{   /* DST to no DST */
+	    timeval += 3600l;
+	    *tm = *localtime(&timeval);
+	}
+	else if (basetm.tm_isdst < 1 && tm->tm_isdst > 0)
+	{   /* no DST to DST */
+	    timeval -= 3600l;
+	    *tm = *localtime(&timeval);
+	}
+    }
 }
 
 int
@@ -468,6 +585,10 @@
 	    }
 	    exectm.tm_mon = newmonth % 12;
 	    number += newmonth / 12 ;
+
+	    /* Recalculate tm_isdst so we don't get a +-1 hour creep */
+	    exectm.tm_isdst = -1;
+	    (void) mktime(&exectm);
 	}
 	if (number == 0) {
 	    break;
@@ -476,6 +597,9 @@
 
     case YEAR:
 	exectm.tm_year += number;
+	/* Recalculate tm_isdst so we don't get a +-1 hour creep */
+	exectm.tm_isdst = -1;
+	(void) mktime(&exectm);
 	break;
 
     default:
@@ -483,5 +607,6 @@
 	fprintf(stderr,"Unexpected case %d\n", period);
 	abort();
     }
+
     return 0;
 }
diff -u at-3.1.8-orig/timespec at-3.1.8/timespec
--- at-3.1.8-orig/timespec	Wed Mar 12 12:11:05 1997
+++ at-3.1.8/timespec	Sat Jan 26 14:18:10 2002
@@ -2,6 +2,13 @@
  * Abbreviated version of the yacc grammar used by at(1).
  */
 
+%token  <charval> DOTTEDDATE
+%token  <charval> HYPHENDATE
+%token  <charval> HOURMIN
+%token  <charval> INT1DIGIT
+%token  <charval> INT2DIGIT
+%token  <charval> INT4DIGIT
+%token  <charval> INT5_8DIGIT
 %token  <charval> INT
 %token  NOW
 %token  AM PM
@@ -11,100 +18,115 @@
 %token  NEXT
 %token  MINUTE HOUR DAY WEEK MONTH YEAR
 %token  JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
-%token  <charval> WORD
+%token  UTC
 
-%type <intval> inc_period
-%type <intval> inc_number
+%type <charval> concatenated_date
+%type <charval> hr24clock_hr_min
+%type <charval> int1_2digit
+%type <charval> int2_or_4digit
+%type <charval> integer
+%type <intval> inc_dec_period
+%type <intval> inc_dec_number
 %type <intval> day_of_week
 
 %start timespec
 %%
-timespec        : time
-                | time date
-                | time increment
-                | time date increment
-		| time decrement
-		| time date decrement
-                | nowspec
-                ;
-
-nowspec         : now
-                | now increment
-		| now decrement
+timespec        : spec_base
+		| spec_base inc_or_dec
                 ;
 
-now		: NOW 
+spec_base	: date
+		| time
+                | time date
+                | NOW
 		;
 
-time            : hr24clock_hr_min
-                | hr24clock_hr_min timezone_name
-                | hr24clock_hour time_sep minute
-                | hr24clock_hour time_sep minute timezone_name
-                | hr24clock_hour am_pm
-                | hr24clock_hour am_pm timezone_name
-                | hr24clock_hour time_sep minute am_pm
-                | hr24clock_hour time_sep minute am_pm timezone_name
-                | NOON
+time		: time_base
+		| time_base timezone_name
+                ;
+
+time_base	: hr24clock_hr_min
+		| time_hour am_pm
+		| time_hour_min
+		| time_hour_min am_pm
+		| NOON
                 | MIDNIGHT
 		| TEATIME
-                ;
+		;
+
+hr24clock_hr_min: INT4DIGIT
+		;
+
+time_hour	: int1_2digit
+		;
+
+time_hour_min	: HOURMIN
+		;
+
+am_pm		: AM
+		| PM
+		;
+
+timezone_name	: UTC
+		;
 
 date            : month_name day_number
+                | month_name day_number year_number
                 | month_name day_number ',' year_number
                 | day_of_week
                 | TODAY
                 | TOMORROW
-		| year_number '-' month_number '-' day_number
-		| day_number '.' month_number '.' year_number
-		| day_number '.' month_number
+		| HYPHENDATE
+		| DOTTEDDATE
 		| day_number month_name
 		| day_number month_name year_number
 		| month_number '/' day_number '/' year_number
-                ;
-
-increment       : '+' inc_number inc_period
-                | NEXT inc_period		
+		| concatenated_date
+                | NEXT inc_dec_period		
 		| NEXT day_of_week
                 ;
 
-decrement	: '-' inc_number inc_period
+concatenated_date: INT5_8DIGIT
 		;
 
-inc_period      : MINUTE | HOUR | DAY | WEEK | MONTH | YEAR
+month_name	: JAN | FEB | MAR | APR | MAY | JUN
+		| JUL | AUG | SEP | OCT | NOV | DEC
 		;
 
-hr24clock_hr_min: INT
+month_number	: int1_2digit
 		;
 
-timezone_name	: WORD
+day_number	: int1_2digit
 		;
 
-hr24clock_hour	: hr24clock_hr_min
+year_number	: int2_or_4digit
 		;
 
-minute		: INT
+day_of_week	: SUN | MON | TUE | WED | THU | FRI | SAT
 		;
 
-am_pm		: AM | PM
+inc_or_dec	: increment | decrement
 		;
 
-month_name	: JAN | FEB | MAR | APR | MAY | JUN | JUL
-		| AUG | SEP | OCT | NOV | DEC
-		;
+increment       : '+' inc_dec_number inc_dec_period
+                ;
 
-month_number	: INT
+decrement	: '-' inc_dec_number inc_dec_period
 		;
-day_number	: INT
+
+inc_dec_number	: integer
 		;
 
-year_number	: INT
+inc_dec_period	: MINUTE | HOUR | DAY | WEEK | MONTH | YEAR
 		;
 
-day_of_week	: SUN | MON | TUE | WED | THU | FRI | SAT
+int1_2digit	: INT1DIGIT | INT2DIGIT
 		;
 
-inc_number	: INT
+int2_or_4digit	: INT2DIGIT | INT4DIGIT
 		;
 
-time_sep	: ':' | '\'' | '.' | 'h' | ','
+integer		: INT | INT1DIGIT | INT2DIGIT | INT4DIGIT | INT5_8DIGIT
 		;
+
+%%