如何在 Perl 中更改日期时间值的时区?

Posted

技术标签:

【中文标题】如何在 Perl 中更改日期时间值的时区?【英文标题】:How can I change the timezone of a datetime value in 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)),我需要更改什么?

提前致谢,

安德斯

【问题讨论】:

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

【讨论】:

非常干净的答案。以下是时区列表:en.wikipedia.org/wiki/List_of_tz_database_time_zones【参考方案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";'

【讨论】:

TLA 时区不明确且定义不明确。最好使用zoneinfo 名称:TZ=Europe/Berlin perl ... 这里是直接指向list of valid Time Zone strings aka Zone.tab 的链接。【参考方案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

【讨论】:

以上是关于如何在 Perl 中更改日期时间值的时区?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django 中自定义数据库连接设置的时区?

如何更改 cPanel 日期时区? [复制]

如何在python烧瓶中获取具有本地时区的模板文件的修改日期

更改熊猫中日期时间列的时区并添加为分层索引

如何在 aix 中获取具有给定值的上一个日期?

Oracle SQL:从时间戳时区中提取日期和时间