【问题标题】:How can I change the timezone of a datetime value in Perl?如何在 Perl 中更改日期时间值的时区?
【发布时间】:2011-01-11 17:48:02
【问题描述】:

使用此功能:

perl -e 'use Time::Local; print timelocal("00","00","00","01","01","2000"),"\n";'

它将返回一个纪元时间 - 但仅限于 GMT - 如果我想要 GMT+1 的结果(即系统本地时间 (TZ)),我需要更改什么?

提前致谢,

安德斯

【问题讨论】:

    标签: perl timezone solaris epoch


    【解决方案1】:
    use DateTime;
    my $dt   = DateTime->now;
    $dt->set_time_zone( 'Europe/Madrid' );
    

    【讨论】:

    【解决方案2】:

    纪元时间只有一个标准定义,基于 UTC,不同时区没有不同的纪元时间。

    如果你想找到offset between gmtime and localtime,请使用

    use Time::Local;
    @t = localtime(time);
    $gmt_offset_in_seconds = timegm(@t) - timelocal(@t);
    

    【讨论】:

      【解决方案3】:

      虽然 Time::Local 是一个合理的解决方案,但您最好使用更现代的 DateTime 面向对象的模块。这是一个例子:

      use strict;
      use DateTime;
      my $dt = DateTime->now;
      print $dt->epoch, "\n";
      

      对于时区,您可以使用 DateTime::TimeZone 模块。

      use strict;
      use DateTime;
      use DateTime::TimeZone;
      
      my $dt = DateTime->now;
      my $tz = DateTime::TimeZone->new(name => "local");
      
      $dt->add(seconds => $tz->offset_for_datetime($dt));
      
      print $dt->epoch, "\n";
      

      CPAN 链接:

      DateTime

      【讨论】:

        【解决方案4】:

        您只需要设置时区。试试:

        env TZ=UTC+1 perl -e '使用时间::本地;打印 timelocal("00","00","00","01","01","2000"),"\n";'

        【讨论】:

        【解决方案5】:

        Time::Local::timelocallocaltime 的倒数。结果将是您主机的当地时间:

        $ perl -MTime::Local -le \
            '打印标量 localtime timelocal "00","00","00","01","01","2000"'
        2000 年 2 月 1 日星期二 00:00:00

        您想要与localtime 对应的gmtime 吗?

        $ perl -MTime::Local' -le \
            '打印标量 gmtime timelocal "00","00","00","01","01","2000"'
        2000 年 1 月 31 日星期一 23:00:00

        您是否想要反过来,localtime 对应于 gmtime

        $ perl -MTime::Local -le \
            '打印标量本地时间 timegm "00","00","00","01","01","2000"'
        2000 年 2 月 1 日星期二 01:00:00

        【讨论】:

          【解决方案6】:

          另一个基于DateTime::Format::Strptime的例子

          use strict;
          use warnings;
          use v5.10;
          use DateTime::Format::Strptime;
          
          my $s = "2016-12-22T06:16:29.798Z";
          my $p = DateTime::Format::Strptime->new(
            pattern => "%Y-%m-%dT%T.%NZ",
            time_zone => "UTC"
          );
          
          my $dt = $p->parse_datetime($s);    
          $dt->set_time_zone("Europe/Berlin");
          say join ' ', $dt->ymd, $dt->hms; # shows 2016-12-22 07:16:29
          

          【讨论】:

            【解决方案7】:

            算法

            如果您想将时间值从一个时区更改为另一个时区,您必须能够同时指定两个时区。

            毕竟,如果您设置是否要将 "12:30" 转换为 GMT 或美国/东部或委内瑞拉时间,这意味着添加/减去一些小时或小时和分钟,您需要知道什么时区 是起始时区,否则,计算不知道加减多少。

            如果您使用DateTime->now;,则时区默认为系统时间,可能不是您要转换的时区。

            在下面的代码中,我演示了如何将 datetime 对象初始化为正确的起始时区 (fromtimezone) 以及如何将该时间转换为结束时区 (totimezone)...

            工作代码

            我在网上找不到安装了DateTime CPAN 模块的 Perl 沙箱。

            use strict;
            use DateTime;
            
            sub convertTimeZonesForTime {
                    my ($args) = @_;
            
                    my $time = $args->{time};
                    my $date = $args->{date};
                    my $totimezone = $args->{totimezone};
                    my $fromtimezone = $args->{fromtimezone};
                    my $format = $args->{format} || '%H:%M:%S';
            
                    my ($year, $month, $day) = map {int $_} split('-', $date);
                    my ($hour, $minute, $second) = map {int $_} split(':', $time);
            
                    $year ||= 1999 if !defined $year;
                    $month ||= 1 if !defined $month;
                    $day ||= 1 if !defined $day;
                    $hour ||= 12 if !defined $hour;
                    $minute ||= 30 if !defined $minute;
                    $second ||= 0 if !defined $second;
            
                    my $dt = DateTime->new(
                            year=>$year,
                            month=>$month,
                            day=>$day,
                            hour=>$hour,
                            minute=>$minute,
                            second=>$second,
                            time_zone => $fromtimezone,
                    );
                    my $formatter = new DateTime::Format::Strptime(pattern => $format);
                    $dt->set_formatter($formatter);
                    $dt->set_time_zone($totimezone);
            
                    return "$dt";
            }
            
            print(convertTimeZonesForTime({
                'totimezone'=>'America/Denver',
                'fromtimezone'=>'US/Eastern',
                'time'=>'12:30:00',
            }));
            

            输出:

            10:30:00

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2022-06-14
              • 2013-09-21
              • 2012-08-07
              • 2011-06-06
              • 1970-01-01
              • 1970-01-01
              • 2017-04-18
              • 2019-09-12
              相关资源
              最近更新 更多