【问题标题】:How do I get yesterday's date in perl?我如何在perl中获取昨天的日期?
【发布时间】:2020-12-11 09:27:12
【问题描述】:

目前我使用下面的日期来获取今天的日期。我需要使用这个来获取昨天的日期。我怎样才能得到那个?

my $today = `date "+%Y-%m-%d"`;

【问题讨论】:

  • 这询问的是“昨天”,但该示例使用了 HMS ...您确实也需要时间,还是只需要日期?
  • 实际上@Heyddo 回答对我有用。但是我在上面使用时间戳创建目录。但我用 \n 得到它。 ed :- 2019-05-14\n 但我没有通过任何输入.. 知道这是什么原因吗?
  • "但我用 \n 得到它。" - 反引号返回它;你需要chomp
  • 其实我今天和昨天都想要。所以我把今天使用上面,现在我可以把昨天使用今天作为@Heyddo 的答案
  • 对于不存在的时间(例如,纽约的 2019-03-10T02:30:00 前 1 天),您想要什么输出?

标签: perl date


【解决方案1】:

如果你想要昨天的日期:

use DateTime qw( );

my $yday_date =
   DateTime
      ->now( time_zone => 'local' )
      ->set_time_zone('floating')
      ->truncate( to => 'day' )
      ->subtract( days => 1 )
      ->strftime('%Y-%m-%d');

例如,在 2019 年 5 月 14 日 01:00:00 在纽约,它会在 2019 年 5 月 13 日返回。

例如,在 2019 年 11 月 4 日 00:00:00 在纽约,它会在 2019 年 11 月 3 日返回。

请注意,使用->now( time_zone => 'local' )->set_time_zone('floating')->truncate( to => 'day' ) 代替->today( time_zone => 'local' ) 以避免this problem


如果您想要提前一天的时间:

use DateTime qw( );

my $yday_datetime =
   DateTime
      ->now( time_zone => 'local' )
      ->subtract( days => 1 )
      ->strftime('%Y-%m-%d %H:%M:%S');

例如,在 2019 年 5 月 14 日 01:00:00 在纽约,它会在 2019 年 5 月 13 日 01:00:00 返回。

例如,在 2019 年 3 月 10 日 12:00:00 在纽约,它会在 2019 年 3 月 9 日 12:00:00 返回。

例如,在 2019 年 3 月 11 日 02:30:00 在纽约,它会导致错误。由于切换到夏令时,2019-03-10 02:30:00 不存在。


如果您想要提前 24 小时的时间:

use DateTime qw( );

my $yday_datetime =
   DateTime
      ->now( time_zone => 'local' )
      ->subtract( hours => 24 )
      ->strftime('%Y-%m-%d %H:%M:%S');

例如,在 2019 年 5 月 14 日 01:00:00 在纽约,它会在 2019 年 5 月 13 日 01:00:00 返回。

例如,在 2019 年 3 月 10 日 12:00:00 在纽约,它会在 2019 年 3 月 9 日 11:00:00 返回。

例如,在 2019 年 3 月 11 日 02:30:00 在纽约,它会在 2019 年 3 月 10 日 01:30:00 返回。

【讨论】:

  • 我必须在截断时使用day 而不是days 以防止出现以下异常:Validation failed for type named TruncationLevel declared in package DateTime::Types (C:/Strawberry/perl/vendor/lib/DateTime/Types.pm) at line 135 in sub named (eval) with value "days"
  • @nck 确实。固定
【解决方案2】:

使用DateTime 模块

use strict;
use warnings;
use feature 'say';

use DateTime;

my $today = DateTime->today(time_zone => 'local');

my $yesterday = $today->clone->add(days => -1);

say $yesterday->ymd;  #--> 2019-05-13

或直接

my $yesterday = DateTime->today(time_zone => 'local')->add(days => -1);

现在这些对象几乎可以用来做任何与日期时间相关的事情。

要以问题的格式提取字符串,请使用$yesterday->ymd,因为ymd 的默认格式是%Y-%m-%d。使用strftime 方法可以获得几乎任意格式。


没有理由为这样的工作使用系统设施。更重要的是,该模块更加复杂和圆润,适合各种奇怪的案例和需求。

一个例子:在某些日期时间,随着夏令时的开始,某些时间段不存在。 2003-04-06 的文档offer an example,当 01:59:59 “跳转”到 03:00:00 并且那个小时已经过去了。该模块通过抛出错误来处理正确使用此类(不存在时间)的尝试。

如果您需要对日期进行任何处理,那么使用系统的 date 甚至不是一个选项,因为您返回的只是一个字符串,您必须手动解析它以供进一步使用。


已经补充说,事实上,时间也是如此,而不仅仅是日期。那么,例如

my $today = DateTime->now(time_zone => 'local');

say $today->strftime("%Y%m%d_%H.%M.%S");         #--> 20190522_22.44.23

my $yesterday = $today->clone->add(days => -1);

say $yesterday->strftime("%Y%m%d_%H.%M.%S");     #--> 20190521_22.44.23

where 方法 now“保留”(本地)时间以及日期(todaytruncate-ed now)。

