cvs: php4 / configure.in /ext/standard datetime.c parsedate.y
| From: | Andrei Zmievski | Date: | Thu, 15 Jun 2000 16:24:11 +0000 |
| Subject: | cvs: php4 / configure.in /ext/standard datetime.c parsedate.y | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-287@lists.php.net to get a copy of this message | ||
andrei Thu Jun 15 09:24:11 2000 EDT
Modified files:
/php4 configure.in
/php4/ext/standard datetime.c parsedate.y
Log:
@- Updated strtotime() to handle many more formats. It now has complete
@ feature parity with GNU date command. (Andrei)
Index: php4/configure.in
diff -u php4/configure.in:1.149 php4/configure.in:1.150
--- php4/configure.in:1.149 Wed Jun 14 04:51:43 2000
+++ php4/configure.in Thu Jun 15 09:24:10 2000
@@ -1,4 +1,4 @@
-dnl ## $Id: configure.in,v 1.149 2000/06/14 11:51:43 eschmid Exp $ -*- sh -*-
+dnl ## $Id: configure.in,v 1.150 2000/06/15 16:24:10 andrei Exp $ -*- sh -*-
dnl ## Process this file with autoconf to produce a configure script.
divert(1)
@@ -341,6 +341,7 @@
gettimeofday \
gmtime_r \
inet_aton \
+isascii \
link \
localtime_r \
lockf \
Index: php4/ext/standard/datetime.c
diff -u php4/ext/standard/datetime.c:1.46 php4/ext/standard/datetime.c:1.47
--- php4/ext/standard/datetime.c:1.46 Wed Jun 14 15:11:10 2000
+++ php4/ext/standard/datetime.c Thu Jun 15 09:24:10 2000
@@ -19,7 +19,7 @@
*/
-/* $Id: datetime.c,v 1.46 2000/06/14 22:11:10 hholzgra Exp $ */
+/* $Id: datetime.c,v 1.47 2000/06/15 16:24:10 andrei Exp $ */
#include "php.h"
@@ -53,7 +53,7 @@
};
#if !defined(HAVE_TM_ZONE) && !defined(_TIMEZONE) &&
!defined(HAVE_DECLARED_TIMEZONE)
-extern time_t timezone;
+extern time_t timezone, altzone;
extern int daylight;
#endif
@@ -65,7 +65,7 @@
#define isleap(year) (((year%4) == 0 && (year%100)!=0) || (year%400)==0)
-extern PHPAPI time_t parsedate(char *p, struct timeval *now);
+extern PHPAPI time_t parse_date (const char *p, const time_t *now);
/* {{{ proto int time(void)
Return current UNIX timestamp */
@@ -81,6 +81,7 @@
struct tm *ta, tmbuf;
time_t t;
int i, gmadjust, seconds, arg_count = ZEND_NUM_ARGS();
+ int is_dst = -1;
if (arg_count > 7 || zend_get_parameters_array_ex(arg_count,arguments) == FAILURE) {
WRONG_PARAM_COUNT;
@@ -116,7 +117,7 @@
*/
switch(arg_count) {
case 7:
- ta->tm_isdst = (*arguments[6])->value.lval;
+ ta->tm_isdst = is_dst = (*arguments[6])->value.lval;
/* fall-through */
case 6:
/*
@@ -155,6 +156,8 @@
}
seconds = mktime(ta);
+ if (is_dst == -1)
+ is_dst = ta->tm_isdst;
if (gm) {
#if HAVE_TM_GMTOFF
@@ -165,11 +168,12 @@
gmadjust = ta->tm_gmtoff;
#else
/*
- ** Without tm_gmtoff, the non-ANSI C run-time global 'timezone'
- ** variable simply returns the current Winter GMT offset
- ** in the current locale (defined in DOS/Windows compilers).
+ ** If correcting for daylight savings time, we set the adjustment to
+ ** the value of altzone variable. Otherwise, we need to overcorrect and
+ ** set the adjustment to the main timezone offset plus difference
+ ** between the main and alternate ones.
*/
- gmadjust = timezone;
+ gmadjust = -(is_dst ? altzone : timezone + (timezone - altzone));
#endif
seconds += gmadjust;
}
@@ -405,9 +409,9 @@
break;
case 'Z': /* timezone offset in seconds */
#if HAVE_TM_GMTOFF
- sprintf(tmp_buff, "%ld", ta->tm_isdst ? ta->tm_gmtoff-3600 : ta->tm_gmtoff);
+ sprintf(tmp_buff, "%ld", ta->tm_gmtoff);
#else
- sprintf(tmp_buff, "%ld", daylight ? timezone-3600 : timezone);
+ sprintf(tmp_buff, "%ld", ta->tm_isdst ? altzone : timezone);
#endif
strcat(return_value->value.str.val, tmp_buff);
break;
@@ -710,28 +714,27 @@
Convert string representation of date and time to a timestamp */
PHP_FUNCTION(strtotime)
{
- pval **timep, **nowp;
- int ac;
- struct timeval tv;
+ zval **z_time, **z_now;
+ int argc;
+ time_t now;
- ac = ZEND_NUM_ARGS();
+ argc = ZEND_NUM_ARGS();
- if (ac < 1 || ac > 2 || zend_get_parameters_ex(ac, &timep,&nowp)==FAILURE) {
+ if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &z_time, &z_now)==FAILURE)
{
WRONG_PARAM_COUNT;
}
- convert_to_string_ex(timep);
- if (ac == 2) {
- convert_to_long_ex(nowp);
- tv.tv_sec = (*nowp)->value.lval;
- tv.tv_usec = 0;
- RETURN_LONG(parsedate((*timep)->value.str.val, &tv));
+ convert_to_string_ex(z_time);
+ if (argc == 2) {
+ convert_to_long_ex(z_now);
+ now = Z_LVAL_PP(z_now);
+ RETURN_LONG(parse_date(Z_STRVAL_PP(z_time), &now));
} else {
- RETURN_LONG(parsedate((*timep)->value.str.val, NULL));
+ RETURN_LONG(parse_date(Z_STRVAL_PP(z_time), NULL));
}
}
-
/* }}} */
+
/*
* Local variables:
Index: php4/ext/standard/parsedate.y
diff -u php4/ext/standard/parsedate.y:1.18 php4/ext/standard/parsedate.y:1.19
--- php4/ext/standard/parsedate.y:1.18 Thu May 4 03:38:14 2000
+++ php4/ext/standard/parsedate.y Thu Jun 15 09:24:10 2000
@@ -1,37 +1,23 @@
%{
-/* $Revision: 1.18 $
-**
+/*
** Originally written by Steven M. Bellovin <smb@research.att.com> while
** at the University of North Carolina at Chapel Hill. Later tweaked by
** a couple of people on Usenet. Completely overhauled by Rich $alz
-** <rsalz@osf.org> and Jim Berets <jberets@bbn.com> in August, 1990.
-** Further revised (removed obsolete constructs and cleaned up timezone
-** names) in August, 1991, by Rich. Paul Eggert <eggert@twinsun.com>
-** helped in September, 1992.
-**
-** This grammar has six shift/reduce conflicts.
+** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
**
** This code is in the public domain and has no copyright.
*/
-/* SUPPRESS 530 *//* Empty body for statement */
-/* SUPPRESS 593 on yyerrlab *//* Label was not used */
-/* SUPPRESS 593 on yynewstate *//* Label was not used */
-/* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */
-
#include "php.h"
#ifdef PHP_WIN32
#include <malloc.h>
#endif
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
+#include <ctype.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
@@ -40,78 +26,118 @@
# include "win32/time.h"
#endif
-#include <ctype.h>
+#if HAVE_STDLIB_H
+# include <stdlib.h> /* for `free'; used by Bison 1.27 */
+#endif
#if defined(_HPUX_SOURCE)
#include <alloca.h>
#endif
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+
+/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
+ - Its arg may be any int or unsigned int; it need not be an unsigned char.
+ - It's guaranteed to evaluate its argument exactly once.
+ - It's typically faster.
+ Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+ only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless
+ it's important to use the locale's definition of `digit' even when the
+ host does not conform to Posix. */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
-#if !defined(HAVE_TM_ZONE) && !defined(_TIMEZONE) &&
!defined(HAVE_DECLARED_TIMEZONE)
-extern time_t timezone;
+#if defined (STDC_HEADERS) || defined (USG)
+# include <string.h>
#endif
-#define yylhs date_yylhs
-#define yylen date_yylen
-#define yydefred date_yydefred
-#define yydgoto date_yydgoto
-#define yysindex date_yysindex
-#define yyrindex date_yyrindex
-#define yygindex date_yygindex
-#define yytable date_yytable
-#define yycheck date_yycheck
-#define yyparse date_parse
-#define yyparse date_parse
-#define yylex date_lex
-#define yyerror date_error
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __attribute__(x)
+#endif
+#ifndef ATTRIBUTE_UNUSED
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif
- /* See the LeapYears table in Convert. */
-#define EPOCH 1970
-#define END_OF_TIME 2038
- /* Constants for general time calculations. */
-#define DST_OFFSET 1
-#define SECSPERDAY (24L * 60L * 60L)
- /* Readability for TABLE stuff. */
-#define HOUR(x) (x * 60)
-
-#define LPAREN '('
-#define RPAREN ')'
-#define IS7BIT(x) ((unsigned int)(x) < 0200)
+/* Some old versions of bison generate parsers that use bcopy.
+ That loses on systems that don't provide the function, so we have
+ to redefine it here. */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+# define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
-/*
-** Get the number of elements in a fixed-size array, or a pointer just
-** past the end of it.
-*/
-#define SIZEOF(array) ((int)(sizeof array / sizeof array[0]))
-#define ENDOF(array) (&array[SIZEOF(array)])
-#define CTYPE(isXXXXX, c) ((isascii((c)) && isXXXXX((c))))
-
-typedef struct _TIMEINFO {
- time_t time;
- long usec;
- long tzone;
-} TIMEINFO;
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+ as well as gratuitiously global symbol names, so we can have multiple
+ yacc generated parsers in the same program. Note that these are only
+ the variables produced by yacc. If other parser generators (bison,
+ byacc, etc) produce additional global names that conflict at link time,
+ then those parser generators need to be fixed instead of adding those
+ names to this list. */
+
+#define yymaxdepth gd_maxdepth
+#define yyparse gd_parse
+#define yylex gd_lex
+#define yyerror gd_error
+#define yylval gd_lval
+#define yychar gd_char
+#define yydebug gd_debug
+#define yypact gd_pact
+#define yyr1 gd_r1
+#define yyr2 gd_r2
+#define yydef gd_def
+#define yychk gd_chk
+#define yypgo gd_pgo
+#define yyact gd_act
+#define yyexca gd_exca
+#define yyerrflag gd_errflag
+#define yynerrs gd_nerrs
+#define yyps gd_ps
+#define yypv gd_pv
+#define yys gd_s
+#define yy_yys gd_yys
+#define yystate gd_state
+#define yytmp gd_tmp
+#define yyv gd_v
+#define yy_yyv gd_yyv
+#define yyval gd_val
+#define yylloc gd_lloc
+#define yyreds gd_reds /* With YYDEBUG defined */
+#define yytoks gd_toks /* With YYDEBUG defined */
+#define yylhs gd_yylhs
+#define yylen gd_yylen
+#define yydefred gd_yydefred
+#define yydgoto gd_yydgoto
+#define yysindex gd_yysindex
+#define yyrindex gd_yyrindex
+#define yygindex gd_yygindex
+#define yytable gd_yytable
+#define yycheck gd_yycheck
-int GetTimeInfo(TIMEINFO *Now);
+static int yylex ();
+static int yyerror ();
-typedef char const *STRING;
-typedef char * const CSTRING;
+#define EPOCH 1970
+#define HOUR(x) ((x) * 60)
+#define MAX_BUFF_LEN 128 /* size of buffer to read the date into */
+
/*
** An entry in the lexical lookup table.
*/
typedef struct _TABLE {
- STRING name;
+ const char *name;
int type;
- time_t value;
+ int value;
} TABLE;
-/*
-** Daylight-savings mode: on, off, or not yet known.
-*/
-typedef enum _DSTMODE {
- DSTon, DSToff, DSTmaybe
-} DSTMODE;
/*
** Meridian: am, pm, or 24-hour style.
@@ -122,49 +148,51 @@
/*
-** Global variables. We could get rid of most of them by using a yacc
-** union, but this is more efficient. (This routine predates the
-** yacc %union construct.)
+** Global variables. We could get rid of most of these by using a good
+** union as the yacc stack. (This routine was originally written before
+** yacc had the %union construct.) Maybe someday; right now we only use
+** the %union very rarely.
*/
-static char *yyInput;
-static DSTMODE yyDSTmode;
+static const char *yyInput;
+static int yyDayOrdinal;
+static int yyDayNumber;
static int yyHaveDate;
+static int yyHaveDay;
static int yyHaveRel;
static int yyHaveTime;
-static time_t yyTimezone;
-static time_t yyDay;
-static time_t yyHour;
-static time_t yyMinutes;
-static time_t yyMonth;
-static time_t yySeconds;
-static time_t yyYear;
+static int yyHaveZone;
+static int yyTimezone;
+static int yyDay;
+static int yyHour;
+static int yyMinutes;
+static int yyMonth;
+static int yySeconds;
+static int yyYear;
static MERIDIAN yyMeridian;
-static time_t yyRelMonth;
-static time_t yyRelSeconds;
-
-
+static int yyRelDay;
+static int yyRelHour;
+static int yyRelMinutes;
+static int yyRelMonth;
+static int yyRelSeconds;
+static int yyRelYear;
-static void date_error(char *s);
-
%}
-%pure_parser
-%expect 6
+/* This grammar has 13 shift/reduce conflicts. */
+%expect 13
%union {
- time_t Number;
+ int Number;
enum _MERIDIAN Meridian;
}
-
-%{
-static int date_lex(YYSTYPE *yylval);
-%}
-%token tDAY tDAYZONE tMERIDIAN tMONTH tMONTH_UNIT tSEC_UNIT tSNUMBER
-%token tUNUMBER tZONE
-
-%type <Number> tDAYZONE tMONTH tMONTH_UNIT tSEC_UNIT
-%type <Number> tSNUMBER tUNUMBER tZONE numzone zone
+%token tAGO tDAY tDAY_UNIT tDAYZONE tDST tHOUR_UNIT tID
+%token tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE
+
+%type <Number> tDAY tDAY_UNIT tDAYZONE tHOUR_UNIT tMINUTE_UNIT
+%type <Number> tMONTH tMONTH_UNIT
+%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE
%type <Meridian> tMERIDIAN o_merid
%%
@@ -175,34 +203,25 @@
item : time {
yyHaveTime++;
-#if defined(lint)
- /* I am compulsive about lint natterings... */
- if (yyHaveTime == -1) {
- YYERROR;
- }
-#endif /* defined(lint) */
}
- | time zone {
- yyHaveTime++;
- yyTimezone = $2;
+ | zone {
+ yyHaveZone++;
}
| date {
yyHaveDate++;
}
+ | day {
+ yyHaveDay++;
+ }
| rel {
- yyHaveRel = 1;
+ yyHaveRel++;
}
+ | number
;
-time : tUNUMBER o_merid {
- if ($1 < 100) {
- yyHour = $1;
- yyMinutes = 0;
- }
- else {
- yyHour = $1 / 100;
- yyMinutes = $1 % 100;
- }
+time : tUNUMBER tMERIDIAN {
+ yyHour = $1;
+ yyMinutes = 0;
yySeconds = 0;
yyMeridian = $2;
}
@@ -212,12 +231,14 @@
yySeconds = 0;
yyMeridian = $4;
}
- | tUNUMBER ':' tUNUMBER numzone {
+ | tUNUMBER ':' tUNUMBER tSNUMBER {
yyHour = $1;
yyMinutes = $3;
- yyTimezone = $4;
yyMeridian = MER24;
- yyDSTmode = DSToff;
+ yyHaveZone++;
+ yyTimezone = ($4 < 0
+ ? -$4 % 100 + (-$4 / 100) * 60
+ : - ($4 % 100 + ($4 / 100) * 60));
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
yyHour = $1;
@@ -225,56 +246,41 @@
yySeconds = $5;
yyMeridian = $6;
}
- | tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone {
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
yyHour = $1;
yyMinutes = $3;
yySeconds = $5;
- yyTimezone = $6;
yyMeridian = MER24;
- yyDSTmode = DSToff;
+ yyHaveZone++;
+ yyTimezone = ($6 < 0
+ ? -$6 % 100 + (-$6 / 100) * 60
+ : - ($6 % 100 + ($6 / 100) * 60));
}
;
zone : tZONE {
- $$ = $1;
- yyDSTmode = DSToff;
+ yyTimezone = $1;
}
| tDAYZONE {
- $$ = $1;
- yyDSTmode = DSTon;
- }
- | tZONE numzone {
- /* Only allow "GMT+300" and "GMT-0800" */
- if ($1 != 0) {
- YYABORT;
- }
- $$ = $2;
- yyDSTmode = DSToff;
+ yyTimezone = $1 - 60;
}
- | numzone {
- $$ = $1;
- yyDSTmode = DSToff;
+ |
+ tZONE tDST {
+ yyTimezone = $1 - 60;
}
;
-
-numzone : tSNUMBER {
- int i;
- /* Unix and GMT and numeric timezones -- a little confusing. */
- if ($1 < 0) {
- /* Don't work with negative modulus. */
- $1 = -$1;
- if ($1 > 9999 || (i = $1 % 100) >= 60) {
- YYABORT;
- }
- $$ = ($1 / 100) * 60 + i;
- }
- else {
- if ($1 > 9999 || (i = $1 % 100) >= 60) {
- YYABORT;
- }
- $$ = -(($1 / 100) * 60 + i);
- }
+day : tDAY {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tDAY ',' {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tUNUMBER tDAY {
+ yyDayOrdinal = $1;
+ yyDayNumber = $2;
}
;
@@ -283,25 +289,35 @@
yyDay = $3;
}
| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
- if ($1 > 100) {
- /* assume YYYY/MM/DD format, so need not to add 1900 */
- yyYear = $1;
- yyMonth = $3;
- yyDay = $5;
- }
- else {
- /* assume MM/DD/YY* format */
- yyMonth = $1;
- yyDay = $3;
- if ($5 > 100) {
- /* assume year is YYYY format, so need not to add 1900 */
- yyYear = $5;
- } else {
- /* assume year is YY format, so need to add 1900 */
- yyYear = $5 + 1900;
- }
- }
+ /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
+ The goal in recognizing YYYY/MM/DD is solely to support legacy
+ machine-generated dates like those in an RCS log listing. If
+ you want portability, use the ISO 8601 format. */
+ if ($1 >= 1000)
+ {
+ yyYear = $1;
+ yyMonth = $3;
+ yyDay = $5;
+ }
+ else
+ {
+ yyMonth = $1;
+ yyDay = $3;
+ yyYear = $5;
+ }
+ }
+ | tUNUMBER tSNUMBER tSNUMBER {
+ /* ISO 8601 format. yyyy-mm-dd. */
+ yyYear = $1;
+ yyMonth = -$2;
+ yyDay = -$3;
}
+ | tUNUMBER tMONTH tSNUMBER {
+ /* e.g. 17-JUN-1992. */
+ yyDay = $1;
+ yyMonth = $2;
+ yyYear = -$3;
+ }
| tMONTH tUNUMBER {
yyMonth = $1;
yyDay = $2;
@@ -309,68 +325,139 @@
| tMONTH tUNUMBER ',' tUNUMBER {
yyMonth = $1;
yyDay = $2;
- if ($4 > 100) {
- /* assume year is YYYY format, so need not to add 1900 */
- yyYear = $4;
- } else {
- /* assume year is YY format, so need to add 1900 */
- yyYear = $4 + 1900;
- }
+ yyYear = $4;
}
| tUNUMBER tMONTH {
- yyDay = $1;
yyMonth = $2;
+ yyDay = $1;
}
| tUNUMBER tMONTH tUNUMBER {
- yyDay = $1;
yyMonth = $2;
- if ($3 > 100) {
- /* assume year is YYYY format, so need not to add 1900 */
- yyYear = $3;
- } else {
- /* assume year is YY format, so need to add 1900 */
- yyYear = $3 + 1900;
- }
+ yyDay = $1;
+ yyYear = $3;
}
- | tDAY ',' tUNUMBER tMONTH tUNUMBER {
- yyDay = $3;
- yyMonth = $4;
- if ($5 > 100) {
- /* assume year is YYYY format, so need not to add 1900 */
- yyYear = $5;
- } else {
- /* assume year is YY format, so need to add 1900 */
- yyYear = $5 + 1900;
- }
+ ;
+
+rel : relunit tAGO {
+ yyRelSeconds = -yyRelSeconds;
+ yyRelMinutes = -yyRelMinutes;
+ yyRelHour = -yyRelHour;
+ yyRelDay = -yyRelDay;
+ yyRelMonth = -yyRelMonth;
+ yyRelYear = -yyRelYear;
}
+ | relunit
;
-rel : tSNUMBER tSEC_UNIT {
- yyRelSeconds += $1 * $2;
+relunit : tUNUMBER tYEAR_UNIT {
+ yyRelYear += $1 * $2;
}
- | tUNUMBER tSEC_UNIT {
- yyRelSeconds += $1 * $2;
+ | tSNUMBER tYEAR_UNIT {
+ yyRelYear += $1 * $2;
}
- | tSNUMBER tMONTH_UNIT {
- yyRelMonth += $1 * $2;
+ | tYEAR_UNIT {
+ yyRelYear += $1;
}
| tUNUMBER tMONTH_UNIT {
yyRelMonth += $1 * $2;
}
+ | tSNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tMONTH_UNIT {
+ yyRelMonth += $1;
+ }
+ | tUNUMBER tDAY_UNIT {
+ yyRelDay += $1 * $2;
+ }
+ | tSNUMBER tDAY_UNIT {
+ yyRelDay += $1 * $2;
+ }
+ | tDAY_UNIT {
+ yyRelDay += $1;
+ }
+ | tUNUMBER tHOUR_UNIT {
+ yyRelHour += $1 * $2;
+ }
+ | tSNUMBER tHOUR_UNIT {
+ yyRelHour += $1 * $2;
+ }
+ | tHOUR_UNIT {
+ yyRelHour += $1;
+ }
+ | tUNUMBER tMINUTE_UNIT {
+ yyRelMinutes += $1 * $2;
+ }
+ | tSNUMBER tMINUTE_UNIT {
+ yyRelMinutes += $1 * $2;
+ }
+ | tMINUTE_UNIT {
+ yyRelMinutes += $1;
+ }
+ | tUNUMBER tSEC_UNIT {
+ yyRelSeconds += $1 * $2;
+ }
+ | tSNUMBER tSEC_UNIT {
+ yyRelSeconds += $1 * $2;
+ }
+ | tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ ;
+
+number : tUNUMBER
+ {
+ if (yyHaveTime && yyHaveDate && !yyHaveRel)
+ yyYear = $1;
+ else
+ {
+ if ($1>10000)
+ {
+ yyHaveDate++;
+ yyDay= ($1)%100;
+ yyMonth= ($1/100)%100;
+ yyYear = $1/10000;
+ }
+ else
+ {
+ yyHaveTime++;
+ if ($1 < 100)
+ {
+ yyHour = $1;
+ yyMinutes = 0;
+ }
+ else
+ {
+ yyHour = $1 / 100;
+ yyMinutes = $1 % 100;
+ }
+ yySeconds = 0;
+ yyMeridian = MER24;
+ }
+ }
+ }
;
-o_merid : /* NULL */ {
+o_merid : /* NULL */
+ {
$$ = MER24;
- }
- | tMERIDIAN {
+ }
+ | tMERIDIAN
+ {
$$ = $1;
- }
+ }
;
%%
+time_t get_date (const char *p, const time_t *now);
+
+extern struct tm *gmtime ();
+extern struct tm *localtime ();
+extern time_t mktime ();
+
/* Month and day table. */
-static TABLE MonthDayTable[] = {
+static TABLE const MonthDayTable[] = {
{ "january", tMONTH, 1 },
{ "february", tMONTH, 2 },
{ "march", tMONTH, 3 },
@@ -380,528 +467,552 @@
{ "july", tMONTH, 7 },
{ "august", tMONTH, 8 },
{ "september", tMONTH, 9 },
+ { "sept", tMONTH, 9 },
{ "october", tMONTH, 10 },
{ "november", tMONTH, 11 },
{ "december", tMONTH, 12 },
- /* The value of the day isn't used... */
{ "sunday", tDAY, 0 },
- { "monday", tDAY, 0 },
- { "tuesday", tDAY, 0 },
- { "wednesday", tDAY, 0 },
- { "thursday", tDAY, 0 },
- { "friday", tDAY, 0 },
- { "saturday", tDAY, 0 },
+ { "monday", tDAY, 1 },
+ { "tuesday", tDAY, 2 },
+ { "tues", tDAY, 2 },
+ { "wednesday", tDAY, 3 },
+ { "wednes", tDAY, 3 },
+ { "thursday", tDAY, 4 },
+ { "thur", tDAY, 4 },
+ { "thurs", tDAY, 4 },
+ { "friday", tDAY, 5 },
+ { "saturday", tDAY, 6 },
+ { NULL, 0, 0 }
};
/* Time units table. */
-static TABLE UnitsTable[] = {
- { "year", tMONTH_UNIT, 12 },
+static TABLE const UnitsTable[] = {
+ { "year", tYEAR_UNIT, 1 },
{ "month", tMONTH_UNIT, 1 },
- { "week", tSEC_UNIT, 7 * 24 * 60 * 60 },
- { "day", tSEC_UNIT, 1 * 24 * 60 * 60 },
- { "hour", tSEC_UNIT, 60 * 60 },
- { "minute", tSEC_UNIT, 60 },
- { "min", tSEC_UNIT, 60 },
+ { "fortnight", tDAY_UNIT, 14 },
+ { "week", tDAY_UNIT, 7 },
+ { "day", tDAY_UNIT, 1 },
+ { "hour", tHOUR_UNIT, 1 },
+ { "minute", tMINUTE_UNIT, 1 },
+ { "min", tMINUTE_UNIT, 1 },
{ "second", tSEC_UNIT, 1 },
{ "sec", tSEC_UNIT, 1 },
+ { NULL, 0, 0 }
};
-/* Timezone table. */
-static TABLE TimezoneTable[] = {
- { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
- { "ut", tZONE, HOUR( 0) }, /* Universal */
- { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */
- { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */
- { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */
- { "wet", tZONE, HOUR( 0) }, /* Western European */
- { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
- { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */
- { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */
- { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
- { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
- { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
- { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
- { "cst", tZONE, HOUR( 6) }, /* Central Standard */
- { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
- { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
- { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
- { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
- { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
- { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
- { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
- { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */
- { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */
- { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
- { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */
- { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */
- { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */
- { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */
- { "mez", tZONE, -HOUR(1) }, /* Middle European */
- { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
- { "cet", tZONE, -HOUR(1) }, /* Central European */
- { "met", tZONE, -HOUR(1) }, /* Middle European */
- { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */
- { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */
- { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */
- { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */
- { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */
- { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */
- { "cct", tZONE, -HOUR(8) }, /* China Coast */
- { "jst", tZONE, -HOUR(9) }, /* Japan Standard */
- { "kst", tZONE, -HOUR(9) }, /* Korean Standard */
- { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */
- { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */
- { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */
- { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
- { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
- { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
- { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+ { "tomorrow", tDAY_UNIT, 1 },
+ { "yesterday", tDAY_UNIT, -1 },
+ { "today", tDAY_UNIT, 0 },
+ { "now", tDAY_UNIT, 0 },
+ { "last", tUNUMBER, -1 },
+ { "this", tMINUTE_UNIT, 0 },
+ { "next", tUNUMBER, 1 },
+ { "first", tUNUMBER, 1 },
+/* { "second", tUNUMBER, 2 }, */
+ { "third", tUNUMBER, 3 },
+ { "fourth", tUNUMBER, 4 },
+ { "fifth", tUNUMBER, 5 },
+ { "sixth", tUNUMBER, 6 },
+ { "seventh", tUNUMBER, 7 },
+ { "eighth", tUNUMBER, 8 },
+ { "ninth", tUNUMBER, 9 },
+ { "tenth", tUNUMBER, 10 },
+ { "eleventh", tUNUMBER, 11 },
+ { "twelfth", tUNUMBER, 12 },
+ { "ago", tAGO, 1 },
+ { NULL, 0, 0 }
+};
- /* For completeness we include the following entries. */
+/* The timezone table. */
+static TABLE const TimezoneTable[] = {
+ { "gmt", tZONE, HOUR ( 0) }, /* Greenwich Mean */
+ { "ut", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */
+ { "utc", tZONE, HOUR ( 0) },
+ { "wet", tZONE, HOUR ( 0) }, /* Western European */
+ { "bst", tDAYZONE, HOUR ( 0) }, /* British Summer */
+ { "wat", tZONE, HOUR ( 1) }, /* West Africa */
+ { "at", tZONE, HOUR ( 2) }, /* Azores */
#if 0
-
- /* Duplicate names. Either they conflict with a zone listed above
- * (which is either more likely to be seen or just been in circulation
- * longer), or they conflict with another zone in this section and
- * we could not reasonably choose one over the other. */
- { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */
- { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */
- { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
- { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */
- { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */
- { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */
- { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */
- { "cst", tZONE, HOUR( 5) }, /* Chile Standard */
- { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */
- { "ast", tZONE, HOUR( 5) }, /* Acre Standard */
- { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */
- { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */
- { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */
- { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */
- { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */
- { "sst", tZONE, HOUR(11) }, /* Samoa Standard */
- { "ist", tZONE, -HOUR(2) }, /* Israel Standard */
- { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */
- { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */
- { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */
- { "cst", tZONE, -HOUR(8) }, /* China Standard */
- { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */
- { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */
-
- /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */
- { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
- { "wat", tZONE, -HOUR(1) }, /* West Africa */
- { "at", tZONE, HOUR( 2) }, /* Azores */
- { "gst", tZONE, -HOUR(10) }, /* Guam Standard */
- { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */
- { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
- { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
- { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
- { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
- { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
- { "fwt", tZONE, -HOUR(1) }, /* French Winter */
- { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
- { "bt", tZONE, -HOUR(3) }, /* Baghdad */
- { "it", tZONE, -(HOUR(3)+30) }, /* Iran */
- { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
- { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
- { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */
- { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
- { "nst", tZONE, -HOUR(7) }, /* North Sumatra */
- { "sst", tZONE, -HOUR(7) }, /* South Sumatra */
- { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */
- { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
- { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
- { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */
- { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */
- { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */
- { "hdt", tDAYZONE, HOUR(10) }, /* -- expired 1986 */
+ /* For completeness. BST is also British Summer, and GST is
+ * also Guam Standard. */
+ { "bst", tZONE, HOUR ( 3) }, /* Brazil Standard */
+ { "gst", tZONE, HOUR ( 3) }, /* Greenland Standard */
+#endif
+#if 0
+ { "nft", tZONE, HOUR (3.5) }, /* Newfoundland */
+ { "nst", tZONE, HOUR (3.5) }, /* Newfoundland Standard */
+ { "ndt", tDAYZONE, HOUR (3.5) }, /* Newfoundland Daylight */
+#endif
+ { "ast", tZONE, HOUR ( 4) }, /* Atlantic Standard */
+ { "adt", tDAYZONE, HOUR ( 4) }, /* Atlantic Daylight */
+ { "est", tZONE, HOUR ( 5) }, /* Eastern Standard */
+ { "edt", tDAYZONE, HOUR ( 5) }, /* Eastern Daylight */
+ { "cst", tZONE, HOUR ( 6) }, /* Central Standard */
+ { "cdt", tDAYZONE, HOUR ( 6) }, /* Central Daylight */
+ { "mst", tZONE, HOUR ( 7) }, /* Mountain Standard */
+ { "mdt", tDAYZONE, HOUR ( 7) }, /* Mountain Daylight */
+ { "pst", tZONE, HOUR ( 8) }, /* Pacific Standard */
+ { "pdt", tDAYZONE, HOUR ( 8) }, /* Pacific Daylight */
+ { "yst", tZONE, HOUR ( 9) }, /* Yukon Standard */
+ { "ydt", tDAYZONE, HOUR ( 9) }, /* Yukon Daylight */
+ { "hst", tZONE, HOUR (10) }, /* Hawaii Standard */
+ { "hdt", tDAYZONE, HOUR (10) }, /* Hawaii Daylight */
+ { "cat", tZONE, HOUR (10) }, /* Central Alaska */
+ { "ahst", tZONE, HOUR (10) }, /* Alaska-Hawaii Standard */
+ { "nt", tZONE, HOUR (11) }, /* Nome */
+ { "idlw", tZONE, HOUR (12) }, /* International Date Line West */
+ { "cet", tZONE, -HOUR (1) }, /* Central European */
+ { "met", tZONE, -HOUR (1) }, /* Middle European */
+ { "mewt", tZONE, -HOUR (1) }, /* Middle European Winter */
+ { "mest", tDAYZONE, -HOUR (1) }, /* Middle European Summer */
+ { "mesz", tDAYZONE, -HOUR (1) }, /* Middle European Summer */
+ { "swt", tZONE, -HOUR (1) }, /* Swedish Winter */
+ { "sst", tDAYZONE, -HOUR (1) }, /* Swedish Summer */
+ { "fwt", tZONE, -HOUR (1) }, /* French Winter */
+ { "fst", tDAYZONE, -HOUR (1) }, /* French Summer */
+ { "eet", tZONE, -HOUR (2) }, /* Eastern Europe, USSR Zone 1 */
+ { "bt", tZONE, -HOUR (3) }, /* Baghdad, USSR Zone 2 */
+#if 0
+ { "it", tZONE, -HOUR (3.5) },/* Iran */
+#endif
+ { "zp4", tZONE, -HOUR (4) }, /* USSR Zone 3 */
+ { "zp5", tZONE, -HOUR (5) }, /* USSR Zone 4 */
+#if 0
+ { "ist", tZONE, -HOUR (5.5) },/* Indian Standard */
+#endif
+ { "zp6", tZONE, -HOUR (6) }, /* USSR Zone 5 */
+#if 0
+ /* For completeness. NST is also Newfoundland Standard, and SST is
+ * also Swedish Summer. */
+ { "nst", tZONE, -HOUR (6.5) },/* North Sumatra */
+ { "sst", tZONE, -HOUR (7) }, /* South Sumatra, USSR Zone 6 */
#endif /* 0 */
+ { "wast", tZONE, -HOUR (7) }, /* West Australian Standard */
+ { "wadt", tDAYZONE, -HOUR (7) }, /* West Australian Daylight */
+#if 0
+ { "jt", tZONE, -HOUR (7.5) },/* Java (3pm in Cronusland!) */
+#endif
+ { "cct", tZONE, -HOUR (8) }, /* China Coast, USSR Zone 7 */
+ { "jst", tZONE, -HOUR (9) }, /* Japan Standard, USSR Zone 8 */
+#if 0
+ { "cast", tZONE, -HOUR (9.5) },/* Central Australian Standard */
+ { "cadt", tDAYZONE, -HOUR (9.5) },/* Central Australian Daylight */
+#endif
+ { "east", tZONE, -HOUR (10) }, /* Eastern Australian Standard */
+ { "eadt", tDAYZONE, -HOUR (10) }, /* Eastern Australian Daylight */
+ { "gst", tZONE, -HOUR (10) }, /* Guam Standard, USSR Zone 9 */
+ { "nzt", tZONE, -HOUR (12) }, /* New Zealand */
+ { "nzst", tZONE, -HOUR (12) }, /* New Zealand Standard */
+ { "nzdt", tDAYZONE, -HOUR (12) }, /* New Zealand Daylight */
+ { "idle", tZONE, -HOUR (12) }, /* International Date Line East */
+ { NULL, 0, 0 }
};
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+ { "a", tZONE, HOUR ( 1) },
+ { "b", tZONE, HOUR ( 2) },
+ { "c", tZONE, HOUR ( 3) },
+ { "d", tZONE, HOUR ( 4) },
+ { "e", tZONE, HOUR ( 5) },
+ { "f", tZONE, HOUR ( 6) },
+ { "g", tZONE, HOUR ( 7) },
+ { "h", tZONE, HOUR ( 8) },
+ { "i", tZONE, HOUR ( 9) },
+ { "k", tZONE, HOUR ( 10) },
+ { "l", tZONE, HOUR ( 11) },
+ { "m", tZONE, HOUR ( 12) },
+ { "n", tZONE, HOUR (- 1) },
+ { "o", tZONE, HOUR (- 2) },
+ { "p", tZONE, HOUR (- 3) },
+ { "q", tZONE, HOUR (- 4) },
+ { "r", tZONE, HOUR (- 5) },
+ { "s", tZONE, HOUR (- 6) },
+ { "t", tZONE, HOUR (- 7) },
+ { "u", tZONE, HOUR (- 8) },
+ { "v", tZONE, HOUR (- 9) },
+ { "w", tZONE, HOUR (-10) },
+ { "x", tZONE, HOUR (-11) },
+ { "y", tZONE, HOUR (-12) },
+ { "z", tZONE, HOUR ( 0) },
+ { NULL, 0, 0 }
+};
+
+
/* ARGSUSED */
-static void
-date_error(char *s)
+static int
+yyerror (s)
+ char *s ATTRIBUTE_UNUSED;
{
- /* NOTREACHED */
+ return 0;
}
-int GetTimeInfo(TIMEINFO *Now)
+static int
+ToHour (Hours, Meridian)
+ int Hours;
+ MERIDIAN Meridian;
{
- static time_t NextHour;
- static long LastTzone;
- struct tm *tm, tmbuf;
- int secondsUntilNextHour;
-#if defined(HAVE_GETTIMEOFDAY)
- struct timeval tv;
-#endif /* defined(HAVE_GETTIMEOFDAY) */
-#if !defined(HAVE_TM_GMTOFF)
- struct tm local;
- struct tm gmt;
-#endif /* !defined(HAVE_TM_GMTOFF) */
-
- /* Get the basic time. */
-#if defined(HAVE_GETTIMEOFDAY)
- if (gettimeofday(&tv, (struct timezone *)NULL) == -1)
+ switch (Meridian)
+ {
+ case MER24:
+ if (Hours < 0 || Hours > 23)
return -1;
- Now->time = tv.tv_sec;
- Now->usec = tv.tv_usec;
-#else
- /* Can't check for -1 since that might be a time, I guess. */
- (void)time(&Now->time);
- Now->usec = 0;
-#endif /* defined(HAVE_GETTIMEOFDAY) */
-
- /* Now get the timezone if the last time < HH:00:00 <= now for some HH. */
- if (NextHour <= Now->time) {
- if ((tm = php_localtime_r(&Now->time, &tmbuf)) == NULL)
- return -1;
- secondsUntilNextHour = 60 * (60 - tm->tm_min) - tm->tm_sec;
-#if !defined(HAVE_TM_GMTOFF)
- /* To get the timezone, compare localtime with GMT. */
- local = *tm;
- if ((tm = php_gmtime_r(&Now->time, &tmbuf)) == NULL)
- return -1;
- gmt = *tm;
-
- /* Assume we are never more than 24 hours away. */
- LastTzone = gmt.tm_yday - local.tm_yday;
- if (LastTzone > 1)
- LastTzone = -24;
- else if (LastTzone < -1)
- LastTzone = 24;
- else
- LastTzone *= 24;
-
- /* Scale in the hours and minutes; ignore seconds. */
- LastTzone += gmt.tm_hour - local.tm_hour;
- LastTzone *= 60;
- LastTzone += gmt.tm_min - local.tm_min;
-#else
- LastTzone = (0 - tm->tm_gmtoff) / 60;
-#endif /* defined(HAVE_TM_GMTOFF) */
- NextHour = Now->time + secondsUntilNextHour;
- }
- Now->tzone = LastTzone;
- return 0;
-}
-
-
-static time_t
-ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
-{
- if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61)
+ return Hours;
+ case MERam:
+ if (Hours < 1 || Hours > 12)
return -1;
- if (Meridian == MER24) {
- if (Hours < 0 || Hours > 23)
- return -1;
- }
- else {
- if (Hours < 1 || Hours > 12)
- return -1;
- if (Hours == 12)
- Hours = 0;
- if (Meridian == MERpm)
- Hours += 12;
+ if (Hours == 12)
+ Hours = 0;
+ return Hours;
+ case MERpm:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ if (Hours == 12)
+ Hours = 0;
+ return Hours + 12;
+ default:
+ abort ();
}
- return (Hours * 60L + Minutes) * 60L + Seconds;
+ /* NOTREACHED */
}
-
-static time_t
-Convert(time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes, time_t Seconds,
MERIDIAN Meridian, DSTMODE dst)
+static int
+ToYear (Year)
+ int Year;
{
- static int DaysNormal[13] = {
- 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
- static int DaysLeap[13] = {
- 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
- static int LeapYears[] = {
- 1972, 1976, 1980, 1984, 1988, 1992, 1996,
- 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036
- };
- int *yp;
- int *mp;
- time_t Julian;
- int i;
- time_t tod;
- struct tm tmbuf;
-
- /* Year should not be passed as a relative value, but absolute one.
- so this should not happen, but just ensure it */
- if (Year < 0)
- Year = -Year;
- if (Year < 100)
- Year += 1900;
- if (Year < EPOCH)
- Year += 100;
- for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++)
- if (Year == *yp) {
- mp = DaysLeap;
- break;
- }
- if (Year < EPOCH || Year > END_OF_TIME
- || Month < 1 || Month > 12
- /* NOSTRICT *//* conversion from long may lose accuracy */
- || Day < 1 || Day > mp[(int)Month])
- return -1;
+ if (Year < 0)
+ Year = -Year;
- Julian = Day - 1 + (Year - EPOCH) * 365;
- for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++)
- if (Year <= *yp)
- break;
- for (i = 1; i < Month; i++)
- Julian += *++mp;
- Julian *= SECSPERDAY;
- Julian += yyTimezone * 60L;
- if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
- return -1;
- Julian += tod;
- tod = Julian;
- if (dst == DSTon || (dst == DSTmaybe &&
php_localtime_r(&tod,&tmbuf)->tm_isdst))
- Julian -= DST_OFFSET * 60 * 60;
- return Julian;
-}
-
+ /* XPG4 suggests that years 00-68 map to 2000-2068, and
+ years 69-99 map to 1969-1999. */
+ if (Year < 69)
+ Year += 2000;
+ else if (Year < 100)
+ Year += 1900;
-static time_t
-DSTcorrect(time_t Start, time_t Future)
-{
- time_t StartDay;
- time_t FutureDay;
- struct tm tmbuf;
-
- StartDay = (php_localtime_r(&Start,&tmbuf)->tm_hour + 1) % 24;
- FutureDay = (php_localtime_r(&Future,&tmbuf)->tm_hour + 1) % 24;
- return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60 * 60;
+ return Year;
}
-
-static time_t
-RelativeMonth(time_t Start, time_t RelMonth)
+static int
+LookupWord (buff)
+ char *buff;
{
- struct tm *tm, tmbuf;
- time_t Month;
- time_t Year;
-
- tm = php_localtime_r(&Start, &tmbuf);
- Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
- Year = Month / 12;
- Year += 1900;
- Month = Month % 12 + 1;
- return DSTcorrect(Start,
- Convert(Month, (time_t)tm->tm_mday, Year,
- (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
- MER24, DSTmaybe));
-}
+ register char *p;
+ register char *q;
+ register const TABLE *tp;
+ int i;
+ int abbrev;
+
+ /* Make it lowercase. */
+ for (p = buff; *p; p++)
+ if (ISUPPER ((unsigned char) *p))
+ *p = tolower (*p);
+
+ if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
+ {
+ yylval.Meridian = MERam;
+ return tMERIDIAN;
+ }
+ if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0)
+ {
+ yylval.Meridian = MERpm;
+ return tMERIDIAN;
+ }
+ /* See if we have an abbreviation for a month. */
+ if (strlen (buff) == 3)
+ abbrev = 1;
+ else if (strlen (buff) == 4 && buff[3] == '.')
+ {
+ abbrev = 1;
+ buff[3] = '\0';
+ }
+ else
+ abbrev = 0;
-static int LookupWord(char *buff, int length, YYSTYPE *yylval)
-{
- char *p;
- STRING q;
- TABLE *tp;
- int c;
-
- p = buff;
- c = p[0];
-
- /* See if we have an abbreviation for a month. */
- if (length == 3 || (length == 4 && p[3] == '.'))
- for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) {
- q = tp->name;
- if (c == q[0] && p[1] == q[1] && p[2] == q[2]) {
- yylval->Number = tp->value;
- return tp->type;
- }
+ for (tp = MonthDayTable; tp->name; tp++)
+ {
+ if (abbrev)
+ {
+ if (strncmp (buff, tp->name, 3) == 0)
+ {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+ else if (strcmp (buff, tp->name) == 0)
+ {
+ yylval.Number = tp->value;
+ return tp->type;
}
- else
- for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++)
- if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
- yylval->Number = tp->value;
- return tp->type;
- }
+ }
- /* Try for a timezone. */
- for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
- if (c == tp->name[0] && p[1] == tp->name[1]
- && strcmp(p, tp->name) == 0) {
- yylval->Number = tp->value;
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp (buff, tp->name) == 0)
+ {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ if (strcmp (buff, "dst") == 0)
+ return tDST;
+
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp (buff, tp->name) == 0)
+ {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Strip off any plural and try the units table again. */
+ i = strlen (buff) - 1;
+ if (buff[i] == 's')
+ {
+ buff[i] = '\0';
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp (buff, tp->name) == 0)
+ {
+ yylval.Number = tp->value;
return tp->type;
- }
+ }
+ buff[i] = 's'; /* Put back for "this" in OtherTable. */
+ }
- /* Try the units table. */
- for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
- if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
- yylval->Number = tp->value;
+ for (tp = OtherTable; tp->name; tp++)
+ if (strcmp (buff, tp->name) == 0)
+ {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Military timezones. */
+ if (buff[1] == '\0' && ISALPHA ((unsigned char) *buff))
+ {
+ for (tp = MilitaryTable; tp->name; tp++)
+ if (strcmp (buff, tp->name) == 0)
+ {
+ yylval.Number = tp->value;
return tp->type;
+ }
+ }
+
+ /* Drop out any periods and try the timezone table again. */
+ for (i = 0, p = q = buff; *q; q++)
+ if (*q != '.')
+ *p++ = *q;
+ else
+ i++;
+ *p = '\0';
+ if (i)
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp (buff, tp->name) == 0)
+ {
+ yylval.Number = tp->value;
+ return tp->type;
}
- /* Strip off any plural and try the units table again. */
- if (--length > 0 && p[length] == 's') {
- p[length] = '\0';
- for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++)
- if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
- p[length] = 's';
- yylval->Number = tp->value;
- return tp->type;
- }
- p[length] = 's';
- }
- length++;
+ return tID;
+}
- /* Drop out any periods. */
- for (p = buff, q = (STRING)buff; *q; q++)
- if (*q != '.')
- *p++ = *q;
- *p = '\0';
-
- /* Try the meridians. */
- if (buff[1] == 'm' && buff[2] == '\0') {
- if (buff[0] == 'a') {
- yylval->Meridian = MERam;
- return tMERIDIAN;
- }
- if (buff[0] == 'p') {
- yylval->Meridian = MERpm;
- return tMERIDIAN;
+static int
+yylex ()
+{
+ register unsigned char c;
+ register char *p;
+ char buff[20];
+ int Count;
+ int sign;
+
+ for (;;)
+ {
+ while (ISSPACE ((unsigned char) *yyInput))
+ yyInput++;
+
+ if (ISDIGIT (c = *yyInput) || c == '-' || c == '+')
+ {
+ if (c == '-' || c == '+')
+ {
+ sign = c == '-' ? -1 : 1;
+ if (!ISDIGIT (*++yyInput))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ for (yylval.Number = 0; ISDIGIT (c = *yyInput++);)
+ yylval.Number = 10 * yylval.Number + c - '0';
+ yyInput--;
+ if (sign < 0)
+ yylval.Number = -yylval.Number;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+ if (ISALPHA (c))
+ {
+ for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.';)
+ if (p < &buff[sizeof buff - 1])
+ *p++ = c;
+ *p = '\0';
+ yyInput--;
+ return LookupWord (buff);
}
+ if (c != '(')
+ return *yyInput++;
+ Count = 0;
+ do
+ {
+ c = *yyInput++;
+ if (c == '\0')
+ return c;
+ if (c == '(')
+ Count++;
+ else if (c == ')')
+ Count--;
+ }
+ while (Count > 0);
}
+}
- /* If we saw any periods, try the timezones again. */
- if (p - buff != length) {
- c = buff[0];
- for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++)
- if (c == tp->name[0] && p[1] == tp->name[1]
- && strcmp(p, tp->name) == 0) {
- yylval->Number = tp->value;
- return tp->type;
- }
- }
+#define TM_YEAR_ORIGIN 1900
- /* Unknown word -- assume GMT timezone. */
- yylval->Number = 0;
- return tZONE;
+/* Yield A - B, measured in seconds. */
+static long
+difftm (struct tm *a, struct tm *b)
+{
+ int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+ int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+ long days = (
+ /* difference in day of year */
+ a->tm_yday - b->tm_yday
+ /* + intervening leap days */
+ + ((ay >> 2) - (by >> 2))
+ - (ay / 100 - by / 100)
+ + ((ay / 100 >> 2) - (by / 100 >> 2))
+ /* + difference in years * 365 */
+ + (long) (ay - by) * 365
+ );
+ return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+ + (a->tm_min - b->tm_min))
+ + (a->tm_sec - b->tm_sec));
}
-
-static int date_lex(YYSTYPE *yylval)
+time_t
+parse_date (const char *p, const time_t *now)
{
- char c;
- char *p;
- char buff[20];
- int sign;
- int i;
- int nesting;
-
- for ( ; ; ) {
- /* Get first character after the whitespace. */
- for ( ; ; ) {
- while (CTYPE(isspace, (int)*yyInput))
- yyInput++;
- c = *yyInput;
-
- /* Ignore RFC 822 comments, typically time zone names. */
- if (c != LPAREN)
- break;
- for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; )
- if (c == LPAREN)
- nesting++;
- else if (!IS7BIT(c) || c == '\0' || c == '\r'
- || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c))))
- /* Lexical error: bad comment. */
- return '?';
- yyInput++;
- }
-
- /* A number? */
- if (CTYPE(isdigit, (int)c) || c == '-' || c == '+') {
- if (c == '-' || c == '+') {
- sign = c == '-' ? -1 : 1;
- yyInput++;
- if (!CTYPE(isdigit, (int)*yyInput))
- /* Skip the plus or minus sign. */
- continue;
+ struct tm tm, tm0, *tmp;
+ time_t Start;
+
+ yyInput = p;
+ Start = now ? *now : time ((time_t *) NULL);
+ tmp = localtime (&Start);
+ if (!tmp)
+ return -1;
+ yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
+ yyMonth = tmp->tm_mon + 1;
+ yyDay = tmp->tm_mday;
+ yyHour = tmp->tm_hour;
+ yyMinutes = tmp->tm_min;
+ yySeconds = tmp->tm_sec;
+ tm.tm_isdst = tmp->tm_isdst;
+ yyMeridian = MER24;
+ yyRelSeconds = 0;
+ yyRelMinutes = 0;
+ yyRelHour = 0;
+ yyRelDay = 0;
+ yyRelMonth = 0;
+ yyRelYear = 0;
+ yyHaveDate = 0;
+ yyHaveDay = 0;
+ yyHaveRel = 0;
+ yyHaveTime = 0;
+ yyHaveZone = 0;
+
+ if (yyparse ()
+ || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+ return -1;
+
+ tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear;
+ tm.tm_mon = yyMonth - 1 + yyRelMonth;
+ tm.tm_mday = yyDay + yyRelDay;
+ if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay))
+ {
+ tm.tm_hour = ToHour (yyHour, yyMeridian);
+ if (tm.tm_hour < 0)
+ return -1;
+ tm.tm_min = yyMinutes;
+ tm.tm_sec = yySeconds;
+ }
+ else
+ {
+ tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+ }
+ tm.tm_hour += yyRelHour;
+ tm.tm_min += yyRelMinutes;
+ tm.tm_sec += yyRelSeconds;
+
+ /* Let mktime deduce tm_isdst if we have an absolute timestamp,
+ or if the relative timestamp mentions days, months, or years. */
+ if (yyHaveDate | yyHaveDay | yyHaveTime | yyRelDay | yyRelMonth | yyRelYear)
+ tm.tm_isdst = -1;
+
+ tm0 = tm;
+
+ Start = mktime (&tm);
+
+ if (Start == (time_t) -1)
+ {
+
+ /* Guard against falsely reporting errors near the time_t boundaries
+ when parsing times in other time zones. For example, if the min
+ time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
+ of UTC, then the min localtime value is 1970-01-01 08:00:00; if
+ we apply mktime to 1970-01-01 00:00:00 we will get an error, so
+ we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
+ zone by 24 hours to compensate. This algorithm assumes that
+ there is no DST transition within a day of the time_t boundaries. */
+ if (yyHaveZone)
+ {
+ tm = tm0;
+ if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN)
+ {
+ tm.tm_mday++;
+ yyTimezone -= 24 * 60;
+ }
+ else
+ {
+ tm.tm_mday--;
+ yyTimezone += 24 * 60;
}
- else
- sign = 0;
- for (i = 0; (c = *yyInput++) != '\0' && CTYPE(isdigit, (int)c); )
- i = 10 * i + c - '0';
- yyInput--;
- yylval->Number = sign < 0 ? -i : i;
- return sign ? tSNUMBER : tUNUMBER;
- }
-
- /* A word? */
- if (CTYPE(isalpha, (int)c)) {
- for (p = buff; (c = *yyInput++) == '.' || CTYPE(isalpha, (int)c); )
- if (p < &buff[sizeof buff - 1])
- *p++ = CTYPE(isupper, (int)c) ? tolower(c) : c;
- *p = '\0';
- yyInput--;
- return LookupWord(buff, p - buff, yylval);
+ Start = mktime (&tm);
}
- return *yyInput++;
+ if (Start == (time_t) -1)
+ return Start;
}
-}
-
-time_t parsedate(char *p, TIMEINFO *now)
-{
- struct tm *tm, tmbuf;
- TIMEINFO ti;
- time_t Start;
-
- yyInput = p;
- if (now == NULL) {
- now = &ti;
- (void)GetTimeInfo(&ti);
- }
-
- tm = php_localtime_r(&now->time, &tmbuf);
- yyYear = tm->tm_year + 1900;
- yyMonth = tm->tm_mon + 1;
- yyDay = tm->tm_mday;
-#ifdef HAVE_TM_GMTOFF
- yyTimezone = tm->tm_gmtoff/60;
-#else
- yyTimezone = timezone/60;
-#endif
- yyDSTmode = DSTmaybe;
- yyHour = 0;
- yyMinutes = 0;
- yySeconds = 0;
- yyMeridian = MER24;
- yyRelSeconds = 0;
- yyRelMonth = 0;
- yyHaveDate = 0;
- yyHaveRel = 0;
- yyHaveTime = 0;
+ if (yyHaveDay && !yyHaveDate)
+ {
+ tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7
+ + 7 * (yyDayOrdinal - (0 < yyDayOrdinal)));
+ Start = mktime (&tm);
+ if (Start == (time_t) -1)
+ return Start;
+ }
- if (date_parse(YYPARSE_PARAM_ARG) || yyHaveTime > 1 || yyHaveDate > 1)
+ if (yyHaveZone)
+ {
+ long delta;
+ struct tm *gmt = gmtime (&Start);
+ if (!gmt)
return -1;
+ delta = yyTimezone * 60L + difftm (&tm, gmt);
+ if ((Start + delta < Start) != (delta < 0))
+ return -1; /* time_t overflow */
+ Start += delta;
+ }
- if (yyHaveDate || yyHaveTime) {
- Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
- yyMeridian, yyDSTmode);
- if (Start < 0)
- return -1;
- }
- else {
- Start = now->time;
- if (!yyHaveRel)
- Start -= (tm->tm_hour * 60L + tm->tm_min) * 60L + tm->tm_sec;
- }
-
- Start += yyRelSeconds;
- if (yyRelMonth)
- Start += RelativeMonth(Start, yyRelMonth);
-
- /* Have to do *something* with a legitimate -1 so it's distinguishable
- * from the error return value. (Alternately could set errno on error.) */
- return Start == -1 ? 0 : Start;
+ return Start;
}