My objective is to handle a wide range of dates in perl, including, for instance, 453 CE, the year "Atilla the Hun" died https://en.wikipedia.org/wiki/Attila.
Now, https://perldoc.perl.org/Time::Local points out a limitation of timelocal() in handling years distant from now:
timelocal_modern() and timegm_modern()
When Time::Local was first written, it was a common practice to represent years as a two-digit value like 99 for 1999 or 1 for 2001. This caused all sorts of problems (google "Y2K problem" if you're very young) and developers eventually realized that this was a terrible idea.
Regarding timelocal(), it says
Warning: The year value interpretation that these functions and their nocheck variants use will almost certainly lead to bugs in your code, if not now, then in the future. You are strongly discouraged from using these in new code, and you should convert old code to using either the *_posix or *_modern functions if possible.
...
Year Value Interpretation This does not apply to the *_posix or *_modern functions. Use those exports if you want to ensure consistent behavior as your code ages.
Accordingly, I want to use timelocal_modern(). But my code below shows both
- the behavior of
timelocal()with distant dates, and - the fact that my attempt to invoke
timelocal_modern()generates an exception.
#!/usr/bin/perl
use strict; use warnings;
use Time::Local;
use POSIX qw(strftime);
print $^V; print "\n";
print "the year Atilla the Hun died:\n";
epochsTOyear(-47855224609);
my $modern;
eval{$modern=timelocal_modern(0,0,0,1,0,0)};
if(length $@)
{
print join('', '$modern=timelocal_modern(0,0,0,1,0,0) threw error: ', $@, "\n",);
}
else
{
print "modern==$modern\n";
}
yearTOformat1january(-1);
yearTOformat1january(0);
yearTOformat1january(2000);
yearTOformat1january(1);
yearTOformat1january(2001);
yearTOformat1january(1000);
yearTOformat1january(-999);
sub yearTOformat1january
{
my @base=(0,0,0,1,0,);
my $answer = timelocal( @base, $_[0]);
print join('', "year== ", $_[0], "\tso \tepoch seconds== ", $answer, "\tyields " , (strftime '%Y-%m-%d %a %H:%M:%S', localtime($answer)), "\n",);
}
sub epochsTOyear
{
my $yearresult=(strftime '%Y', localtime($_[0]));
print join('', "\t\tepoch seconds==", $_[0], "\tyields " , $yearresult, "\n",);
return $yearresult;
}
and what I get on my computer
~/u/kh/bin> perl --version
This is perl 5, version 18, subversion 4 (v5.18.4) built for darwin-thread-multi-2level
(with 2 registered patches, see perl -V for more detail)
Copyright 1987-2013, Larry Wall
Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.
Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl". If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.
~/u/kh/bin> z.pl
v5.18.4
the year Atilla the Hun died:
epoch seconds==-47855224609 yields 0453
$modern=timelocal_modern(0,0,0,1,0,0) threw error: Undefined subroutine &main::timelocal_modern called at /Users/kpr/u/kh/bin/z.pl line 12.
year== -1 so epoch seconds== -2240506800 yields 1899-01-01 Sun 00:00:00
year== 0 so epoch seconds== 946702800 yields 2000-01-01 Sat 00:00:00
year== 2000 so epoch seconds== 946702800 yields 2000-01-01 Sat 00:00:00
year== 1 so epoch seconds== 978325200 yields 2001-01-01 Mon 00:00:00
year== 2001 so epoch seconds== 978325200 yields 2001-01-01 Mon 00:00:00
year== 1000 so epoch seconds== -30610206238 yields 1000-01-01 Wed 00:00:00
year== -999 so epoch seconds== -33734343838 yields 0901-01-01 Sat 00:00:00
~/u/kh/bin>
So, what do I need to do to get timelocal_modern()?