在Perl中将系统日期转换为ISO 8601格式

13

我希望将系统日期转换为ISO 8601格式。代码:

my $now = time();
my $tz = strftime("%z", localtime($now));
$tz =~ s/(\d{2})(\d{2})/$1:$2/;
print "Time zone *******-> \"$tz\"\n";
# ISO8601
my $currentDate =  strftime("%Y-%m-%dT%H:%M:%S", localtime($now)) . $tz;
print "Current date *******-> \"$currentDate\"\n";

当前输出为:

Time zone *******-> "-04:00"
Current date *******-> "2014-06-03T03:46:07-04:00"

我希望当前日期的格式为“2014-07-02T10:48:07.124Z”,以便我可以计算两者之间的差异。


哪个模块提供了 strftime 函数? - choroba
@choroba 通常作为子程序而非方法,它通常是POSIX。 - ysth
4
自然,其他人已经解决了这个问题:DateTime::Format::ISO8601 - Biffen
4个回答

16

你应该使用gmtime()而不是localtime()来获取UTC的分解时间值。

use POSIX qw(strftime);
my $now = time();
print strftime('%Y-%m-%dT%H:%M:%SZ', gmtime($now)), "\n";

输出:

2014-06-04T10:17:17Z

你可能想使用'%FT%TZ'作为字符串。这个格式相同,但更短,并明确选择了ISO 8601日期格式(%F)和ISO 8601时间格式(%T),而不是工程ISO 8601。 - Christian Hujer

15

Perl的DateTime包 (CPAN上的链接) 可以非常容易地为您生成ISO8601日期,但有一个注意事项。

DateTime返回的字符串将是UTC时间,但没有时区说明符。这应该没问题,因为根据ISO8601规范,如果未指定时区,则应假定为UTC。然而,并非所有解析器都完全遵循规范。为了使我的日期更加健壮,我会在从DateTime获取的字符串末尾添加Z,因此这是我推荐的代码:

use DateTime;
my $now = DateTime->now()->iso8601().'Z';

2
DateTime->now()->format_cldr("yyyy-MM-dd'T'HH:mm:ssZ") 是一种更动态(尽管冗长)的追加偏移量的方式。在这种情况下,将追加 +00:00 而不是 Z,但仍足以满足 ISO 8601 的要求。 - Tommy Stanton
3
@bart-b,你能提供ISO8601规范的参考文献说明应该假设使用UTC吗?我只看到过一些文档说如果缺少Z,则假定使用本地时间。 - bingles
DateTime->now->rfc3339 在这里更好,因为它已经支持添加时区。 - undefined

7
自2007年起,Time::PieceTime::Seconds 已经成为Perl的标准部分。
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Piece;

my $time = localtime;
say $time->datetime; # Time in ISO8601 format
say $time->tzoffset; # Time zone offset in seconds

# But tzoffset actually returns a Time::Seconds object
say $time->tzoffset->hours; # Time zone offset in hours (for example)

此脚本无法在 Perl v5.8.8 上运行,需要使用 Perl v5.10.0。 - user3616128
@DaveCross Time::Piece 仍然是 Core Perl 的一部分,使用现代特性并不成问题——尤其是硬编码行结尾比强制使用相对较新的 Perl 版本更糟糕。 - Vector Gorgoth
4
@VectorGorgoth:我非常清楚Time::Piece仍然是Perl核心的一部分。我不确定你为什么觉得需要提醒我。 - Dave Cross

-2

这只使用标准包:

#! /usr/bin/perl
use POSIX qw(strftime);
use Time::HiRes qw/gettimeofday/;
  
sub iso8601
{
  my ($s, $f) = split (/\./, gettimeofday);
  strftime ('%Y-%m-%dT%H:%M:%S.'.$f.'%z', localtime ($s))
}

print iso8601, "\n";

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接