Move Time::Local from lib to ext.
[p5sagit/p5-mst-13.2.git] / ext / Time-Local / t / Local.t
CommitLineData
1a3850a5 1#!./perl
2
823a6996 3use strict;
4
65d4ed58 5use Config;
e6f8b432 6use Test::More;
1a3850a5 7use Time::Local;
8
9# Set up time values to test
823a6996 10my @time =
1a3850a5 11 (
823a6996 12 #year,mon,day,hour,min,sec
9b599b2a 13 [1970, 1, 2, 00, 00, 00],
1a3850a5 14 [1980, 2, 28, 12, 00, 00],
15 [1980, 2, 29, 12, 00, 00],
16 [1999, 12, 31, 23, 59, 59],
17 [2000, 1, 1, 00, 00, 00],
18 [2010, 10, 12, 14, 13, 12],
5847cf89 19 # leap day
78063c05 20 [2020, 2, 29, 12, 59, 59],
21 [2030, 7, 4, 17, 07, 06],
a272e669 22 [2038, 1, 17, 23, 59, 59], # last full day in any tz
23
24 # more than 2**31 time_t
25 [2258, 8, 11, 1, 49, 17],
1a3850a5 26 );
27
5847cf89 28my @bad_time =
29 (
30 # month too large
31 [1995, 13, 01, 01, 01, 01],
32 # day too large
33 [1995, 02, 30, 01, 01, 01],
34 # hour too large
35 [1995, 02, 10, 25, 01, 01],
36 # minute too large
37 [1995, 02, 10, 01, 60, 01],
38 # second too large
39 [1995, 02, 10, 01, 01, 60],
40 );
41
42my @neg_time =
43 (
44 # test negative epochs for systems that handle it
45 [ 1969, 12, 31, 16, 59, 59 ],
46 [ 1950, 04, 12, 9, 30, 31 ],
47 );
48
d15eb09c 49# Leap year tests
50my @years =
51 (
52 [ 1900 => 0 ],
53 [ 1947 => 0 ],
54 [ 1996 => 1 ],
55 [ 2000 => 1 ],
56 [ 2100 => 0 ],
57 );
58
93a04732 59# Use 3 days before the start of the epoch because with Borland on
60# Win32 it will work for -3600 _if_ your time zone is +01:00 (or
61# greater).
d15eb09c 62my $neg_epoch_ok = defined ((localtime(-259200))[0]) ? 1 : 0;
5847cf89 63
61bb5906 64# use vmsish 'time' makes for oddness around the Unix epoch
8f230aaa 65if ($^O eq 'VMS') {
5c415a7a 66 $time[0][2]++;
67 $neg_epoch_ok = 0; # time_t is unsigned
68}
61bb5906 69
65d4ed58 70my $epoch_is_64 = eval { $Config{ivsize} == 8 && ( gmtime 2**40 )[5] == 34912 };
71
5847cf89 72my $tests = (@time * 12);
73$tests += @neg_time * 12;
74$tests += @bad_time;
d15eb09c 75$tests += @years;
8ff19c00 76$tests += 21;
1c41b6a4 77
823a6996 78plan tests => $tests;
1a3850a5 79
5847cf89 80for (@time, @neg_time) {
1a3850a5 81 my($year, $mon, $mday, $hour, $min, $sec) = @$_;
82 $year -= 1900;
823a6996 83 $mon--;
84
4c91ace1 85 # Test timelocal()
86 {
87 my $year_in = $year < 70 ? $year + 1900 : $year;
88 my $time = timelocal($sec,$min,$hour,$mday,$mon,$year_in);
89
90 my($s,$m,$h,$D,$M,$Y) = localtime($time);
91
92 is($s, $sec, "timelocal second for @$_");
93 is($m, $min, "timelocal minute for @$_");
94 is($h, $hour, "timelocal hour for @$_");
95 is($D, $mday, "timelocal day for @$_");
96 is($M, $mon, "timelocal month for @$_");
97 is($Y, $year, "timelocal year for @$_");
a272e669 98 }
e6f8b432 99
4c91ace1 100
101 # Test timegm()
a272e669 102 {
103 my $year_in = $year < 70 ? $year + 1900 : $year;
104 my $time = timegm($sec,$min,$hour,$mday,$mon,$year_in);
e6f8b432 105
a272e669 106 my($s,$m,$h,$D,$M,$Y) = gmtime($time);
e6f8b432 107
a272e669 108 is($s, $sec, "timegm second for @$_");
109 is($m, $min, "timegm minute for @$_");
110 is($h, $hour, "timegm hour for @$_");
111 is($D, $mday, "timegm day for @$_");
112 is($M, $mon, "timegm month for @$_");
113 is($Y, $year, "timegm year for @$_");
1a3850a5 114 }
1a3850a5 115}
116
4c91ace1 117
5847cf89 118for (@bad_time) {
119 my($year, $mon, $mday, $hour, $min, $sec) = @$_;
120 $year -= 1900;
121 $mon--;
122
123 eval { timegm($sec,$min,$hour,$mday,$mon,$year) };
124
e6f8b432 125 like($@, qr/.*out of range.*/, 'invalid time caused an error');
5847cf89 126}
127
e6f8b432 128{
129 is(timelocal(0,0,1,1,0,90) - timelocal(0,0,0,1,0,90), 3600,
130 'one hour difference between two calls to timelocal');
1a3850a5 131
e6f8b432 132 is(timelocal(1,2,3,1,0,100) - timelocal(1,2,3,31,11,99), 24 * 3600,
133 'one day difference between two calls to timelocal');
1a3850a5 134
e6f8b432 135 # Diff beween Jan 1, 1980 and Mar 1, 1980 = (31 + 29 = 60 days)
136 is(timegm(0,0,0, 1, 2, 80) - timegm(0,0,0, 1, 0, 80), 60 * 24 * 3600,
137 '60 day difference between two calls to timegm');
138}
1a3850a5 139
13ef5feb 140# bugid #19393
141# At a DST transition, the clock skips forward, eg from 01:59:59 to
142# 03:00:00. In this case, 02:00:00 is an invalid time, and should be
143# treated like 03:00:00 rather than 01:00:00 - negative zone offsets used
144# to do the latter
13ef5feb 145{
146 my $hour = (localtime(timelocal(0, 0, 2, 7, 3, 102)))[2];
147 # testers in US/Pacific should get 3,
148 # other testers should get 2
e6f8b432 149 ok($hour == 2 || $hour == 3, 'hour should be 2 or 3');
823a6996 150}
151
d15eb09c 152for my $p (@years) {
153 my ( $year, $is_leap_year ) = @$p;
154
155 my $string = $is_leap_year ? 'is' : 'is not';
156 is( Time::Local::_is_leap_year($year), $is_leap_year,
157 "$year $string a leap year" );
158}
159
e6f8b432 160{
99ffb1cb 161 eval { timegm(0,0,0,29,1,1900) };
162 like($@, qr/Day '29' out of range 1\.\.28/,
163 'does not accept leap day in 1900');
164
165 eval { timegm(0,0,0,29,1,200) };
166 like($@, qr/Day '29' out of range 1\.\.28/,
167 'does not accept leap day in 2100 (year passed as 200)');
168
169 eval { timegm(0,0,0,29,1,0) };
170 is($@, '', 'no error with leap day of 2000 (year passed as 0)');
171
5847cf89 172 eval { timegm(0,0,0,29,1,1904) };
e6f8b432 173 is($@, '', 'no error with leap day of 1904');
99ffb1cb 174
175 eval { timegm(0,0,0,29,1,4) };
176 is($@, '', 'no error with leap day of 2004 (year passed as 4)');
177
178 eval { timegm(0,0,0,29,1,96) };
179 is($@, '', 'no error with leap day of 1996 (year passed as 96)');
5847cf89 180}
181
65d4ed58 182SKIP:
183{
184 skip 'These tests require a system with 64-bit time_t.', 3
185 unless $epoch_is_64;
186
187 is( timegm( 8, 14, 3, 19, 0, ( 1900 + 138 ) ), 2**31,
188 'can call timegm for 2**31 epoch seconds' );
189 is( timegm( 16, 28, 6, 7, 1, ( 1900 + 206 ) ), 2**32,
190 'can call timegm for 2**32 epoch seconds (on a 64-bit system)' );
191 is( timegm( 16, 36, 0, 20, 1, ( 34912 + 1900 ) ), 2**40,
192 'can call timegm for 2**40 epoch seconds (on a 64-bit system)' );
193}
194
195SKIP:
196{
197 skip 'These tests only run for the package maintainer.', 8
198 unless $ENV{MAINTAINER};
199
e6f8b432 200 require POSIX;
201
202 local $ENV{TZ} = 'Europe/Vienna';
203 POSIX::tzset();
204
205 # 2001-10-28 02:30:00 - could be either summer or standard time,
206 # prefer earlier of the two, in this case summer
207 my $time = timelocal(0, 30, 2, 28, 9, 101);
208 is($time, 1004229000,
209 'timelocal prefers earlier epoch in the presence of a DST change');
210
211 local $ENV{TZ} = 'America/Chicago';
212 POSIX::tzset();
213
214 # Same local time in America/Chicago. There is a transition here
215 # as well.
216 $time = timelocal(0, 30, 1, 28, 9, 101);
217 is($time, 1004250600,
218 'timelocal prefers earlier epoch in the presence of a DST change');
219
220 $time = timelocal(0, 30, 2, 1, 3, 101);
221 is($time, 986113800,
222 'timelocal for non-existent time gives you the time one hour later');
223
224 local $ENV{TZ} = 'Australia/Sydney';
225 POSIX::tzset();
226 # 2001-03-25 02:30:00 in Australia/Sydney. This is the transition
227 # _to_ summer time. The southern hemisphere transitions are
228 # opposite those of the northern.
229 $time = timelocal(0, 30, 2, 25, 2, 101);
230 is($time, 985447800,
231 'timelocal prefers earlier epoch in the presence of a DST change');
232
233 $time = timelocal(0, 30, 2, 28, 9, 101);
234 is($time, 1004200200,
235 'timelocal for non-existent time gives you the time one hour later');
236
237 local $ENV{TZ} = 'Europe/London';
238 POSIX::tzset();
239 $time = timelocal( localtime(1111917720) );
240 is($time, 1111917720,
241 'timelocal for round trip bug on date of DST change for Europe/London');
242
243 # There is no 1:00 AM on this date, as it leaps forward to
244 # 2:00 on the DST change - this should return 2:00 per the
245 # docs.
246 is( ( localtime( timelocal( 0, 0, 1, 27, 2, 2005 ) ) )[2], 2,
247 'hour is 2 when given 1:00 AM on Europe/London date change' );
248
249 is( ( localtime( timelocal( 0, 0, 2, 27, 2, 2005 ) ) )[2], 2,
250 'hour is 2 when given 2:00 AM on Europe/London date change' );
13ef5feb 251}