@@ -1158,6 +1158,38 @@ PHP_FUNCTION(checkdate)
1158
1158
}
1159
1159
/* }}} */
1160
1160
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
+
1161
1193
/* {{{ php_strftime - (gm)strftime helper */
1162
1194
PHPAPI void php_strftime (INTERNAL_FUNCTION_PARAMETERS , int gmt )
1163
1195
{
@@ -1171,6 +1203,7 @@ PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
1171
1203
timelib_tzinfo * tzi ;
1172
1204
timelib_time_offset * offset = NULL ;
1173
1205
zend_string * buf ;
1206
+ const char * tm_zone ;
1174
1207
1175
1208
ZEND_PARSE_PARAMETERS_START (1 , 2 )
1176
1209
Z_PARAM_STR (format )
@@ -1205,24 +1238,25 @@ PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
1205
1238
ta .tm_wday = timelib_day_of_week (ts -> y , ts -> m , ts -> d );
1206
1239
ta .tm_yday = timelib_day_of_year (ts -> y , ts -> m , ts -> d );
1207
1240
if (gmt ) {
1241
+ tm_zone = "GMT" ;
1208
1242
ta .tm_isdst = 0 ;
1209
1243
#if HAVE_STRUCT_TM_TM_GMTOFF
1210
1244
ta .tm_gmtoff = 0 ;
1211
- #endif
1212
- #if HAVE_STRUCT_TM_TM_ZONE
1213
- ta .tm_zone = "GMT" ;
1214
1245
#endif
1215
1246
} else {
1216
1247
offset = timelib_get_time_zone_info (timestamp , tzi );
1248
+ tm_zone = offset -> abbr ;
1217
1249
1218
1250
ta .tm_isdst = offset -> is_dst ;
1219
1251
#if HAVE_STRUCT_TM_TM_GMTOFF
1220
1252
ta .tm_gmtoff = offset -> offset ;
1221
1253
#endif
1254
+ }
1222
1255
#if HAVE_STRUCT_TM_TM_ZONE
1223
- ta .tm_zone = offset -> abbr ;
1256
+ ta .tm_zone = tm_zone ;
1224
1257
#endif
1225
- }
1258
+
1259
+ format = strftime_expand_tzname (format , tm_zone );
1226
1260
1227
1261
/* VS2012 crt has a bug where strftime crash with %z and %Z format when the
1228
1262
initial buffer is too small. See
@@ -1243,6 +1277,7 @@ PHPAPI void php_strftime(INTERNAL_FUNCTION_PARAMETERS, int gmt)
1243
1277
}
1244
1278
#endif
1245
1279
1280
+ zend_string_release (format );
1246
1281
timelib_time_dtor (ts );
1247
1282
if (!gmt ) {
1248
1283
timelib_time_offset_dtor (offset );
0 commit comments