【问题标题】:How I can I convert timezones in Perl?如何在 Perl 中转换时区?
【发布时间】:2011-01-20 17:36:20
【问题描述】:

我正在尝试在 Perl 中将日期/时间 GMT 0 转换为 GMT -6。

例如,DHCP 服务器租用时间的格式如下:

2010/02/18 23:48:37

我正在尝试将该时间转换为本地时区 (GMT -6),但需要它来遵守夏令时。

下面的脚本可能有点矫枉过正,但我​​不知道如何从这里开始。 (任何建议都会很棒)。

my $TIMESTART;

$TIMESTART = "2010/02/18 23:48:37";
$TIMESTART =~ s/\//-/g;

use DateTime;
use DateTime::TimeZone;

use DateTime::Format::MySQL;
my $dt = DateTime::Format::MySQL->parse_datetime($TIMESTART);

my $tz = DateTime::TimeZone->new( name => 'America/Chicago' );

print $tz->offset_for_datetime($dt) . "\n";

它将输出以下行:

2010-02-18T23:48:37
-21600

我需要能够将 -21600 添加到日期以获得 GMT -6 的本地时区,但我不知道如何解决这个问题。

【问题讨论】:

  • 在英国以外使用,请使用UTC,而不是GMT作为国际标准时间。一些系统假定 GMT 表示 UTC,而另一些系统假定 GMT/BST,如英国所用。
  • 我想有不止一种方法可以做到这一点。

标签: perl datetime gmt


【解决方案1】:

调用set_time_zone方法2次:

my $dt = DateTime::Format::MySQL->parse_datetime($TIMESTART);
$dt->set_time_zone('UTC'); ## set timezone of parsed date time
$dt->set_time_zone('America/Chicago'); ## change timezone in safe way

print DateTime::Format::MySQL->format_datetime($dt),"\n"; ## check the result

它是如何工作的:

  • 当您创建 DateTime 对象但未指定时区时,会设置“浮动”时区
  • 第一次调用set_time_zone 将时区更改为UTC,无需转换
  • 第二次调用set_time_zoneUTC 更改为America/Chicago

【讨论】:

  • 第二次运行它是我缺少的部分。可以,谢谢。
  • 感谢您的提示!我也没有意识到第二次调用 set_time_zone() 是关键。
  • 我没有尝试过上面创建DateTime对象的方法,但是如果你使用now()创建一个,或者从一个时间戳创建一个,它将具有UTC时区。 DateTime->now() 现在,或 DateTime->from_epoch(1582040334) 使用时间戳。如果您随后获得time_zone_long_name(),它将是UTC。 (注:我在 2020 年做这个,你的回答是从 2010 年开始的。)
【解决方案2】:

这会将 UTC 时间转换为 ETC 时间。 您还可以使用日期的 +FORMAT 参数以任何格式使用日期/时间。

日期 --date='TZ="ETC" 18:30'

【讨论】:

    【解决方案3】:

    Time::Piece 是一段非常轻量级的高质量代码。或者你可以只使用内置函数和strftimePOSIX::strptime

    【讨论】:

    • Time::Piece 用于显示日期,而不是日期数学。所有这一切都会让您获得小时偏移量,我什至不确定这个数字是否在夏令时安全。没有日期数学函数。
    【解决方案4】:

    不要在 `DateTime::Format::MySQL->parse_datetime` 中使用时区

    在执行与时区有关的任何事情时,您不应该使用它是有充分理由的。为什么?因为它绝对不支持任何时区。请参阅文档:

    所有的解析方法都将返回的DateTime对象的时区设置为浮动时区,因为MySQL不提供时区信息。 (来源:MetaCPAN: DateTime::Format::MySQL。)

    如果您使用它,它将假定您的系统时区为默认值。这可能不是您要转换的时区! (虽然这对很多人都有效,但它只在您的服务器不更改其默认时区时才有效——在那之后,一切都会中断。)

    使用`DateTime->new()`,因为它确实支持时区

    使用DateTime直接提供的构造函数(来源:MetaCPAN: DateTime.):

    my $dt = DateTime->new(
        year       => 1966,
        month      => 10,
        day        => 25,
        hour       => 7,
        minute     => 15,
        second     => 47,
        nanosecond => 500000000,
        time_zone  => 'America/Chicago',
    );
    

    用 DateTime 转换时区

    您的开始时区 是您输入构造函数的任何内容(即上面示例中的America/Chicago)。要将时间转换为结束时区,请使用set_time_zone()

    工作代码

    在下面的代码中,时间从一个时区转换到另一个时区,并且每次都能完美地转换,即使您使用 Linux 操作系统为新加坡时间的服务器将纽约时间转换为旧金山时间。

    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

    【讨论】:

      【解决方案5】:
      #!/usr/bin/perl -w
      ($sec,$min,$hour,$mday,$mon,$year) = gmtime(time+21600);
      $year = $year + 1900;
      printf("%02d:%02d:%02d %02d.%02d.%04d\n", $hour,$min,$sec,$mday,$mon,$year);
      

      【讨论】:

      • 这有时完全是错误的,因为它忽略了问题中“但需要它来尊重夏令时”的部分。
      猜你喜欢
      • 2010-09-29
      • 1970-01-01
      • 2011-01-28
      • 1970-01-01
      • 2021-12-07
      • 1970-01-01
      • 1970-01-01
      • 2020-06-08
      相关资源
      最近更新 更多