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