1use strict;
2use warnings;
3
4use Test::More;
5use Test::Fatal;
6
7use DateTime;
8
9{
10
11    # Tests creating objects from epoch time
12    my $t1 = DateTime->from_epoch( epoch => 0 );
13    is( $t1->epoch, 0, 'epoch should be 0' );
14
15    is( $t1->second, 0,    'seconds are correct on epoch 0' );
16    is( $t1->minute, 0,    'minutes are correct on epoch 0' );
17    is( $t1->hour,   0,    'hours are correct on epoch 0' );
18    is( $t1->day,    1,    'days are correct on epoch 0' );
19    is( $t1->month,  1,    'months are correct on epoch 0' );
20    is( $t1->year,   1970, 'year is correct on epoch 0' );
21}
22
23{
24    my $dt = DateTime->from_epoch( epoch => '3600' );
25    is(
26        $dt->epoch, 3600,
27        'creation test from epoch = 3600 (compare to epoch)'
28    );
29}
30
31{
32
33    # these tests could break if the time changed during the next three lines
34    my $now      = time;
35    my $nowtest  = DateTime->now();
36    my $nowtest2 = DateTime->from_epoch( epoch => $now );
37    is( $nowtest->hour,   $nowtest2->hour,   'Hour: Create without args' );
38    is( $nowtest->month,  $nowtest2->month,  'Month : Create without args' );
39    is( $nowtest->minute, $nowtest2->minute, 'Minute: Create without args' );
40}
41
42{
43    my $epochtest = DateTime->from_epoch( epoch => '997121000' );
44
45    is(
46        $epochtest->epoch, 997121000,
47        'epoch method returns correct value'
48    );
49    is( $epochtest->hour, 18, 'hour' );
50    is( $epochtest->min,  3,  'minute' );
51}
52
53{
54    my $dt = DateTime->from_epoch( epoch => 3600 );
55    $dt->set_time_zone('+0100');
56
57    is( $dt->epoch, 3600, 'epoch is 3600' );
58    is( $dt->hour,  2,    'hour is 2' );
59}
60
61{
62
63    my $dt = DateTime->new(
64        year      => 1970,
65        month     => 1,
66        day       => 1,
67        hour      => 0,
68        time_zone => '-0100',
69    );
70
71    is( $dt->epoch, 3600, 'epoch is 3600' );
72}
73
74{
75
76    my $dt = DateTime->from_epoch(
77        epoch     => 0,
78        time_zone => '-0100',
79    );
80
81    is( $dt->offset, -3600, 'offset should be -3600' );
82    is( $dt->epoch,  0,     'epoch is 0' );
83}
84
85# Adding/subtracting should affect epoch
86{
87    my $expected  = 1049160602;
88    my $epochtest = DateTime->from_epoch( epoch => $expected );
89
90    is(
91        $epochtest->epoch, $expected,
92        "epoch method returns correct value ($expected)"
93    );
94    is( $epochtest->hour, 1,  'hour' );
95    is( $epochtest->min,  30, 'minute' );
96
97    $epochtest->add( hours => 2 );
98    $expected += 2 * 60 * 60;
99
100    is( $epochtest->hour, 3, 'adjusted hour' );
101    is(
102        $epochtest->epoch, $expected,
103        "epoch method returns correct adjusted value ($expected)"
104    );
105
106}
107
108{
109    my $dt = DateTime->from_epoch( epoch => 0.5 );
110    is(
111        $dt->nanosecond, 500_000_000,
112        'nanosecond should be 500,000,000 with 0.5 as epoch'
113    );
114
115    is( $dt->epoch,       0,   'epoch should be 0' );
116    is( $dt->hires_epoch, 0.5, 'hires_epoch should be 0.5' );
117}
118
119{
120    my $dt = DateTime->from_epoch( epoch => -0.5 );
121    is(
122        $dt->nanosecond, 500_000_000,
123        'nanosecond should be 500,000,000 with -0.5 as epoch'
124    );
125
126    is( $dt->epoch,       -1,   'epoch should be -1' );
127    is( $dt->hires_epoch, -0.5, 'hires_epoch should be -0.5' );
128}
129
130{
131    my $dt = DateTime->from_epoch( epoch => 1609459199.999999 );
132    is(
133        $dt->nanosecond, 999999000,
134        'nanosecond should be 999,999,000 with 1609459199.999999 as epoch'
135    );
136
137    is( $dt->epoch, 1609459199, 'epoch should be 1609459199' );
138}
139
140{
141    my $dt = DateTime->from_epoch( epoch => 0.1234567891 );
142    is(
143        $dt->nanosecond, 123_457_000,
144        'nanosecond should be rounded to 123,457,000 when given 0.1234567891'
145    );
146}
147
148{
149    my $dt = DateTime->from_epoch( epoch => -0.1234567891 );
150    is(
151        $dt->nanosecond, 876_543_000,
152        'nanosecond should be rounded to 876,543,000 when given -0.1234567891'
153    );
154}
155
156{
157    is(
158        DateTime->new( year => 1904 )->epoch, -2082844800,
159        'epoch should work back to at least 1904'
160    );
161
162    my $dt = DateTime->from_epoch( epoch => -2082844800 );
163    is( $dt->year,  1904, 'year should be 1904' );
164    is( $dt->month, 1,    'month should be 1904' );
165    is( $dt->day,   1,    'day should be 1904' );
166}
167
168{
169    for my $pair (
170        [ 1   => -62135596800 ],
171        [ 99  => -59042995200 ],
172        [ 100 => -59011459200 ],
173        [ 999 => -30641760000 ],
174    ) {
175
176        my ( $year, $epoch ) = @{$pair};
177
178        is(
179            DateTime->new( year => $year )->epoch, $epoch,
180            "epoch for $year is $epoch"
181        );
182    }
183}
184
185{
186
187    package Number::Overloaded;
188    use overload
189        '0+'     => sub { $_[0]->{num} },
190        fallback => 1;
191
192    sub new { bless { num => $_[1] }, $_[0] }
193}
194
195{
196    my $time = Number::Overloaded->new(12345);
197
198    my $dt = DateTime->from_epoch( epoch => $time );
199    is( $dt->epoch, 12345, 'can pass overloaded object to from_epoch' );
200
201    $time = Number::Overloaded->new(12345.1234);
202    $dt   = DateTime->from_epoch( epoch => $time );
203    is( $dt->epoch, 12345, 'decimal epoch in overloaded object' );
204}
205
206{
207    my $time = Number::Overloaded->new(-12345);
208    my $dt   = DateTime->from_epoch( epoch => $time );
209
210    is( $dt->epoch, -12345, 'negative epoch in overloaded object' );
211}
212
213{
214    my @tests = (
215        'asldkjlkjd',
216        '1234 foo',
217        'adlkj 1234',
218    );
219
220    for my $test (@tests) {
221        like(
222            exception { DateTime->from_epoch( epoch => $test ) },
223            qr/Validation failed for type named Num/,
224            qq{'$test' is not a valid epoch value}
225        );
226    }
227}
228
229done_testing();
230