Skip to content

Commit 521a82e

Browse files
committed
Explicitly expand strftime %Z
1 parent 1295dc4 commit 521a82e

File tree

1 file changed

+40
-5
lines changed

1 file changed

+40
-5
lines changed

ext/date/php_date.c

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,38 @@ PHP_FUNCTION(checkdate)
11581158
}
11591159
/* }}} */
11601160

1161+
/* Explicitly expand stftime %Z format, to make it independent of the TZ environment
1162+
* variable and avoid libc behavior discrepancies. */
1163+
zend_string *strftime_expand_tzname(zend_string *format, const char *tm_zone)
1164+
{
1165+
size_t tm_zone_len = strlen(tm_zone);
1166+
zend_string_addref(format);
1167+
for (size_t i = 0; i < ZSTR_LEN(format);) {
1168+
if (ZSTR_VAL(format)[i] != '%') {
1169+
i++;
1170+
continue;
1171+
}
1172+
1173+
if (ZSTR_VAL(format)[i+1] != 'Z') {
1174+
i += 2;
1175+
continue;
1176+
}
1177+
1178+
zend_string *new_format = zend_string_concat3(
1179+
/* Format string up to %Z */
1180+
ZSTR_VAL(format), i,
1181+
/* The timezone name */
1182+
tm_zone, tm_zone_len,
1183+
/* Format string after %Z */
1184+
ZSTR_VAL(format) + i + 2, ZSTR_LEN(format) - (i + 2)
1185+
);
1186+
zend_string_release(format);
1187+
format = new_format;
1188+
i += tm_zone_len;
1189+
}
1190+
return format;
1191+
}
1192+
11611193
/* {{{ php_strftime - (gm)strftime helper */
11621194
PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
11631195
{
@@ -1171,6 +1203,7 @@ PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
11711203
timelib_tzinfo *tzi;
11721204
timelib_time_offset *offset = NULL;
11731205
zend_string *buf;
1206+
const char *tm_zone;
11741207

11751208
ZEND_PARSE_PARAMETERS_START(1, 2)
11761209
Z_PARAM_STR(format)
@@ -1205,24 +1238,25 @@ PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
12051238
ta.tm_wday = timelib_day_of_week(ts->y, ts->m, ts->d);
12061239
ta.tm_yday = timelib_day_of_year(ts->y, ts->m, ts->d);
12071240
if (gmt) {
1241+
tm_zone = "GMT";
12081242
ta.tm_isdst = 0;
12091243
#if HAVE_STRUCT_TM_TM_GMTOFF
12101244
ta.tm_gmtoff = 0;
1211-
#endif
1212-
#if HAVE_STRUCT_TM_TM_ZONE
1213-
ta.tm_zone = "GMT";
12141245
#endif
12151246
} else {
12161247
offset = timelib_get_time_zone_info(timestamp, tzi);
1248+
tm_zone = offset->abbr;
12171249

12181250
ta.tm_isdst = offset->is_dst;
12191251
#if HAVE_STRUCT_TM_TM_GMTOFF
12201252
ta.tm_gmtoff = offset->offset;
12211253
#endif
1254+
}
12221255
#if HAVE_STRUCT_TM_TM_ZONE
1223-
ta.tm_zone = offset->abbr;
1256+
ta.tm_zone = tm_zone;
12241257
#endif
1225-
}
1258+
1259+
format = strftime_expand_tzname(format, tm_zone);
12261260

12271261
/* VS2012 crt has a bug where strftime crash with %z and %Z format when the
12281262
initial buffer is too small. See
@@ -1243,6 +1277,7 @@ PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
12431277
}
12441278
#endif
12451279

1280+
zend_string_release(format);
12461281
timelib_time_dtor(ts);
12471282
if (!gmt) {
12481283
timelib_time_offset_dtor(offset);

0 commit comments

Comments
 (0)