File: time.t

package info (click to toggle)
perl 5.42.0-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 128,392 kB
  • sloc: perl: 534,963; ansic: 240,563; sh: 72,042; pascal: 6,934; xml: 2,428; yacc: 1,360; makefile: 1,197; cpp: 208; lisp: 1
file content (228 lines) | stat: -rw-r--r-- 8,529 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#!perl -w

BEGIN {
    unshift @INC, "../../t";
    require 'loc_tools.pl';
}

use strict;

use Config;
use POSIX;
use Test::More tests => 31;

# For the first go to UTC to avoid DST issues around the world when testing.  SUS3 says that
# null should get you UTC, but some environments want the explicit names.
# Those with a working tzset() should be able to use the TZ below.
$ENV{TZ} = "EST5EDT";

SKIP: {
    # It looks like POSIX.xs claims that only VMS and Mac OS traditional
    # don't have tzset().  Win32 works to call the function, but it doesn't
    # actually do anything.  Cygwin works in some places, but not others.  The
    # other Win32's below are guesses.
    skip "No tzset()", 1
       if $^O eq "VMS" || $^O eq "cygwin" ||
          $^O eq "MSWin32" || $^O eq "interix";
    tzset();
    SKIP: {
        my @tzname = tzname();

        # See extensive discussion in GH #22062.
        skip 1 if $tzname[1] ne "EDT";
        is(strftime("%Y-%m-%d %H:%M:%S", 0, 30, 2, 10, 2, 124, 0, 0, 0),
                    "2024-03-10 02:30:00",
                    "strftime() doesnt pay attention to dst");
    }
}

# go to UTC to avoid DST issues around the world when testing.  SUS3 says that
# null should get you UTC, but some environments want the explicit names.
# Those with a working tzset() should be able to use the TZ below.
$ENV{TZ} = "UTC0UTC";

SKIP: {
    skip "No tzset()", 2
       if $^O eq "VMS" || $^O eq "cygwin" ||
          $^O eq "MSWin32" || $^O eq "interix";
    tzset();
    my @tzname = tzname();
    like($tzname[0], qr/(GMT|UTC)/i, "tzset() to GMT/UTC");
    SKIP: {
        skip "Mac OS X/Darwin doesn't handle this", 1 if $^O =~ /darwin/i;
        like($tzname[1], qr/(GMT|UTC)/i, "The whole year?");
    }
}

if ($^O eq "hpux" && $Config{osvers} >= 11.3) {
    # HP does not support UTC0UTC and/or GMT0GMT, as they state that this is
    # legal syntax but as it has no DST rule, it cannot be used. That is the
    # conclusion of bug
    # QXCR1000896916: Some timezone valuesfailing on 11.31 that work on 11.23
    $ENV{TZ} = "UTC";
}

# asctime and ctime...Let's stay below INT_MAX for 32-bits and
# positive for some picky systems.

is(asctime(CORE::localtime(0)), ctime(0), "asctime() and ctime() at zero");
is(asctime(POSIX::localtime(0)), ctime(0), "asctime() and ctime() at zero");
is(asctime(CORE::localtime(12345678)), ctime(12345678),
   "asctime() and ctime() at 12345678");
is(asctime(POSIX::localtime(12345678)), ctime(12345678),
   "asctime() and ctime() at 12345678");

my $illegal_format = "%!";

# An illegal format could result in an empty result, but many platforms just
# pass it through, or strip off the '%'
sub munge_illegal_format_result($) {
    my $result = shift;
    $result = "" if $result eq $illegal_format || $result eq '!';
    return $result;
}

my $jan_16 = 15 * 86400;

is(munge_illegal_format_result(strftime($illegal_format,
                                        CORE::localtime($jan_16))),
   "", "strftime returns appropriate result for an illegal format");

# Careful!  strftime() is locale sensitive.  Let's take care of that
my $orig_time_loc = 'C';

my $LC_TIME_enabled = locales_enabled('LC_TIME');
if ($LC_TIME_enabled) {
    $orig_time_loc = setlocale(LC_TIME) || die "Cannot get time locale information:  $!";
    setlocale(LC_TIME, "C") || die "Cannot setlocale() to C:  $!";
}

my $ctime_format = "%a %b %d %H:%M:%S %Y\n";
is(ctime($jan_16), strftime($ctime_format, CORE::localtime($jan_16)),
        "get ctime() equal to strftime()");
is(ctime($jan_16), strftime($ctime_format, POSIX::localtime($jan_16)),
        "get localtime() equal to strftime()");

my $ss = chr 223;
unlike($ss, qr/\w/, 'Not internally UTF-8 encoded');
is(ord strftime($ss, CORE::localtime), 223,
   'Format string has correct character');
is(ord strftime($ss, POSIX::localtime(time)),
   223, 'Format string has correct character');
unlike($ss, qr/\w/, 'Still not internally UTF-8 encoded');

