Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
/perl5Public

Commit4c99243

Browse files
committed
Fix POSIX::strftime()
This fixes GH#22351The new sv_strftime_ints() API function acts consistently with regardsto daylight savings time, with POSIX-mandated behavior, which takes thecurrent locale into account.POSIX::strftime() is problematic in regard to this. This commit adds abackwards compatibility mode to preserve its behavior that inadvertentlywas changed by86a9c18.These functions are intended to wrap libc strftime(), includingnormalizing the input values. For example, if you pass 63 seconds as avalue, they will typically change that to be 3 seconds into the nextminute up. In C, the mktime() function is typically called first to dothat normalization. (I don't know what happens if plain strftime() iscalled with unnormalized values.). mktime() looks at the currentlocale, determines if daylight savings time is in effect, and adjustsaccordingly. Perl calls its own mktime-equivalent for you, eliminatingthe need for explicitly calling something that would need to always becalled anyway, hence saving an extra step.mini_mktime() is the Perl mktime-equivalent. It is unaffected bylocales, and does not consider the possibility of there being daylightsavings time. The problem is that libc strftime() is affected bylocale, and does consider dst. Perl uses these two functions together,and this inconsistency between them is bound to cause problems.The 'isdst' parameter to POSIX::strftime() is used to indicate ifdaylight savings is in effect for the time and date given by the otherparameters. If perl used mktime() to normalize those values, it wouldcalculate this for itself, using the passed-in value only as a hint.But since it uses mini_mktime(), it has to take that value as-is.Thus, daylight savings alone, out of all the input values, is notnormalized. This is contrary to the documentation, and I didn't knowthis when I wrote the blamed commit.It turns out that typical uses of this function, like POSIX::strftime('%s', localtime) POSIX::strftime('%s', gmtime)cause the correct 'isdst' to be passed. But this is a defect in theinterface that can bite you; changing it would cause cpan breakage.I wrote the API function sv_strftime_ints() to not have these issues.And, to workaround a defect in the POSIX definition of mktime(). Itturns out you can't tell it you don't want to adjust for dayight time,except by changing the locale to one that doesn't have dst, such as the"C" locale. But this isn't a Perl-level function.
1 parentf3d3dcc commit4c99243

File tree

4 files changed

+54
-17
lines changed

4 files changed

+54
-17
lines changed

‎ext/POSIX/POSIX.xs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3588,7 +3588,7 @@ difftime(time1, time2)
35883588
# sv_setpv(TARG, ...) could be used rather than
35893589
# ST(0) = sv_2mortal(newSVpv(...))
35903590
void
3591-
strftime(fmt,sec,min,hour,mday,mon,year,wday=-1,yday=-1,isdst=-1)
3591+
strftime(fmt,sec,min,hour,mday,mon,year,wday=-1,yday=-1,isdst=0)
35923592
SV*fmt
35933593
intsec
35943594
intmin
@@ -3603,9 +3603,11 @@ strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1)
36033603
{
36043604
PERL_UNUSED_ARG(wday);
36053605
PERL_UNUSED_ARG(yday);
3606-
PERL_UNUSED_ARG(isdst);
36073606

3608-
SV*sv=sv_strftime_ints(fmt,sec,min,hour,mday,mon,year,0);
3607+
/* -isdst triggers backwards compatibility mode for non-zero
3608+
* 'isdst' */
3609+
SV*sv=sv_strftime_ints(fmt,sec,min,hour,mday,mon,year,
3610+
-abs(isdst));
36093611
if (sv) {
36103612
sv=sv_2mortal(sv);
36113613
}

‎ext/POSIX/lib/POSIX.pod

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1872,15 +1872,19 @@ Returns the string.
18721872
Synopsis:
18731873

18741874
strftime(fmt, sec, min, hour, mday, mon, year,
1875-
wday = -1, yday = -1, isdst =-1)
1875+
wday = -1, yday = -1, isdst =0)
18761876

18771877
The month (C<mon>) begins at zero,
18781878
I<e.g.>, January is 0, not 1. The
18791879
year (C<year>) is given in years since 1900, I<e.g.>, the year 1995 is 95; the
18801880
year 2001 is 101. Consult your system's C<strftime()> manpage for details
18811881
about these and the other arguments.
18821882

