moriyoshi Mon Mar 1 05:42:29 2004 EDT Modified files: /php-src/ext/standard parsedate.y /php-src/ext/standard/tests/time 002.phpt Log: - Add support for more ISO8601 style formats. . Timezone specifier (ex. 20040301T00:00:00+1900) . Week specifier "W" (ex. 1997W021) - Modified test case to test new features.
http://cvs.php.net/diff.php/php-src/ext/standard/parsedate.y?r1=1.51&r2=1.52&ty=u Index: php-src/ext/standard/parsedate.y diff -u php-src/ext/standard/parsedate.y:1.51 php-src/ext/standard/parsedate.y:1.52 --- php-src/ext/standard/parsedate.y:1.51 Fri Dec 19 07:43:39 2003 +++ php-src/ext/standard/parsedate.y Mon Mar 1 05:42:27 2004 @@ -8,7 +8,7 @@ ** This code is in the public domain and has no copyright. */ -/* $Id: parsedate.y,v 1.51 2003/12/19 12:43:39 wez Exp $ */ +/* $Id: parsedate.y,v 1.52 2004/03/01 10:42:27 moriyoshi Exp $ */ #include "php.h" @@ -151,17 +151,17 @@ static int yylex (YYSTYPE *lvalp, void *parm); %} -/* This grammar has 22 shift/reduce conflicts. */ -%expect 22 +/* This grammar has 24 shift/reduce conflicts. */ +%expect 36 %pure_parser -%token tAGO tDAY tDAY_UNIT tDAYZONE tDST tHOUR_UNIT tID tTZONE tZZONE +%token tAGO tDAY tDAY_UNIT tDAYZONE tDST tHOUR_UNIT tID tTZONE tWZONE tZZONE %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 tTZONE tZZONE +%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tYEAR_UNIT tZONE tTZONE tWZONE tZZONE %type <Meridian> tMERIDIAN %% @@ -195,71 +195,66 @@ ((struct date_yy *)parm)->yySeconds = 0; ((struct date_yy *)parm)->yyMeridian = $2; } - | tUNUMBER ':' tUNUMBER { - ((struct date_yy *)parm)->yyHour = $1; - ((struct date_yy *)parm)->yyMinutes = $3; - ((struct date_yy *)parm)->yySeconds = 0; + | iso8601time_colon + /* | pgsqltime ... shares a common spec with ISO8601 */ + ; + +iso8601time_colon: HMStime_with_colon sec_fraction_part iso8601zonepart { + ((struct date_yy *)parm)->yyMeridian = MER24; } - | tUNUMBER ':' tUNUMBER tSNUMBER { - ((struct date_yy *)parm)->yyHour = $1; - ((struct date_yy *)parm)->yyMinutes = $3; + | HMtime_with_colon sec_fraction_part iso8601zonepart { + ((struct date_yy *)parm)->yySeconds = 0; ((struct date_yy *)parm)->yyMeridian = MER24; - ((struct date_yy *)parm)->yyHaveZone++; - ((struct date_yy *)parm)->yyTimezone = ($4 < 0 - ? -$4 % 100 + (-$4 / 100) * 60 - : - ($4 % 100 + ($4 / 100) * 60)); } - | tUNUMBER ':' tUNUMBER ':' tUNUMBER { - ((struct date_yy *)parm)->yyHour = $1; - ((struct date_yy *)parm)->yyMinutes = $3; - ((struct date_yy *)parm)->yySeconds = $5; + ; + +iso8601zonepart: zonepart_numeric_without_colon { + ((struct date_yy *)parm)->yyHaveZone++; } - | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { - /* ISO 8601 format. hh:mm:ss[+-][0-9]{2}([0-9]{2})?. */ - ((struct date_yy *)parm)->yyHour = $1; - ((struct date_yy *)parm)->yyMinutes = $3; - ((struct date_yy *)parm)->yySeconds = $5; - ((struct date_yy *)parm)->yyMeridian = MER24; - ((struct date_yy *)parm)->yyHaveZone++; - if ($6 <= -100 || $6 >= 100) { - ((struct date_yy *)parm)->yyTimezone = - -$6 % 100 + (-$6 / 100) * 60; - } else { - ((struct date_yy *)parm)->yyTimezone = -$6 * 60; - } - } - | tUNUMBER ':' tUNUMBER ':' tUNUMBER '.' tUNUMBER pgsqlzonepart { - ((struct date_yy *)parm)->yyHour = $1; - ((struct date_yy *)parm)->yyMinutes = $3; - ((struct date_yy *)parm)->yySeconds = $5; - ((struct date_yy *)parm)->yyMeridian = MER24; + | zonepart_numeric_with_colon { + ((struct date_yy *)parm)->yyHaveZone++; + } + | zone { + ((struct date_yy *)parm)->yyHaveZone++; } + | /* empty */ ; -iso8601time: tUNUMBER ':' tUNUMBER ':' tUNUMBER { - ((struct date_yy *)parm)->yyHour = $1; - ((struct date_yy *)parm)->yyMinutes = $3; - ((struct date_yy *)parm)->yySeconds = $5; - ((struct date_yy *)parm)->yyMeridian = MER24; - } - ; - +sec_fraction_part: '.' tUNUMBER { + } + | /* empty */ + ; -pgsqlzonepart : tSNUMBER { - ((struct date_yy *)parm)->yyHaveZone++; +zonepart_numeric_without_colon: tSNUMBER { + /* format: [+-]hhmm */ if ($1 <= -100 || $1 >= 100) { - ((struct date_yy *)parm)->yyTimezone = - -$1 % 100 + (-$1 / 100) * 60; - } else { - ((struct date_yy *)parm)->yyTimezone = -$1 * 60; + ((struct date_yy *)parm)->yyTimezone = (-$1 / 100) * 60 + (-$1 % 100); + } else if ($1 >= -99 || $1 <= 99) { + ((struct date_yy *)parm)->yyTimezone = -$1 * 60; } } - | zone { - ((struct date_yy *)parm)->yyHaveZone++; + ; + +zonepart_numeric_with_colon: tSNUMBER ':' tUNUMBER { + /* format: [+-]hh:mm */ + ((struct date_yy *)parm)->yyTimezone = -$1 * 60 + ($1 > 0 ? -$3: $3); } - | /* empty */ ; +HMStime_with_colon: HMtime_with_colon ':' tUNUMBER { + /* format: hh:mm:ss */ + ((struct date_yy *)parm)->yySeconds = $3; + } + ; + +HMtime_with_colon: tUNUMBER ':' tUNUMBER { + /* format: hh:mm */ + ((struct date_yy *)parm)->yyHour = $1; + ((struct date_yy *)parm)->yyMinutes = $3; + } + ; + + /* we have to deal with a special case for the datetime format of XML Schema here: '2003-11-18T22:40:00Z' the combination of a 'T' timezone specifier later followed @@ -271,6 +266,9 @@ zone : tTZONE { ((struct date_yy *)parm)->yyTimezone = $1; } + | tWZONE { + ((struct date_yy *)parm)->yyTimezone = $1; + } | tZZONE { ((struct date_yy *)parm)->yyTimezone = $1; } @@ -280,8 +278,7 @@ | tDAYZONE { ((struct date_yy *)parm)->yyTimezone = $1 - 60; } - | - tZONE tDST { + | tZONE tDST { ((struct date_yy *)parm)->yyTimezone = $1 - 60; } ; @@ -335,13 +332,6 @@ } | iso8601date | iso8601datetime { - ((struct date_yy *)parm)->yyTimezone = 0; - ((struct date_yy *)parm)->yyHaveZone++; - ((struct date_yy *)parm)->yyHaveTime++; - } - | iso8601datetime tZZONE { - ((struct date_yy *)parm)->yyTimezone = 0; - ((struct date_yy *)parm)->yyHaveZone++; ((struct date_yy *)parm)->yyHaveTime++; } | tUNUMBER tMONTH tSNUMBER { @@ -384,7 +374,23 @@ ; iso8601datetime: iso8601date tTZONE iso8601time - ; + | tUNUMBER tTZONE iso8601time { + int i = $1; + + if (i >= 10000) { + /* format: yyyymmdd */ + ((struct date_yy *)parm)->yyYear = i / 10000; + i %= 10000; + ((struct date_yy *)parm)->yyMonth = i / 100; + i %= 100; + ((struct date_yy *)parm)->yyDay = i; + } else if (i >= 1000 && i <= 9999) { + /* format: yyyy */ + ((struct date_yy *)parm)->yyYear = i; + ((struct date_yy *)parm)->yyDay= 1; + ((struct date_yy *)parm)->yyMonth = 1; + } + } iso8601date: tUNUMBER tSNUMBER tSNUMBER { /* ISO 8601 format. yyyy-mm-dd. */ @@ -392,8 +398,59 @@ ((struct date_yy *)parm)->yyMonth = -$2; ((struct date_yy *)parm)->yyDay = -$3; } + | tUNUMBER tSNUMBER { + /* ISO 8601 format yyyy-mm */ + ((struct date_yy *)parm)->yyYear = $1; + ((struct date_yy *)parm)->yyMonth = -$2; + ((struct date_yy *)parm)->yyDay = 1; + } + | tUNUMBER iso8601weekspec { + const int om = (1 + 9) % 12; /* offset month */ + const int oy = $1 - 1; /* offset year */ + + ((struct date_yy *)parm)->yyYear = $1; + ((struct date_yy *)parm)->yyMonth = 1; + /* Zeller's formula */ + ((struct date_yy *)parm)->yyDay -= ((13 * om + 12) / 5 + + oy + oy / 4 + oy / 400 - oy / 100) % 7 - 1; + } ; +iso8601weekspec: tWZONE tUNUMBER { + ((struct date_yy *)parm)->yyDay = ($2 / 10) * 7 + ($2 % 10) - 8; + } + | tWZONE tUNUMBER tSNUMBER { + ((struct date_yy *)parm)->yyDay = $2 * 7 - $3 - 8; + } + ; + +iso8601time: + iso8601time_colon + | tUNUMBER sec_fraction_part iso8601zonepart { + int i = $1; + + if (i <= -100000 || i >= 100000) { + ((struct date_yy *)parm)->yyHour = i / 10000; + i %= 10000; + ((struct date_yy *)parm)->yyMinutes = i / 100; + i %= 100; + ((struct date_yy *)parm)->yySeconds = i; + } else if (i <= -1000 || i >= 1000) { + ((struct date_yy *)parm)->yyHour = i / 100; + i %= 100; + ((struct date_yy *)parm)->yyMinutes = i; + ((struct date_yy *)parm)->yySeconds = 0; + } else if (i >= -99 || i <= 99) { + ((struct date_yy *)parm)->yyHour = $1; + ((struct date_yy *)parm)->yyMinutes = 0; + ((struct date_yy *)parm)->yySeconds = 0; + } else { + ((struct date_yy *)parm)->yyHaveTime = 0; + } + ((struct date_yy *)parm)->yyMeridian = MER24; + } + ; + rel : relunit tAGO { ((struct date_yy *)parm)->yyRelSeconds = -((struct date_yy *)parm)->yyRelSeconds; @@ -697,7 +754,7 @@ { "t", tTZONE, HOUR ( 7) }, { "u", tZONE, HOUR ( 8) }, { "v", tZONE, HOUR ( 9) }, - { "w", tZONE, HOUR ( 10) }, + { "w", tWZONE, HOUR ( 10) }, { "x", tZONE, HOUR ( 11) }, { "y", tZONE, HOUR ( 12) }, { "z", tZZONE, HOUR ( 0) }, http://cvs.php.net/diff.php/php-src/ext/standard/tests/time/002.phpt?r1=1.11&r2=1.12&ty=u Index: php-src/ext/standard/tests/time/002.phpt diff -u php-src/ext/standard/tests/time/002.phpt:1.11 php-src/ext/standard/tests/time/002.phpt:1.12 --- php-src/ext/standard/tests/time/002.phpt:1.11 Tue Sep 9 17:56:33 2003 +++ php-src/ext/standard/tests/time/002.phpt Mon Mar 1 05:42:28 2004 @@ -25,14 +25,22 @@ "2001-10-22 21:19:58-02", "2001-10-22 21:19:58-0213", "2001-10-22 21:19:58+02", - "2001-10-22 21:19:58+0213" + "2001-10-22 21:19:58+0213", + "2001-10-22T21:20:58-03:40", + "2001-10-22T211958-2", + "20011022T211958+0213", + "20011022T21:20+0215", + "1997W011", + "2004W101T05:00+0", ); + echo "*** GMT0\n"; putenv ("TZ=GMT0"); foreach ($dates as $date) { echo date ("Y-m-d H:i:s\n", strtotime ($date)); } + echo "*** US/Eastern\n"; putenv("TZ=US/Eastern"); if( date("T") == "GMT" ) { // POSIX style @@ -44,6 +52,7 @@ } ?> --EXPECT-- +*** GMT0 1999-10-13 00:00:00 1999-10-13 00:00:00 2000-01-19 00:00:00 @@ -58,6 +67,13 @@ 2001-10-22 23:32:58 2001-10-22 19:19:58 2001-10-22 19:06:58 +2001-10-23 01:00:58 +2001-10-22 23:19:58 +2001-10-22 19:06:58 +2001-10-22 19:05:00 +1996-12-30 00:00:00 +2004-03-01 05:00:00 +*** US/Eastern 1999-10-13 00:00:00 1999-10-13 00:00:00 2000-01-19 00:00:00 @@ -72,3 +88,9 @@ 2001-10-22 19:32:58 2001-10-22 15:19:58 2001-10-22 15:06:58 +2001-10-22 21:00:58 +2001-10-22 19:19:58 +2001-10-22 15:06:58 +2001-10-22 15:05:00 +1996-12-30 00:00:00 +2004-03-01 00:00:00
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php