use v6;
use Test;
plan 19;
my ( DateTime $g1, DateTime $g2, Num $t, Int $d );
$g1 = DateTime.from-epoch(0);
ok $g1.year==1970 && $g1.month == 1 && $g1.day == 1 &&
$g1.hour==0 && $g1.minute== 0 && $g1.second== 0 ,
'DateTime at beginning of Unix epoch'; # test 1
ok $g1.day-of-week==5 && $g1.month-name eq 'January' &&
$g1.iso8601 eq '1970-01-01T00:00:00+0000',
'1970-01-01 was a Thursday in January'; # test 2
$t = 946684799; # last second of previous Millennium, FSVO 'Millennium'.
$g1 = DateTime.from-epoch($t);
ok $g1.year==1999 && $g1.month ==12 && $g1.day ==31 &&
$g1.hour==23 && $g1.minute==59 && $g1.second==59 ,
'from-epoch at 1999-12-31 23:59:59'; # test 3
ok $g1.day-name=='Friday' && $g1.month-name eq 'December' &&
$g1.iso8601 eq '1999-12-31T23:59:59+0000',
'1999-12-31 23:59:59 was on a Friday in December'; # test 4
$g1 = DateTime.from-epoch(++$t); # one second later, sing Auld Lang Syne.
ok $g1.year==2000 && $g1.month == 1 && $g1.day == 1 &&
$g1.hour==0 && $g1.minute== 0 && $g1.second== 0 ,
'gmtime at 2000-01-01 00:00:00'; # test 5
ok $g1.day-of-week==7 && $g1.month-name eq 'January' &&
$g1.iso8601 eq '2000-01-01T00:00:00+0000',
'2000-01-01 00:00:00 was on a Saturday in January'; # test 6
$t = floor(time);
while floor(time) == $t { ; } # empty loop until the next second begins
$t = time;
$d = (floor($t) div 86400 + 4) % 7 + 1;
$g1 = DateTime.from-epoch($t);
$g2 = DateTime.now; # $g1 and $g2 might differ very occasionally
ok $g1.year ==$g2.year && $g1.month ==$g2.month &&
$g1.day ==$g2.day && $g1.hour ==$g2.hour &&
$g1.minute==$g2.minute && floor($g1.second)==floor($g2.second),
'now() uses current time'; # test 7
ok $g2.day-of-week==$d,
"today, {$g2.ymd} {$g2.hms}," ~
" is a {$g2.day-name} in {$g2.month-name}"; # test 8
# compare dates for a series of times earlier and later than "now", so
# that every test run will use different values
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
# the offset changes all time components and causes overflow/underflow
$t = floor(time);
my $t1 = $t;
my $t2 = $t;
my $offset = ((((7*31+1)*24+10)*60+21)*60+21);
for 1..3 {
$t1 -= $offset;
$g1 = DateTime.from-epoch( $t1 );
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = test-gmtime($t1);
ok $g1.day==$mday && $g1.month==$mon+1 && $g1.year==$year+1900 &&
$g1.hour==$hour && $g1.minute==$min && $g1.second==$sec &&
$g1.day-of-week==$wday+1,
"crosscheck {$g1.ymd} {$g1.hms}";
$t2 += $offset;
$g2 = DateTime.from-epoch( $t2 );
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = test-gmtime($t2);
ok $g2.day==$mday && $g2.month==$mon+1 && $g2.year==$year+1900 &&
$g2.hour==$hour && $g2.minute==$min && $g2.second==$sec &&
$g2.day-of-week==$wday+1,
"crosscheck {$g2.ymd} {$g2.hms}";
} # tests 9-14
$g1 = DateTime.new(
year=>1970, month=>1, day=>1,
hour=>1, minute=>1, second=>1,
time-zone=>'+0100' );
ok $g1.to-epoch==3661, "epoch at 1970-01-01 01:01:01"; # test 15
ok ~$g1 eq '1970-01-01T01:01:01+0100',
"as Str 1970-01-01T01:01:01+0100"; # test 16
# round trip test for current number of seconds in the Unix epoch
$t = floor(time);
my @t = test-gmtime( $t );
$g1 = DateTime.new(
year=>@t[5]+1900, month=>@t[4]+1, day=>@t[3],
hour=>@t[2], minute=>@t[1], second=>@t[0],
timezone => '+0000' );
ok $g1.to-epoch == $t, "at $g1, epoch is {$g1.to-epoch}"; # test 17
# Calls to constructors may omit parameters
$g1 = DateTime.new(year=>1969, day=>15, hour=>9, minute=>15);
ok ~$g1 eq '1969-01-15T09:15:00+0000', 'new without some params'; # test 18
# Loopback
$g1 = DateTime.parse('2009-12-31T22:33:44+1100');
ok $g1.ymd eq '2009-12-31' && $g1.hms eq '22:33:44', 'parse ISO 8601'; # test 19
# An independent calculation to cross check the Temporal algorithms.
sub test-gmtime( Num $t is copy ) {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
$t = floor($t);
$sec = $t % 60; $t div= 60; # $t is now epoch minutes
$min = $t % 60; $t div= 60; # $t is now epoch hours
$hour = $t % 24; $t div= 24; # $t is now epoch days
# Not a sophisticated or fast algorithm, just an understandable one
# only valid from 1970-01-01 until 2100-02-28
$wday = ($t+4) % 7; # 1970-01-01 was a Thursday
$year = 70; # (Unix epoch 0) == (Gregorian 1970) == (Perl year 70)
loop ( $yday = 365; $t >= $yday; $year++ ) {
$t -= $yday; # count off full years of 365 or 366 days
$yday = (($year+1) % 4 == 0) ?? 366 !! 365;
}
$yday = $t;
# Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
my @days = 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31;
@days[1] = ($year % 4 == 0) ?? 29 !! 28; # calibrate February
loop ( $mon = 0; $t >= @days[$mon]; $mon++ ) {
$t -= @days[$mon]; # count off full months of whatever days
}
$mday = $t + 1;
$isdst = 0;
return ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
}
# vim: ft=perl6