@@ -9,7 +9,7 @@ use strict;
99
1010use Config;
1111use POSIX;
12- use Test::More tests => 31 ;
12+ use Test::More tests => 49 ;
1313
1414# For the first go to UTC to avoid DST issues around the world when testing. SUS3 says that
1515# null should get you UTC, but some environments want the explicit names.
@@ -226,3 +226,66 @@ SKIP: {
226226 is(strftime(undef , CORE::localtime ), ' ' , " strftime() works if format is undef" );
227227 like($warnings , qr / ^Use of uninitialized value in subroutine entry / , " strftime(undef, ...) produces expected warning" );
228228}
229+
230+ SKIP: { # GH #23878; test that dst fall back works properly
231+ my $skip_count = 9;
232+ skip " No mktime()" , $skip_count if $Config {d_mktime } ne ' define' ;
233+ my $locale = " Europe/Paris" ;
234+ $ENV {TZ } = $locale ;
235+ my $t = 1761436800; # an hour before time should have changed
236+
237+ # The time in the first test case is such that UTC gives a different day.
238+ # If the locale above is unknown, libc is supposed to use UTC; so that's
239+ # how we check if the system knows about the rules for Paris; which on
240+ # some systems differ from plain CET-1CEST.
241+ skip " '$locale ' not understood" , $skip_count if
242+ POSIX::strftime(" %F %T%z " , localtime ($t - 1)) !~ / 2025-10-26/ ;
243+
244+ # On Windows, the documentation says that it won't understand what our
245+ # $locale is set to, but instead of falling back to UTC, it uses the
246+ # system timezone, or U.S. Pacific time. The trick above therefore
247+ # doesn't work, so just skip this batch of tests.
248+ skip " '$locale ' not understood" , $skip_count if $^O eq " MSWin32" ;
249+
250+ my @fall = (
251+ [ -1, " 2025-10-26 01:59:59+0200" , " Chg -1 hr, 1 sec" ],
252+ [ 0, " 2025-10-26 02:00:00+0200" , " Chg -1 hr, 0 sec" ],
253+ [ 1, " 2025-10-26 02:00:01+0200" , " Chg -59 min, 59 sec" ],
254+ [ 3599, " 2025-10-26 02:59:59+0200" , " Chg -1 sec" ],
255+ [ 3600, " 2025-10-26 02:00:00+0100" , " At Paris DST fallback" ],
256+ [ 3601, " 2025-10-26 02:00:01+0100" , " Chg +1 sec" ],
257+ [ 7199, " 2025-10-26 02:59:59+0100" , " Chg +1 hr, 59m, 59s" ],
258+ [ 7200, " 2025-10-26 03:00:00+0100" , " Chg +1 hr" ],
259+ [ 7201, " 2025-10-26 03:00:01+0100" , " Chg +1 hr, 1 sec" ],
260+ );
261+ for (my $i = 0; $i < @fall ; $i ++) {
262+ is(POSIX::strftime(" %F %T%z " , localtime $t + $fall [$i ][0]),
263+ $fall [$i ][1], $fall [$i ][2]);
264+ }
265+ }
266+
267+ SKIP: { # GH #23878: test that dst spring forward works properly; use a
268+ # locale that MS narcissism should be able to handle
269+ my $skip_count = 9;
270+ skip " No mktime()" , $skip_count if $Config {d_mktime } ne ' define' ;
271+ my $locale = " PST8PDT" ;
272+ $ENV {TZ } = $locale ;
273+ my $t = 1741510800; # an hour before time should have changed
274+
275+ my @spring = (
276+ [ -1, " 2025-03-09 00:59:59-0800" , " Chg -1 hr, 1 sec" ],
277+ [ 0, " 2025-03-09 01:00:00-0800" , " Chg -1 hr, 0 sec" ],
278+ [ 1, " 2025-03-09 01:00:01-0800" , " Chg -59 min, 59 sec" ],
279+ [ 3599, " 2025-03-09 01:59:59-0800" , " Chg -1 sec" ],
280+ [ 3600, " 2025-03-09 03:00:00-0700" ,
281+ " At Redmond DST spring forward" ],
282+ [ 3601, " 2025-03-09 03:00:01-0700" , " Chg +1 sec" ],
283+ [ 7199, " 2025-03-09 03:59:59-0700" , " Chg +1 hr, 59m, 59s" ],
284+ [ 7200, " 2025-03-09 04:00:00-0700" , " Chg +1 hr" ],
285+ [ 7201, " 2025-03-09 04:00:01-0700" , " Chg +1 hr, 1 sec" ],
286+ );
287+ for (my $i = 0; $i < @spring ; $i ++) {
288+ is(POSIX::strftime(" %F %T%z " , localtime $t + $spring [$i ][0]),
289+ $spring [$i ][1], $spring [$i ][2]);
290+ }
291+ }
0 commit comments