1use strict;
2use warnings;
3
4use lib 't/lib';
5use T::RequireDateTime;
6
7use Test::More;
8use Test::Fatal;
9
10use DateTime::TimeZone;
11use Try::Tiny;
12
13my @names = DateTime::TimeZone::all_names();
14cmp_ok(
15    scalar @names, '>', 100,
16    'at least 100 zones'
17);
18
19my %links = DateTime::TimeZone->links();
20cmp_ok(
21    scalar keys %links, '>', 100,
22    'at least 100 links'
23);
24
25my $is_maintainer = -d '.git' || $ENV{RELEASE_TESTING} ? 1 : 0;
26
27foreach my $name (@names) {
28    my $resolved_name = $links{$name} || $name;
29
30    my $tz = DateTime::TimeZone->new( name => $name );
31    isa_ok( $tz, 'DateTime::TimeZone' );
32
33    is( $tz->name, $resolved_name, 'check ->name' );
34
35    is( $tz->is_floating, 0, 'should not be floating' );
36    is( $tz->is_utc,      0, 'should not be UTC' )
37        unless $resolved_name eq 'UTC';
38
39    # adding these tests makes the test suite take a _long_ time to
40    # finish, and it uses up lots of memory too.
41    if ($is_maintainer) {
42        my $dt;
43        is(
44            exception { $dt = DateTime->now( time_zone => $name ) },
45            undef,
46            "Can call DateTime->now with $name"
47        );
48
49        is(
50            exception { $dt->add( years => 50 ) },
51            undef,
52            "Can add 50 years with $name"
53        );
54
55        is(
56            exception { $dt->subtract( years => 400 ) },
57            undef,
58            "Can subtract 400 years with $name"
59        );
60
61        try {
62            $dt = DateTime->new(
63                year      => 2000, month => 6, hour => 1,
64                time_zone => $name
65            );
66        };
67        is( $dt->hour, 1, 'make sure that local time is always respected' );
68
69        try {
70            $dt = DateTime->new(
71                year      => 2000, month => 12, hour => 1,
72                time_zone => $name
73            );
74        };
75        is( $dt->hour, 1, 'make sure that local time is always respected' );
76    }
77}
78
79foreach my $name ( '0', 'Z', 'UTC' ) {
80    my $tz = DateTime::TimeZone->new( name => $name );
81    isa_ok( $tz, 'DateTime::TimeZone' );
82
83    is( $tz->name, 'UTC', 'name should be UTC' );
84
85    is( $tz->is_floating, 0, 'should not be floating' );
86    is( $tz->is_utc,      1, 'should be UTC' );
87}
88
89my $tz = DateTime::TimeZone->new( name => 'America/Chicago' );
90
91# These tests are odd since we're feeding UTC times into the time zone
92# object, which isn't what happens in real usage.  But doing this
93# minimizes how much of DateTime.pm needs to work for these tests.
94{
95    my $dt = DateTime->new(
96        year      => 2001,
97        month     => 9,
98        day       => 10,
99        time_zone => 'UTC',
100    );
101    is( $tz->offset_for_datetime($dt), -18000,    'offset should be -18000' );
102    is( $tz->short_name_for_datetime($dt), 'CDT', 'name should be CDT' );
103}
104
105{
106    my $dt = DateTime->new(
107        year      => 2001,
108        month     => 10,
109        day       => 29,
110        time_zone => 'UTC',
111    );
112    is( $tz->offset_for_datetime($dt), -21600,    'offset should be -21600' );
113    is( $tz->short_name_for_datetime($dt), 'CST', 'name should be CST' );
114}
115
116{
117
118    # check that generation works properly
119    my $dt = DateTime->new(
120        year      => 2200,
121        month     => 11,
122        day       => 2,
123        time_zone => 'UTC',
124    );
125    is(
126        $tz->offset_for_datetime($dt), -18000,
127        'generated offset should be -1800'
128    );
129    is(
130        $tz->short_name_for_datetime($dt), 'CDT',
131        'generated name should be CDT'
132    );
133}
134
135{
136
137    # check that generation works properly
138    my $dt = DateTime->new(
139        year      => 2200,
140        month     => 11,
141        day       => 3,
142        time_zone => 'UTC',
143    );
144    is(
145        $tz->offset_for_datetime($dt), -21600,
146        'generated offset should be -21600'
147    );
148    is(
149        $tz->short_name_for_datetime($dt), 'CST',
150        'generated name should be CST'
151    );
152}
153
154{
155    my $dt = DateTime->new(
156        year      => 1944,
157        month     => 10,
158        day       => 29,
159        time_zone => 'UTC',
160    );
161    is( $tz->offset_for_datetime($dt), -18000,    'offset should be -18000' );
162    is( $tz->short_name_for_datetime($dt), 'CWT', 'name should be CWT' );
163}
164
165{
166    my $dt = DateTime->new(
167        year      => 1936,
168        month     => 3,
169        day       => 2,
170        time_zone => 'UTC',
171    );
172
173    is( $tz->offset_for_datetime($dt), -18000,    'offset should be -18000' );
174    is( $tz->short_name_for_datetime($dt), 'EST', 'name should be EST' );
175}
176
177{
178    my $dt = DateTime->new(
179        year      => 1883,
180        month     => 1,
181        day       => 29,
182        time_zone => 'UTC',
183    );
184
185    is( $tz->offset_for_datetime($dt), -21036,    'offset should be -21036' );
186    is( $tz->short_name_for_datetime($dt), 'LMT', 'name should be LMT' );
187}
188
189{
190    {
191
192        package TestHack;
193
194        sub new { bless {}, shift }
195
196        # UTC RD secs == 63518486401
197        sub utc_rd_values { ( 735167, 57601 ) }
198    }
199
200    # This is to check a bug in DT::TZ::_span_for_datetime, where it
201    # was always looking at the LOCAL_END of the current max_span.
202    #
203    # Australia/Sydney's max_span (before generation) has a LOCAL_END
204    # of 63518522400 and UTC_END of 63518486400.  The values above
205    # create a utc_rd_seconds value that is after the UTC_END but
206    # before the LOCAL_END.
207    my $dt = DateTime->from_object( object => TestHack->new );
208
209    is(
210        exception {
211            $dt->set_time_zone('UTC')->set_time_zone('Australia/Sydney')
212        },
213        undef,
214        'should be able to set time zone without error'
215    );
216
217    ok( $dt->is_dst, 'is_dst should be true' );
218}
219
220{
221    my $offset_tz = DateTime::TimeZone->new( name => '-0100' );
222    ok(
223        !$offset_tz->is_olson,
224        'is_olson is false for offset only time zone'
225    );
226}
227
228{
229
230    # bug when creating new datetime for year just after time zone's
231    # max year
232    my $la_tz = DateTime::TimeZone->new( name => 'America/Los_Angeles' );
233
234    my $dt = try {
235        DateTime->new(
236            year      => $la_tz->{max_year} + 1,
237            month     => 5,
238            day       => 20,
239            time_zone => $la_tz
240        );
241    };
242    ok( $dt, 'was able to create datetime object' );
243}
244
245done_testing();
246