Skip to content

Commit 22dba2f

Browse files
committed
Fixed bug #45543: DateTime::setTimezone can not set timezones without ID.
1 parent 4e308ab commit 22dba2f

File tree

6 files changed

+84
-12
lines changed

6 files changed

+84
-12
lines changed

ext/date/lib/timelib.h

+2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ int timelib_apply_localtime(timelib_time *t, unsigned int localtime);
9191
void timelib_unixtime2gmt(timelib_time* tm, timelib_sll ts);
9292
void timelib_unixtime2local(timelib_time *tm, timelib_sll ts);
9393
void timelib_update_from_sse(timelib_time *tm);
94+
void timelib_set_timezone_from_offset(timelib_time *t, timelib_sll utc_offset);
95+
void timelib_set_timezone_from_abbr(timelib_time *t, timelib_abbr_info abbr_info);
9496
void timelib_set_timezone(timelib_time *t, timelib_tzinfo *tz);
9597

9698
/* From parse_tz.c */

ext/date/lib/timelib_structs.h

+6
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,12 @@ typedef struct timelib_time {
172172
* 2 TimeZone abbreviation */
173173
} timelib_time;
174174

175+
typedef struct timelib_abbr_info {
176+
timelib_sll utc_offset;
177+
char *abbr;
178+
int dst;
179+
} timelib_abbr_info;
180+
175181
typedef struct timelib_error_message {
176182
int position;
177183
char character;

ext/date/lib/unixtime2tm.c

+28
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,34 @@ void timelib_unixtime2local(timelib_time *tm, timelib_sll ts)
214214
tm->have_zone = 1;
215215
}
216216

217+
void timelib_set_timezone_from_offset(timelib_time *t, timelib_sll utc_offset)
218+
{
219+
if (t->tz_abbr) {
220+
free(t->tz_abbr);
221+
}
222+
t->tz_abbr = NULL;
223+
224+
t->z = utc_offset;
225+
t->have_zone = 1;
226+
t->zone_type = TIMELIB_ZONETYPE_OFFSET;
227+
t->dst = 0;
228+
t->tz_info = NULL;
229+
}
230+
231+
void timelib_set_timezone_from_abbr(timelib_time *t, timelib_abbr_info abbr_info)
232+
{
233+
if (t->tz_abbr) {
234+
free(t->tz_abbr);
235+
}
236+
t->tz_abbr = strdup(abbr_info.abbr);
237+
238+
t->z = abbr_info.utc_offset;
239+
t->have_zone = 1;
240+
t->zone_type = TIMELIB_ZONETYPE_ABBR;
241+
t->dst = abbr_info.dst;
242+
t->tz_info = NULL;
243+
}
244+
217245
void timelib_set_timezone(timelib_time *t, timelib_tzinfo *tz)
218246
{
219247
timelib_time_offset *gmt_offset;

ext/date/php_date.c

+11-4
Original file line numberDiff line numberDiff line change
@@ -2992,11 +2992,18 @@ PHP_FUNCTION(date_timezone_set)
29922992
dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
29932993
DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
29942994
tzobj = (php_timezone_obj *) zend_object_store_get_object(timezone_object TSRMLS_CC);
2995-
if (tzobj->type != TIMELIB_ZONETYPE_ID) {
2996-
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only do this for zones with ID for now");
2997-
return;
2995+
2996+
switch (tzobj->type) {
2997+
case TIMELIB_ZONETYPE_OFFSET:
2998+
timelib_set_timezone_from_offset(dateobj->time, tzobj->tzi.utc_offset);
2999+
break;
3000+
case TIMELIB_ZONETYPE_ABBR:
3001+
timelib_set_timezone_from_abbr(dateobj->time, tzobj->tzi.z);
3002+
break;
3003+
case TIMELIB_ZONETYPE_ID:
3004+
timelib_set_timezone(dateobj->time, tzobj->tzi.tz);
3005+
break;
29983006
}
2999-
timelib_set_timezone(dateobj->time, tzobj->tzi.tz);
30003007
timelib_unixtime2local(dateobj->time, dateobj->time->sse);
30013008

30023009
RETURN_ZVAL(object, 1, 0);

ext/date/php_date.h

+3-8
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,9 @@ struct _php_timezone_obj {
122122
int initialized;
123123
int type;
124124
union {
125-
timelib_tzinfo *tz; /* TIMELIB_ZONETYPE_ID; */
126-
timelib_sll utc_offset; /* TIMELIB_ZONETYPE_OFFSET */
127-
struct /* TIMELIB_ZONETYPE_ABBR */
128-
{
129-
timelib_sll utc_offset;
130-
char *abbr;
131-
int dst;
132-
} z;
125+
timelib_tzinfo *tz; /* TIMELIB_ZONETYPE_ID */
126+
timelib_sll utc_offset; /* TIMELIB_ZONETYPE_OFFSET */
127+
timelib_abbr_info z; /* TIMELIB_ZONETYPE_ABBR */
133128
} tzi;
134129
};
135130

ext/date/tests/bug45543.phpt

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
Test for bug #45543: DateTime::setTimezone can not set timezones without ID.
3+
--INI--
4+
date.timezone=UTC
5+
--FILE--
6+
<?php
7+
$test_dates = array(
8+
'2008-01-01 12:00:00 PDT',
9+
'2008-01-01 12:00:00 +02:00',
10+
);
11+
12+
foreach ($test_dates as $test_date)
13+
{
14+
$d1 = new DateTime($test_date);
15+
$d2 = new DateTime('2008-01-01 12:00:00 UTC');
16+
echo $d1->format(DATE_ISO8601), PHP_EOL;
17+
echo $d2->format(DATE_ISO8601), PHP_EOL;
18+
$tz = $d1->getTimeZone();
19+
$d2->setTimeZone($tz);
20+
echo $d1->format(DATE_ISO8601), PHP_EOL;
21+
echo $d2->format(DATE_ISO8601), PHP_EOL;
22+
echo PHP_EOL;
23+
}
24+
--EXPECT--
25+
2008-01-01T12:00:00-0700
26+
2008-01-01T12:00:00+0000
27+
2008-01-01T12:00:00-0700
28+
2008-01-01T05:00:00-0700
29+
30+
2008-01-01T12:00:00+0200
31+
2008-01-01T12:00:00+0000
32+
2008-01-01T12:00:00+0200
33+
2008-01-01T14:00:00+0200
34+

0 commit comments

Comments
 (0)