【讨论】:

  • 注意:这(正确地)在不存在的时间(纽约 2019-03-10T02:30 前 1 天)失败。如果您只想要日期(而不是时间),那么您可以使用 ->set_time_zone('floating') 来阻止它失败。
  • @zdim 只是我很好奇。是否可以运行一次并使用它几天?例如:- 使用我今天使用的日期时间(YYYY-MM-DD-HH-MM-SS)使用今天我可以使用昨天或前 X 天而不每次都运行吗?
  • @Debugger 如果我得到你想要的,那将是答案中的第二种方式(“或直接”)?比如,my $d_N_back = DateTime->today(time_zone=>"local")->add(days=>-$N);(其中$N 有数字)。现在这是一个您可以使用的对象。如果您希望获得准备好的字符串,请继续该链条:my $str = DateTime->[as above]->ymd;。或者,对于更具体的格式,->strftime(...)。这是你的意思吗?
  • @Debugger 当我再次阅读时,我不明白“每次都不运行”......?一旦你拥有其中一个,你就可以在一个声明中从中得到任何其他的一天——这就是你想要的“今天使用我可以在昨天还是 X 天前”?喜欢$N_back = $today->clone->add(days=>-$N);。这里clone$today 生成另一个对象,所以你保留$today 并获得一个新对象,用于$N 前几天。或者,要获取字符串,$N_back_str = $today->clone->add(days=>-$N)->ymd;
  • @zdim 这是事情。我正在创建 perl 脚本,我需要使用时间戳创建目录。在我使用 Y-M-D 之前,但现在我计划使用 Y-M-D-H-M-S,以防脚本运行很少一天中的次数。你上面的那个给出了 2019-05-23T00:00:00 这个输出。谢谢你的帮助。
【解决方案3】:

我建议使用 DateTime(如 ikegami 的回答中所述)。但如果您不想安装 CPAN 模块,此方法仅使用标准 Perl 安装中可用的功能。

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use Time::Local;
use POSIX 'strftime';

# Get the current date/time
my ($sec, $min, $hr, $day, $mon, $yr) = localtime;

# Get the epoch seconds for midday today
# (we use midday to eliminate potential problems
# when entering or leaving daylight savings time)
my $midday = timelocal(0, 0, 12, $day, $mon, $yr);

# Subtract a day's worth of seconds from the epoch
my $midday_yesterday = $midday - (24 * 60 * 60);

# Convert that epoch value to a string date using
# localtime() and POSIX::strftime().
my $yesterday = strftime('%Y%m%d', localtime($midday_yesterday));

say $yesterday;

【讨论】:

    【解决方案4】:

    Time::Moment,就在昨天的日期:

    use strict;
    use warnings;
    use Time::Moment;
    my $yesterday = Time::Moment->now->minus_days(1)->strftime('%Y-%m-%d');
    

    Time::Moment 适用于瞬间和偏移,而不是时区,因此,如果您想要本地时区中“一天前”的确切日期和时间(如 DateTime 示例中所示),您可以使用 Time::Moment::Role::TimeZone

    use strict;
    use warnings;
    use Time::Moment;
    use Role::Tiny ();
    my $class = Role::Tiny->create_class_with_roles('Time::Moment', 'Time::Moment::Role::TimeZone');
    my $yesterday = $class->now->minus_days(1)->with_system_offset_same_local; # 1 day ago
    my $yesterday = $class->now->minus_days(1)->with_system_offset_same_instant; # 24 hours ago
    

    如果当前时间在本地时区的前一天不存在,则同样需要注意。

    【讨论】:

      【解决方案5】:
      my $yesterday = `date -d yesterday +%Y%m%d-%H%M%S`;
      

      【讨论】:

      • 感谢您的帮助,所以如果我需要前天我可以添加-2d?
      • 日期 -d -2days +%Y%m%d
      • 这并不总是有效。它有时会给出一个小时的时间。 (例如,它在纽约为20190310-120000 提供20190309-110000。)
      • 对这么简单的事情使用外部程序并不是一个好主意。它会降低代码的可移植性并使其不必要地变慢。
      【解决方案6】:

      使用反引号字符串有一些怪癖......我通常喜欢那个运算符。

      让我推荐使用Time::Piece 模块提供的localtime() 函数(有一个bulitin localtime() 函数,但来自Time::Piece 的函数更棒:)

      
      use Time::Piece;
      
      my ($t, $today, $yesterday);
      
      $t = localtime();
      $today = sprintf('%04d/%02d/%02d', $t->year, $t->mon, $t->mday);
      
      $t = localtime(time() - 86400);
      $yesterday = sprintf('%04d/%02d/%02d', $t->year, $t->mon, $t->mday);
      
      

      【讨论】:

      • 这并不总是有效。它有时会给出今天的日期,有时会给出两天前的日期。 Time::Piece 是一个糟糕的模块,因为它使这类错误非常容易产生。
      • @ikegami 我认为我的示例代码的数学错误,而不是 Time::Piece。 :-) 恕我直言 Time::Piece 与它的记录方式一样好。我可能不应该使用时间数学来计算日期......
      • Re "我认为我的示例代码的数学错误",我也是。这绝对是对模块的滥用。 (你想要localtime(time()) - 86400 或者只是localtime() - 86400 而不是localtime(time() - 86400))但是模块鼓励这种类型的错误的事实是模块的问题。
      猜你喜欢
      • 2011-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-05
      相关资源
      最近更新 更多