Perl函数localtime在1964年到1967年之间给出了不正确的值

时间:2017-04-05 03:12:45

标签: perl localtime

我从Perl中的 localtime 函数中获得了一些糟糕的值。以下是一些我得到错误值的代码。

特别是,此代码用于确定每年第一天的工作日。

#!/usr/bin/perl
use strict 'vars';
use Time::Local;
use POSIX qw(strftime);

mytable();

sub mytable {
   print "Year" . " "x4 .  "Jan 1st (localtime)" . " "x4 . "Jan 1st (Gauss)\n";
   foreach my $year ( 1964 .. 2017 )
     {
       my $janlocaltime = evalweekday( 1,1,$year);
       my $jangauss     = gauss($year);
       my $diff = $jangauss - $janlocaltime;
       printf "%4s%10s%-12s ",$year,"",$janlocaltime;
       printf "%12s",$jangauss;
       printf " <----- ERROR: off by %2s", $diff if ( $diff != 0 );
     print "\n";
     }
}

sub evalweekday {
   ## Using "localtime"
   my ($day,$month,$year) = @_;
   my $epoch   =  timelocal(0,0,0, $day,$month-1,$year-1900);
   my $weekday = ( localtime($epoch) ) [6];
   return $weekday;
 }

sub gauss {
   ## Alternative approach
   my ($year) = @_;
   my $weekday =
     (  1 + 5 * ( ( $year - 1 ) % 4 )
      + 4 * ( ( $year - 1 ) % 100 )
      + 6 * ( ( $year - 1 ) % 400 )
    ) % 7;
   return $weekday;
 }

以下是显示年份值不正确的输出:

Year    Jan 1st (localtime)    Jan 1st (Gauss)
1964          2                       3 <----- ERROR: off by  1
1965          4                       5 <----- ERROR: off by  1
1966          5                       6 <----- ERROR: off by  1
1967          6                       0 <----- ERROR: off by -6
1968          1                       1
1969          3                       3
1970          4                       4
1971          5                       5
1972          6                       6
1973          1                       1
1974          2                       2
1975          3                       3
1976          4                       4
1977          6                       6
1978          0                       0
1979          1                       1
1980          2                       2
1981          4                       4
1982          5                       5
1983          6                       6
1984          0                       0
1985          2                       2
1986          3                       3
1987          4                       4
1988          5                       5
1989          0                       0
1990          1                       1
1991          2                       2
1992          3                       3
1993          5                       5
1994          6                       6
1995          0                       0
1996          1                       1
1997          3                       3
1998          4                       4
1999          5                       5
2000          6                       6
2001          1                       1
2002          2                       2
2003          3                       3
2004          4                       4
2005          6                       6
2006          0                       0
2007          1                       1
2008          2                       2
2009          4                       4
2010          5                       5
2011          6                       6
2012          0                       0
2013          2                       2
2014          3                       3
2015          4                       4
2016          5                       5
2017          0                       0

事实上,这些错误似乎可以追溯到1900年,但我还没有确认它们在1964年之前确实是错误的。

perl --version 会返回以下内容:

This is perl 5, version 18, subversion 2 (v5.18.2) 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.

我不确定它是否相关,但我的操作系统是macOS Sierra版本10.12.3。

我已经阅读了文档,但是我没有看到任何关于1968年之前返回的值的事情(或者我是盲人)。我还尝试过网络搜索但是,除了对数组值的典型误解以及一年中的月份和日期的数量之外,我还没有提出任何建议。

有人可以帮助我并解释我的错误吗?或者,如果这是我的Perl版本的问题,请告诉我如何解决它。

1 个答案:

答案 0 :(得分:4)

这可能与Time :: Local中如何处理负时间值有关。看看perldoc Time::Local #Negative-Epoch-Values

在我的Linux机器上(perl 5.20),您的代码很好地演示了这个问题。如果您打印出收到的纪元值,您将看到问题,即timelocal返回的纪元变得庞大而不是更负面:

Year       Epoch Jan 1st (localtime)     Jan 1st (Gauss)
1964  2966342400 2                       3 <----- ERROR: off by  1
1965  2997964800 4                       5 <----- ERROR: off by  1
1966  3029500800 5                       6 <----- ERROR: off by  1
1967  3061036800 6                       0 <----- ERROR: off by -6
1968   -63185400 1                       1
1969   -31563000 3                       3
1970      -27000 4                       4
1971    31509000 5                       5
1972    63045000 6                       6

为什么不尝试使用DateTime库:

use DateTime;
my $dt = DateTime->new(
    year   => 1966, # Real Year
    day    => 1,    # 1-31
    month  => 1,    # 1-12
    hour   => 0,    # 0-23
    second => 0,    # 0-59
);
print $dt->dow . "\n";

6
与维基百科视图匹配的

6 = SaturdayJan 1, 1966 (Saturday)