【问题标题】:How can I parse dates and convert time zones in Perl?如何在 Perl 中解析日期和转换时区?
【发布时间】:2010-09-29 12:44:42
【问题描述】:

我在 Perl 中使用了localtime 函数来获取当前日期和时间,但需要解析现有日期。我有以下格式的 GMT 日期:“20090103 12:00”我想将其解析为我可以使用的日期对象,然后将 GMT 时间/日期转换为我当前的时区,该时区目前是东部标准时间.因此,我想将“20090103 12:00”转换为“20090103 7:00”任何有关如何执行此操作的信息将不胜感激。

【问题讨论】:

标签: perl datetime parsing date timezone


【解决方案1】:

因为 Perl 内置的日期处理接口有点笨拙,并且您最终会传递大约六个变量,所以更好的方法是使用 DateTimeTime::Piece。 DateTime 是全能歌唱、全能跳舞的 Perl 日期对象,您可能最终会想要使用它,但 Time::Piece 更简单且完全适合此任务,具有与 5.10 一起发布的优势,并且该技术是两者基本相同。

这是使用 Time::Piece 和 strptime 的简单灵活的方法。

#!/usr/bin/perl

use 5.10.0;

use strict;
use warnings;

use Time::Piece;

# Read the date from the command line.
my $date = shift;

# Parse the date using strptime(), which uses strftime() formats.
my $time = Time::Piece->strptime($date, "%Y%m%d %H:%M");

# Here it is, parsed but still in GMT.
say $time->datetime;

# Create a localtime object for the same timestamp.
$time = localtime($time->epoch);

# And here it is localized.
say $time->datetime;

为了对比,这里是手动方式。

由于格式是固定的,正则表达式就可以了,但如果格式发生变化,您将不得不调整正则表达式。

my($year, $mon, $day, $hour, $min) = 
    $date =~ /^(\d{4}) (\d{2}) (\d{2})\ (\d{2}):(\d{2})$/x;

然后将其转换为 Unix 纪元时间(自 1970 年 1 月 1 日以来的秒数)

use Time::Local;
# Note that all the internal Perl date handling functions take month
# from 0 and the year starting at 1900.  Blame C (or blame Larry for
# parroting C).
my $time = timegm(0, $min, $hour, $day, $mon - 1, $year - 1900);

然后回到你的当地时间。

(undef, $min, $hour, $day, $mon, $year) = localtime($time);

my $local_date = sprintf "%d%02d%02d %02d:%02d\n",
    $year + 1900, $mon + 1, $day, $hour, $min;

【讨论】:

  • 即使在自己滚动时,至少从 Perl 5.6.0 开始,在 Unix 和 Windows 系统上都可以use POSIX qw(strftime)。这使得最终的“自己动手”变得更短且更易于维护:my $local_date = strftime "%Y%m%d %H:%M\n", localtime($time);.
  • $time->localtime->tzoffset AFAICT 返回当前时间的偏移量,而不是给定时间。
  • @ysth 是的,这没关系,除非我们想担心历史时区的变化,我肯定不会。 DST 可能很重要。
  • @Dfr 是的,这是其设计的一部分。它们不是附带无数的格式化程序,而是插件。请参阅文档中的 Formatters and Stringification。缺点是 DateTime 甚至不提供开箱即用的最简单格式。好处是there are a lot of formatters
  • @ysth,已修复。 . .
【解决方案2】:

这是一个示例,使用DateTime 及其strptime 格式模块。

use DateTime;
use DateTime::Format::Strptime;

my $val = "20090103 12:00";

my $format = new DateTime::Format::Strptime(
                pattern => '%Y%m%d %H:%M',
                time_zone => 'GMT',
                );

my $date = $format->parse_datetime($val);

print $date->strftime("%Y%m%d %H:%M %Z")."\n";

$date->set_time_zone("America/New_York");  # or "local"

print $date->strftime("%Y%m%d %H:%M %Z")."\n";

$ perl dates.pl
20090103 12:00 UTC
20090103 07:00 EST


如果您想解析本地时间,这就是您的方法:)
use DateTime;

my @time = (localtime);

my $date = DateTime->new(year => $time[5]+1900, month => $time[4]+1,
                day => $time[3], hour => $time[2], minute => $time[1],
                second => $time[0], time_zone => "America/New_York");

print $date->strftime("%F %r %Z")."\n";

$date->set_time_zone("Europe/Prague");

print $date->strftime("%F %r %Z")."\n";

【讨论】:

  • 您缺少解析部分。
  • 哦,真的。我误以为他想使用本地时间输出。
【解决方案3】:

这就是我会做的......

#!/usr/bin/perl
use Date::Parse;
use POSIX;

$orig = "20090103 12:00";

print strftime("%Y%m%d %R", localtime(str2time($orig, 'GMT')));

您也可以使用Time::ParseDateparsedate() 代替Date::Parsestr2time()。请注意,事实上的标准 atm。似乎是 DateTime(但您可能不想使用 OO 语法来转换时间戳)。

【讨论】:

  • 优秀的替代品。在旧的 UNIX 上,不存在 Date::Time,但存在 Date::Parse。
【解决方案4】:

任你选:

毫无疑问,还有无数其他人,但他们可能是最有力的竞争者。

【讨论】:

  • Date::Calc 在 2009 年有相当多的活动。
  • 但我认为在 2009 年 1 月 4 日我撰写该评论时该活动尚未发生。但是,很高兴知道它正在被维护。随着 Perl 的发展,好的稳定模块不一定需要做很多工作。
【解决方案5】:
use strict;
use warnings;
my ($sec,$min,$hour,$day,$month,$year)=localtime();
$year+=1900;
$month+=1;
$today_time = sprintf("%02d-%02d-%04d %02d:%02d:%02d",$day,$month,$year,$hour,$min,$sec);
print $today_time;

【讨论】:

  • 此代码仅打印当前本地时间。它没有回答问题。
猜你喜欢
  • 2012-11-03
  • 1970-01-01
  • 2021-11-03
  • 2011-09-30
  • 2016-07-23
  • 2021-03-01
  • 1970-01-01
  • 2011-01-20
相关资源
最近更新 更多