my $zh_format = "%Y\x{5e74}%m\x{6708}%d\x{65e5}";
my $zh_expected_result = "1970\x{5e74}01\x{6708}16\x{65e5}";
isnt(strftime($zh_format, CORE::gmtime($jan_16)),
              $zh_expected_result,
           "strftime() UTF-8 format doesn't return UTF-8 in non-UTF-8 locale");

my $utf8_locale = find_utf8_ctype_locale();
SKIP: {
    my $has_time_utf8_locale = ($LC_TIME_enabled && defined $utf8_locale);
    if ($has_time_utf8_locale) {
        my $time_utf8_locale = setlocale(LC_TIME, $utf8_locale);

        # Some platforms don't allow LC_TIME to be changed to a UTF-8 locale,
        # even if we have found one whose LC_CTYPE can be.  The next two tests
        # are invalid on such platforms.  Check for that.  (Examples include
        # OpenBSD, and Alpine Linux without the add-on locales package
        # installed.)
        if (   ! defined $time_utf8_locale
            || ! is_locale_utf8($time_utf8_locale))
        {
            $has_time_utf8_locale = 0;
        }
    }

    skip "No LC_TIME UTF-8 locale", 2 unless $has_time_utf8_locale;

    # By setting LC_TIME only, we verify that the code properly handles the
    # case where that and LC_CTYPE differ
    is(strftime($zh_format, CORE::gmtime($jan_16)),
                $zh_expected_result,
                "strftime() can handle a UTF-8 format;  LC_CTYPE != LCTIME");
    is(strftime($zh_format, POSIX::gmtime($jan_16)),
                $zh_expected_result,
                "Same, but uses POSIX::gmtime; previous test used CORE::");
    setlocale(LC_TIME, "C") || die "Cannot setlocale() to C: $!";
}

my $non_C_locale = $utf8_locale;
if (! defined $non_C_locale) {
    my @locales = find_locales(LC_CTYPE);
    while (@locales) {
        if ($locales[0] ne "C") {
            $non_C_locale = $locales[0];
            last;
        }

        shift @locales;
    }
}

SKIP: {
    skip "No non-C locale", 4 if ! locales_enabled(LC_CTYPE)
                              || ! defined $non_C_locale;
    my $orig_ctype_locale = setlocale(LC_CTYPE)
                            || die "Cannot get ctype locale information:  $!";
    setlocale(LC_CTYPE, $non_C_locale)
                    || die "Cannot setlocale(LC_CTYPE) to $non_C_locale:  $!";

    is(ctime($jan_16), strftime($ctime_format, CORE::localtime($jan_16)),
       "Repeat of ctime() equal to strftime()");
    is(setlocale(LC_CTYPE), $non_C_locale, "strftime restores LC_CTYPE");

    is(munge_illegal_format_result(strftime($illegal_format,
                                            CORE::localtime($jan_16))),
       "", "strftime returns appropriate result for an illegal format");
    is(setlocale(LC_CTYPE), $non_C_locale,
       "strftime restores LC_CTYPE even on failure");

    setlocale(LC_CTYPE, $orig_ctype_locale)
                          || die "Cannot setlocale(LC_CTYPE) back to orig: $!";
}

if ($LC_TIME_enabled) {
    setlocale(LC_TIME, $orig_time_loc)
                            || die "Cannot setlocale(LC_TIME) back to orig: $!";
}

# clock() seems to have different definitions of what it does between POSIX
# and BSD.  Cygwin, Win32, and Linux lean the BSD way.  So, the tests just
# check the basics.
like(clock(), qr/\d*/, "clock() returns a numeric value");
cmp_ok(clock(), '>=', 0, "...and it returns something >= 0");

SKIP: {
    skip "No difftime()", 1 if $Config{d_difftime} ne 'define';
    is(difftime(2, 1), 1, "difftime()");
}

SKIP: {
    skip "No mktime()", 2 if $Config{d_mktime} ne 'define';
    my $time = time();
    is(mktime(CORE::localtime($time)), $time, "mktime()");
    is(mktime(POSIX::localtime($time)), $time, "mktime()");
}
 
SKIP: {
    skip "'%s' not implemented in strftime", 1 if $^O eq "VMS"
                                               || $^O eq "MSWin32"
                                               || $^O eq "os390";
    # Somewhat arbitrarily, put in 60 seconds of slack;  if this fails, it
    # will likely be off by 1 hour
    ok(abs(POSIX::strftime('%s', localtime) - time) < 60,
       'GH #22351; pr: GH #22369');
}

{
    # GH #22498
    is(strftime(42, CORE::localtime), '42', "strftime() works if format is a number");
    my $obj = bless {}, 'Some::Random::Class';
    is(strftime($obj, CORE::localtime), "$obj", "strftime() works if format is an object");
    my $warnings = '';
    local $SIG{__WARN__} = sub { $warnings .= $_[0] };
    is(strftime(undef, CORE::localtime), '', "strftime() works if format is undef");
    like($warnings, qr/^Use of uninitialized value in subroutine entry /, "strftime(undef, ...) produces expected warning");
}