1

我有系统时区为 EST 的服务器

它被设置为

# timedatectl set-timezone EST
# timedatectl 
  Local time: Tue 2019-06-18 03:29:42 EST
  Universal time: Tue 2019-06-18 08:29:42 UTC
    RTC time: Tue 2019-06-18 08:29:42
    Time zone: EST (EST, -0500)
    NTP enabled: yes
    NTP synchronized: no
    RTC in local TZ: no
    DST active: n/a

然后在我的perl代码中,我尝试检测时区并将时间转换为 UTC 并且由于某种原因,时区被检测为 EDT。目前(夏季)EST 是我们在 EDT 之后的一个

我的 perl 代码是

# cat test.cgi # code file is named test.cgi
#!/usr/bin/perl -w

use Date::Manip;

print "Local time: ".UnixDate("now","%Y-%m-%d %H:%M:%S %Z")."\n";

# get local system timezone
my $TZ = UnixDate("now","%Z");

# convert time to GMT 
my $dtlocal =  Date_ConvTZ(ParseDate(UnixDate("now","%g")),$TZ,"GMT");

# format GMT time
my $dt =  UnixDate($dtlocal,"%Y-%m-%d %H:%M:%S"); 

print "Timezone: $TZ\n";
print "UTC time: $dt\n";

我执行脚本

# date
Tue Jun 18 04:17:56 EST 2019
# date -u
Tue Jun 18 09:17:58 UTC 2019
# ./test.cgi 
Local time: 2019-06-18 04:18:00 EDT
Timezone: EDT
UTC time: 2019-06-18 08:18:00

Date::Manip 错误检测时区的原因是什么?还有其他检测系统时区的好方法吗?

更新。

我刚刚发现 POSIX 正确检测时区。所以,问题在于 Date::Manip

 use POSIX;
 print strftime("%Z", localtime()), "\n";
4

2 回答 2

2

Date::Manip::TZ 文档有一个关于确定系统时区的部分。如果您向下滚动一点,您会找到一个列表,其中列出了使用哪些方法(以及以什么顺序)来确定系统时区,具体取决于您是在 Unix 还是 Windows 下运行。

根据您在问题中发布的内容,它似乎正确读取了当地时间,但未能识别正确的时区,因此您应该能够通过查看使用的 TZ 识别方法列表找到根本问题在您的操作系统上。(即,对于 Unix,检查$::TZ,然后是环境设置,然后zone,等等,直到您找到一个既存在又列出了错误时区的设置)TZ/etc/TIMEZONE

于 2019-06-18T10:02:58.193 回答
2

查找时区的一种方法是使用DateTime::TimeZone。与DateTime一起用于其他需求

use warnings;
use strict;
use feature 'say';

use DateTime; 
use DateTime::TimeZone; 

my $tz = DateTime::TimeZone->new(name => "local");
say $tz->name();                                   #--> America/Los_Angeles


my $dt = DateTime->now(time_zone => "local");
say "local: $dt";                             #--> local: 2019-06-18T09:57:58

$dt->set_time_zone("UTC"); 
say "UTC: $dt";                               #--> UTC: 2019-06-18T16:57:58

请参阅文档以获取详细信息,至少对于DateTime::TimeZone 构造函数

另请注意他们建议不要在$tz->short_name下使用“短”名称(“EST”) ...


一旦你正在使用DateTime也可以有偏移量

my $dt = DateTime->now(time_zone => 'local');

say $dt->offset/(60*60);                       #--> -7

say $dt->strftime("%z");                       #--> -0700

方法offset以秒为单位返回时区偏移量。

我们通常期望的strftime提供格式;文档说“任何与 POSIX 标准的偏差都可能是一个错误。 ”一个完整的时间戳示例:$dt->strftime('%Y-%m-%dT%H:%M:%S%z').

于 2019-06-18T10:02:21.250 回答