【问题标题】:Why does perl's localtime seem to output the wrong month?为什么 perl 的 localtime 似乎输出了错误的月份?
【发布时间】:2015-11-12 16:42:22
【问题描述】:

我看过其他答案,但由于某种原因它们对我不起作用。

我正在尝试使用以下代码在 Perl 脚本中获取昨天的日期。

为了将来参考,今天的日期是 2015 年 11 月 12 日

my (undef, undef, undef, $mday,$mon,$year) = localtime();
my $prev_day = timelocal(0, 0, 0, $mday-1, $mon, $year);
(undef, undef, undef, $mday,$mon,$year) = localtime($prev_day);
$year += 1900;

print "Yesterday's Day: $mday, Month: $mon, Year: $year\n";

除了我的输出看起来像这样

Yesterday's Day: 11, Month: 10, Year: 2015.

我应该将昨天的日期读取为Day: 11, Month: 11, Year: 2015。为什么要减去月份?

编辑:这与建议的答案不同,因为我想知道为什么当地时间似乎写错了月份。

【问题讨论】:

  • timelocal()中的月份从0到11
  • @Prix 这没有回答 OP 关于为什么 localtime 在 11 月返回 10 而不是 11 的问题,所以我认为这不是一个好的欺骗目标。 (不过,这可能还有另一个问题。)
  • @Prix 阅读问题的正文,这不是您链接的问题的欺骗。人们总是写不好的标题,但仅仅因为一个人的问题标题为“Perl 问题”并不会使其与标题为“PERL 问题”的问题重复。
  • @Prix Perl Incorrect day generated by localtime 是一个实际的副本,虽然这个问题写得更好,所以我投票关闭另一个作为这个问题的欺骗。
  • 要获得更好的方法,请参阅How do I find yesterday's date? in perldoc perlfaq4

标签: perl date


【解决方案1】:

documentation for localtime 这么说

$mday 是月份中的第几天,$mon 是月份,范围为 0..11,其中 0 表示一月,11 表示十二月。

因此,要获得一月份为 1 的月份数,您需要 $mon+1,或者您可以在将 1900 添加到 $year 的同时将一个添加到 $mday

这样

use strict;
use warnings 'all';

use Time::Local;

my ($y, $m, $d) = (localtime)[5,4,3];

my $yesterday = timelocal(0, 0, 0, $d-1, $m, $y);
($y, $m, $d) = (localtime($yesterday))[5,4,3];
$y += 1900;
++$m;

print "Yesterday's Day: $d, Month: $m, Year: $y\n";

输出

Yesterday's Day: 11, Month: 11, Year: 2015

更好的方法是像这样使用核心库Time::Piece

use strict;
use warnings 'all';

use Time::Piece;
use Time::Seconds 'ONE_DAY';

my $yesterday = localtime() - ONE_DAY;

printf "Yesterday's Day: %d, Month: %d, Year: %d\n",
    $yesterday->mday,
    $yesterday->mon,
    $yesterday->year;

输出

Yesterday's Day: 11, Month: 11, Year: 2015

【讨论】:

  • 仅仅从日期中减去一天在一个月的第一天是行不通的。
【解决方案2】:

localtime 和朋友们在一个 6-(或 9-)元素列表上工作,它只是扩展了 POSIX struct tm 结构的各个字段。在该结构中,tm_mon 字段是第 5 个元素,表示 0 到 11 范围内的月份。我相信这里的意图可能是允许您将其用作包含名称的字符串数组中的索引您所在地区的月份。

获取时间元素列表并对其进行格式化以供人类使用的唯一明智方法是使用strftime 函数,该函数采用您希望呈现的某种格式。例如:

use POSIX qw( strftime );

print strftime( "Yesterday's Day: %d Month: %m, Year: %Y\n", localtime $epoch );

如果您还没有 Unix 纪元值,您可以从 mktime()timelocal() 获得一个

use POSIX qw( strftime mktime );

my ( $mday, $mon, $year ) = ... # as before

print strftime( "Yesterday's Day: %d Month: %m, Year: %Y\n",
   localtime mktime 0, 0, 0, $mday, $mon, $year );

通过此mktime-localtime 往返发送值很重要,因为这是它们标准化的方式 - 例如因为从该月的第一天减去了 1; mktime() 的工作是将其重新规范化为上个月的最后一天(如果是 1 月,则必须将年份回滚,等等......)

【讨论】:

    猜你喜欢
    • 2017-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多