1883-
The C<wday>, C<yday>, and C<isdst> parameters are all ignored.
1883+
The C<wday> and C<yday> parameters are both ignored. Their values are
1884+
always determinable from the other parameters.
1885+
1886+
C<isdst> should be C<1> or C<0>, depending on whether or not daylight
1887+
savings time is in effect for the given time or not.
18841888

18851889
If you want your code to be portable, your format (C<fmt>) argument
18861890
should use only the conversion specifiers defined by the ANSI C
@@ -1895,11 +1899,10 @@ The C<Z> specifier is notoriously unportable since the names of
18951899
timezones are non-standard. Sticking to the numeric specifiers is the
18961900
safest route.
18971901

1898-
The given arguments are made consistent as though by calling
1899-
C<mktime()> before calling your system's C<strftime()> function,
1900-
except that the C<isdst> value is not affected, so that the returned
1901-
value will always be as if the locale doesn't have daylight savings
1902-
time.
1902+
The arguments, except for C<isdst>, are made consistent as though by
1903+
calling C<mktime()> before calling your system's C<strftime()> function.
1904+
To get correct results, you must set C<isdst> to be the proper value.
1905+
When omitted, the function assumes daylight savings is not in effect.
19031906

19041907
The string for Tuesday, December 12, 1995 in the C<C> locale.
19051908

‎ext/POSIX/t/time.t

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use strict;
99

1010
use Config;
1111
use POSIX;
12-
use Test::Moretests=>26;
12+
use Test::Moretests=>27;
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.
@@ -205,3 +205,12 @@ SKIP: {
205205
is(mktime(CORE::localtime($time)),$time,"mktime()");
206206
is(mktime(POSIX::localtime($time)),$time,"mktime()");
207207
}
208+
209+
SKIP: {
210+
skip"'%s' not implemented in strftime", 1if $^Oeq"VMS"
211+
|| $^Oeq"MSWin32";
212+
# Somewhat arbitrarily, put in 60 seconds of slack; if this fails, it
213+
# will likely be off by 1 hour
214+
ok(abs(POSIX::strftime('%s',localtime) -time) < 60,
215+
'GH #22351; pr: GH #22369');
216+
}

‎locale.c

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8095,11 +8095,27 @@ The caller assumes ownership of the returned SV with a reference count of 1.
80958095
80968096
C<sv_strftime_ints> takes a bunch of integer parameters that together
80978097
completely define a given time. It calculates the S<C<struct tm>> to pass to
8098-
libc strftime(), and calls that function. Setting C<isdst> to 0 causes the
8099-
date to be calculated as if there is no daylight savings time in effect; any
8100-
other value causes the possibility of daylight savings time to be considered.
8101-
A positive value is a hint to the function that daylight savings is likely to
8102-
be in effect for the passed-in time.
8098+
libc strftime(), and calls that function.
8099+
8100+
The value of C<isdst> is used as follows:
8101+
8102+
=over
8103+
8104+
=item 0
8105+
8106+
No daylight savings time is in effect
8107+
8108+
=item E<gt>0
8109+
8110+
Check if daylight savings time is in effect, and adjust the results
8111+
accordingly.
8112+
8113+
=item E<lt>0
8114+
8115+
This value is reserved for internal use by the L<POSIX> module for backwards
8116+
compatibility purposes.
8117+
8118+
=back
81038119
81048120
The caller assumes ownership of the returned SV with a reference count of 1.
81058121
@@ -8166,8 +8182,15 @@ Perl_sv_strftime_ints(pTHX_ SV * fmt, int sec, int min, int hour,
81668182
constchar*locale="C";
81678183
#endif
81688184

8185+
/* A negative 'isdst' triggers backwards compatibility mode for
8186+
* POSIX::strftime(), in which 0 is always passed to ints_to_tm() so that
8187+
* the possibility of daylight savings time is never considered, But, a 1
8188+
* is eventually passed to libc strftime() so that it returns the results
8189+
* it always has for a non-zero 'isdst'. See GH #22351 */
81698190
structtmmytm;
8170-
ints_to_tm(&mytm,locale,sec,min,hour,mday,mon,year,isdst);
8191+
ints_to_tm(&mytm,locale,sec,min,hour,mday,mon,year,
8192+
MAX(0,isdst));
8193+
mytm.tm_isdst=MIN(1,abs(isdst));
81718194
returnsv_strftime_common(fmt,locale,&mytm);
81728195
}
81738196

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp