]> granicus.if.org Git - php/commitdiff
Fixed bug #45543: DateTime::setTimezone can not set timezones without ID.
authorDerick Rethans <github@derickrethans.nl>
Sun, 26 Jan 2014 12:58:13 +0000 (13:58 +0100)
committerDerick Rethans <github@derickrethans.nl>
Sun, 26 Jan 2014 13:01:58 +0000 (14:01 +0100)
ext/date/lib/timelib.h
ext/date/lib/timelib_structs.h
ext/date/lib/unixtime2tm.c
ext/date/php_date.c
ext/date/php_date.h
ext/date/tests/bug45543.phpt [new file with mode: 0644]

index 0396e62cabf794494bdcab3271db419a078639a3..533c88664f9d6e4226837c84af8397cdf9f2a965 100644 (file)
@@ -91,6 +91,8 @@ int timelib_apply_localtime(timelib_time *t, unsigned int localtime);
 void timelib_unixtime2gmt(timelib_time* tm, timelib_sll ts);
 void timelib_unixtime2local(timelib_time *tm, timelib_sll ts);
 void timelib_update_from_sse(timelib_time *tm);
+void timelib_set_timezone_from_offset(timelib_time *t, timelib_sll utc_offset);
+void timelib_set_timezone_from_abbr(timelib_time *t, timelib_abbr_info abbr_info);
 void timelib_set_timezone(timelib_time *t, timelib_tzinfo *tz);
 
 /* From parse_tz.c */
index 2648c52e6652a8421326dd870e24ef0bc7b43fc2..5185e7b40b6ac1fae93740929dcf47f309c2cc87 100644 (file)
@@ -172,6 +172,12 @@ typedef struct timelib_time {
                                      *  2 TimeZone abbreviation */
 } timelib_time;
 
+typedef struct timelib_abbr_info {
+       timelib_sll  utc_offset;
+       char        *abbr;
+       int          dst;
+} timelib_abbr_info;
+
 typedef struct timelib_error_message {
        int         position;
        char        character;
index eefbaa8f373c60b02124b3457ebfa958da1bc995..9870313fbce8c99af71b76254ef5d02b5a938482 100644 (file)
@@ -214,6 +214,34 @@ void timelib_unixtime2local(timelib_time *tm, timelib_sll ts)
        tm->have_zone = 1;
 }
 
+void timelib_set_timezone_from_offset(timelib_time *t, timelib_sll utc_offset)
+{
+       if (t->tz_abbr) {
+               free(t->tz_abbr);
+       }
+       t->tz_abbr = NULL;
+
+       t->z = utc_offset;
+       t->have_zone = 1;
+       t->zone_type = TIMELIB_ZONETYPE_OFFSET;
+       t->dst = 0;
+       t->tz_info = NULL;
+}
+
+void timelib_set_timezone_from_abbr(timelib_time *t, timelib_abbr_info abbr_info)
+{
+       if (t->tz_abbr) {
+               free(t->tz_abbr);
+       }
+       t->tz_abbr = strdup(abbr_info.abbr);
+
+       t->z = abbr_info.utc_offset;
+       t->have_zone = 1;
+       t->zone_type = TIMELIB_ZONETYPE_ABBR;
+       t->dst = abbr_info.dst;
+       t->tz_info = NULL;
+}
+
 void timelib_set_timezone(timelib_time *t, timelib_tzinfo *tz)
 {
        timelib_time_offset *gmt_offset;
index 1655057212a3ab406b6a26b307a9b4ba42653d03..c0566334db4895498b55b1cd39e98241b1da64be 100644 (file)
@@ -2992,11 +2992,18 @@ PHP_FUNCTION(date_timezone_set)
        dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
        DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
        tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
-       if (tzobj->type != TIMELIB_ZONETYPE_ID) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only do this for zones with ID for now");
-               return;
+
+       switch (tzobj->type) {
+               case TIMELIB_ZONETYPE_OFFSET:
+                       timelib_set_timezone_from_offset(dateobj->time, tzobj->tzi.utc_offset);
+                       break;
+               case TIMELIB_ZONETYPE_ABBR:
+                       timelib_set_timezone_from_abbr(dateobj->time, tzobj->tzi.z);
+                       break;
+               case TIMELIB_ZONETYPE_ID:
+                       timelib_set_timezone(dateobj->time, tzobj->tzi.tz);
+                       break;
        }
-       timelib_set_timezone(dateobj->time, tzobj->tzi.tz);
        timelib_unixtime2local(dateobj->time, dateobj->time->sse);
 
        RETURN_ZVAL(object, 1, 0);
index 1d6a94d0ae705d999721769c056cdb9a4632dde9..4ce730bb2ba4421018321ac4db3345aa7e104296 100644 (file)
@@ -122,14 +122,9 @@ struct _php_timezone_obj {
        int             initialized;
        int             type;
        union {
-               timelib_tzinfo *tz; /* TIMELIB_ZONETYPE_ID; */
-               timelib_sll     utc_offset; /* TIMELIB_ZONETYPE_OFFSET */
-               struct                      /* TIMELIB_ZONETYPE_ABBR */
-               {
-                       timelib_sll  utc_offset;
-                       char        *abbr;
-                       int          dst;
-               } z;
+               timelib_tzinfo   *tz;         /* TIMELIB_ZONETYPE_ID */
+               timelib_sll       utc_offset; /* TIMELIB_ZONETYPE_OFFSET */
+               timelib_abbr_info z;          /* TIMELIB_ZONETYPE_ABBR */
        } tzi;
 };
 
diff --git a/ext/date/tests/bug45543.phpt b/ext/date/tests/bug45543.phpt
new file mode 100644 (file)
index 0000000..8e36e62
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+Test for bug #45543: DateTime::setTimezone can not set timezones without ID.
+--INI--
+date.timezone=UTC
+--FILE--
+<?php
+$test_dates = array(
+       '2008-01-01 12:00:00 PDT',
+       '2008-01-01 12:00:00 +02:00',
+);
+
+foreach ($test_dates as $test_date)
+{
+       $d1 = new DateTime($test_date);
+       $d2 = new DateTime('2008-01-01 12:00:00 UTC');
+       echo $d1->format(DATE_ISO8601), PHP_EOL;
+       echo $d2->format(DATE_ISO8601), PHP_EOL;
+       $tz = $d1->getTimeZone();
+       $d2->setTimeZone($tz);
+       echo $d1->format(DATE_ISO8601), PHP_EOL;
+       echo $d2->format(DATE_ISO8601), PHP_EOL;
+       echo PHP_EOL;
+}
+--EXPECT--
+2008-01-01T12:00:00-0700
+2008-01-01T12:00:00+0000
+2008-01-01T12:00:00-0700
+2008-01-01T05:00:00-0700
+
+2008-01-01T12:00:00+0200
+2008-01-01T12:00:00+0000
+2008-01-01T12:00:00+0200
+2008-01-01T14:00:00+0200
+