【问题标题】:convert the systemdate in iso 8601 format in perl在 perl 中将 systemdate 转换为 iso 8601 格式
【发布时间】:2014-06-03 07:47:49
【问题描述】:

我希望将系统日期转换为 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 作为子,不是方法,通常是 POSIX
  • 自然其他人已经解决了这个问题:DateTime::Format::ISO8601

标签: perl iso8601


【解决方案1】:

Perl 的 DateTime 包 (on CPAN) 可以非常轻松地为您生成 ISO8601 日期,但有一点需要注意。

DateTime 返回的字符串将采用 UTC,但没有时区说明符。这应该没问题,因为根据 ISO8601 规范,如果未指定时区,则应假定为 UTC。但是,并非所有解析器都完全遵守规范。为了使我的日期更可靠,我在从DateTime 得到的字符串末尾附加了一个Z,所以这是我推荐的代码:

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

【讨论】:

  • DateTime->now()->format_cldr("yyyy-MM-dd'T'HH:mm:ssZ") 是一种更动态(尽管很冗长)的附加偏移量的方式。在这种情况下,+00:00 将被附加而不是 Z,但这对于 ISO 8601 来说仍然足够。
  • @bart-b 你有没有提到 ISO8601 规范说应该假设 UTC?我只看到文档说如果 Z 丢失,则假定为当地时间。
【解决方案2】:

您应该使用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

【讨论】:

    【解决方案3】:

    Time::PieceTime::Seconds 自 2007 年以来已作为 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-
    • @DaveCross Time::Piece 继续 是 Core Perl 的一部分,并且使用现代功能没有问题——尤其是因为硬编码行尾远比强制执行较新的 Perl 版本。
    • @VectorGorgoth:我很清楚 Time::Piece 仍然是核心 Perl 的一部分。我不知道你为什么认为你需要提醒我。
    【解决方案4】:

    这仅使用标准包:

    #! /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";
    

    【讨论】:

      【解决方案5】:

      评论后更新。 OP 需要 UTC ISO 日期+时间格式的当前日期,精度为毫秒, 像这样“2014-07-02T10:48:07.124Z”。其他答案没有提供。 一条评论错误地指出“实际问题是关于日期差异”。 页面标题显示“在 perl 中将 systemdate 转换为 iso 8601 格式”。 OP 的第一行说“我希望将系统日期转换为 ISO 8601 格式。”。

      来自原文:

      Current output is:
      
          Time zone *******-> "-04:00"
          Current date *******-> "2014-06-03T03:46:07-04:00"
      
      I want the current date to be in format "2014-07-02T10:48:07.124Z",
      So that I can compute the difference between the two.'
      

      是的,最后一句不清楚,但想要的是当前 UTC ISO 格式的日期+时间。所有其他答案都同意。 在短语“以便我可以计算两者之间的差异。”中, “两个”是指“当前日期”和“时区”,因为那些 在给出的示例中打印。 但是,这没有任何意义,因为差异不取决于日期+时间, 但日期+时间取决于差异(假设 OP 想要 从本地时间减去时区)。

      更好的措辞是:

      I want the current date to be in format "2014-07-02T10:48:07.124Z",
      so can I compute the difference between local time and the time zone?
      

      但是,由于 UTC 时间已经是 通过使用给定代码的第一行中的 time() 然后利用 gmtime() 而不是 localtime()。

      这里有两种解决方案:

      方法一:

      #! /usr/bin/perl -l
      use Time::HiRes qw( time );
      use DateTime;
      print DateTime->from_epoch( epoch => time )->strftime( "%FT%T.%3NZ" );
      

      方法二:

      #! /usr/bin/perl -l
      use Time::HiRes qw( gettimeofday );
      use POSIX       qw( strftime );
      ($isec,$usec) = gettimeofday;
      printf strftime("%FT%T.%%03dZ\n", gmtime $isec), $usec / 1000;
      

      【讨论】:

      • 实际问题是关于日期差异。日期格式正是 OP 试图这样做的方式。
      猜你喜欢
      • 2018-05-26
      • 2015-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多