如何在 Perl 中将日期/时间转换为纪元时间(自 1970 年以来的 UNIX 时间/秒)?
题
给定一个日期/时间数组(年、月、日、时、分、秒),如何将其转换为纪元时间,即自 1970-01-01 00:00:00 GMT 以来的秒数?
奖金问题:如果将日期/时间作为字符串给出,您首先如何将其解析为 (y,m,d,h,m,s) 数组?
解决方案 2
这是获取 unix 时间的最简单方法:
use Time::Local;
timelocal($second,$minute,$hour,$day,$month-1,$year);
请注意参数的相反顺序,一月是 0 月。有关更多选项,请参阅 约会时间 来自 CPAN 的模块。
至于解析,请参见 日期::解析 来自 CPAN 的模块。如果您确实需要了解日期解析,那么 日期::马尼普 可能会有所帮助,尽管它自己的文档警告您远离它,因为它带有很多包袱(例如,它知道常见的商务假期之类的事情)并且其他解决方案要快得多。
如果您碰巧知道要解析的日期/时间的格式,那么一个简单的正则表达式可能就足够了,但您最好使用适当的 CPAN 模块。例如,如果您知道日期始终采用 YMDHMS 顺序,请使用 CPAN 模块 日期时间::格式::ISO8601.
作为我自己的参考,如果没有别的,下面是我用于应用程序的函数,其中我知道日期将始终按 YMDHMS 顺序排列,并且全部或部分“HMS”部分是可选的。它接受任何分隔符(例如“2009-02-15”或“2009.02.15”)。它返回相应的unix时间(自1970-01-01 00:00:00 GMT以来的秒数)或-1,如果它无法解析它(这意味着你最好确保你永远不会合法地需要解析日期1969- 12-31 23:59:59)。它还假定“69”之前的两位数年份 XX 指“20XX”,否则“19XX”(例如,“50-02-15”表示 2050-02-15,但“75-02-15”表示 1975- 02-15)。
use Time::Local;
sub parsedate {
my($s) = @_;
my($year, $month, $day, $hour, $minute, $second);
if($s =~ m{^\s*(\d{1,4})\W*0*(\d{1,2})\W*0*(\d{1,2})\W*0*
(\d{0,2})\W*0*(\d{0,2})\W*0*(\d{0,2})}x) {
$year = $1; $month = $2; $day = $3;
$hour = $4; $minute = $5; $second = $6;
$hour |= 0; $minute |= 0; $second |= 0; # defaults.
$year = ($year<100 ? ($year<70 ? 2000+$year : 1900+$year) : $year);
return timelocal($second,$minute,$hour,$day,$month-1,$year);
}
return -1;
}
其他提示
要解析日期,请查看 日期::解析 在 CPAN 中。
$ENV{TZ}="GMT";
POSIX::tzset();
$time = POSIX::mktime($s,$m,$h,$d,$mo-1,$y-1900);
我知道这是一个老问题,但我想我会提供另一个答案。
Time::Piece
是 Perl 5.9.5 的核心
这允许通过以下方式解析任意格式的时间 strptime
方法。
例如。:
my $t = Time::Piece->strptime("Sunday 3rd Nov, 1943",
"%A %drd %b, %Y");
有用的部分是 - 因为它是一个重载对象,所以您可以使用它进行数字比较。
例如
if ( $t < time() ) { #do something }
或者,如果您在字符串上下文中访问它:
print $t,"\n";
你得到:
Wed Nov 3 00:00:00 1943
有许多访问器方法允许进行一些其他有用的基于时间的转换。 https://metacpan.org/pod/Time::Piece
从 CPAN 获取日期::Manip, , 然后:
use Date::Manip;
$string = '18-Sep-2008 20:09'; # or a wide range of other date formats
$unix_time = UnixDate( ParseDate($string), "%s" );
编辑:
Date::Manip 又大又慢,但解析非常灵活,而且是纯 Perl 的。如果您在编写代码时很匆忙,并且知道运行代码时不会很匆忙,请使用它。
例如在启动时使用它来解析命令行选项,但不要使用它在繁忙的 Web 服务器上解析大量数据。
看 作者评论.
(感谢下面第一条评论的作者)
我最喜欢的日期时间解析器是 日期时间::格式::ISO8601 一旦你完成了这个工作,你将拥有一个 DateTime 对象,可以使用 epoch() 轻松转换为纪元秒
CPAN 上有很多日期操作模块。我特别喜欢的是 约会时间 你可以使用 strptime模块 解析任意格式的日期。CPAN 上还有许多 DateTime::Format 模块用于处理专门的日期格式,但 strptime 是最通用的。
为了进一步参考,一种内衬可以应用于,例如, !#/bin/sh
脚本。
EPOCH="`perl -e 'use Time::Local; print timelocal('${SEC}','${MIN}','${HOUR}','${DAY}','${MONTH}','${YEAR}'),\"\n\";'`"
请记住避免八进制值!
无论有或没有 CPAN 的帮助,这可能都是“有不止一种方法可以做到这一点”的更好例子之一。
如果您可以控制作为“日期/时间”传递的内容,我建议您选择 约会时间 路线,可以通过使用特定的 Date::Time::Format 子类,或者使用 DateTime::Format::Strptime 如果没有支持您古怪的日期格式(请参阅 日期时间常见问题解答 更多细节)。一般来说,如果你想对结果做任何严肃的事情,Date::Time 是最好的选择:CPAN 上很少有课程能够像肛门保持一样准确。
如果你期待奇怪的自由形式的东西,把它扔到 日期::解析的 str2time() 方法,它会给你一个自纪元以来的秒数值,然后你可以用你的邪恶方式,而不需要开销 日期::马尼普.
一个过滤器,可以将任何日期转换为各种 ISO 相关格式(以及阅读后谁会使用其他任何内容) 著作 Mighty Kuhn?)在标准输入上到标准输出上的自纪元以来的秒数时间可能有助于说明这两部分:
martind@whitewater:~$ cat `which isoToEpoch`
#!/usr/bin/perl -w
use strict;
use Time::Piece;
# sudo apt-get install libtime-piece-perl
while (<>) {
# date --iso=s:
# 2007-02-15T18:25:42-0800
# Other matched formats:
# 2007-02-15 13:50:29 (UTC-0800)
# 2007-02-15 13:50:29 (UTC-08:00)
s/(\d{4}-\d{2}-\d{2}([T ])\d{2}:\d{2}:\d{2})(?:\.\d+)? ?(?:\(UTC)?([+\-]\d{2})?:?00\)?/Time::Piece->strptime ($1, "%Y-%m-%d$2%H:%M:%S")->epoch - (defined ($3) ? $3 * 3600 : 0)/eg;
print;
}
martind@whitewater:~$
如果您只是在寻找命令行实用程序(即,不是从其他函数调用的东西),请尝试此脚本。它假设 GNU 日期的存在(几乎所有 Linux 系统上都存在):
#! /usr/bin/perl -w
use strict;
$_ = (join ' ', @ARGV);
$_ ||= <STDIN>;
chomp;
if (/^[\d.]+$/) {
print scalar localtime $_;
print "\n";
}
else {
exec "date -d '$_' +%s";
}
它的工作原理如下:
$ Time now
1221763842
$ Time yesterday
1221677444
$ Time 1221677444
Wed Sep 17 11:50:44 2008
$ Time '12:30pm jan 4 1987'
536790600
$ Time '9am 8 weeks ago'
1216915200