注意 在发布和编辑后,问题和标题已更改,以坚持要求“support of non-standard”缩写。
但是,通常建议不要使用短名称,因为该答案的第二部分已经详细讨论过。更重要的是,在这个问题的上下文中,这显然是不行的,因为没有程序可以知道任意缩写(也没有任何“标准”)。
一旦提供了到接受名称的映射,那么这将成为一个非问题,并且在答案中也已考虑到这一点。因此,我将保留此答案,并稍作修改。
使用DateTime::Format::ISO8601 从您的字符串构建一个DateTime 对象,或者通常使用DateTime::Format::Strptime。然后根据需要使用DateTime 来处理它
use warnings;
use strict;
use feature 'say';
use DateTime::Format::ISO8601;
use DateTime;
my $dt_string = shift or die "Usage: $0 datetime-ISO8601\n";
my $fmt = DateTime::Format::ISO8601->new();
my $dt = $fmt->parse_datetime($dt_string);
say $dt->time_zone->name;
$dt->set_time_zone("America/Chicago");
say $dt->time_zone->name;
这使用DateTime::set_time_zone 来转换(更改)对象上的时区。
问题要求使用时区缩写名称进行转换。但是有一个问题:缩写名称没有任何标准,可能只是本地约定,不验证/使用解析器的方法......甚至可能是模棱两可的。
这在很多地方都有讨论。 DateTime::TimeZone 中的简短摘要,在 short_name_for_datetime 方法下,表示“短名称”(如要求的缩写)
强烈建议您不要将这些名称用于显示以外的任何内容。这些名称并非官方名称,其中许多只是 Olson 数据库维护者的发明。此外,这些名称并不是唯一的。例如,在 -0500 和 +1000/+1100 处都有一个“EST”。
(原重点)
仍然尝试处理用户出现的缩写的一种方法是使用all_names 从DateTime::TimeZone 到grep 其输出感兴趣的缩写。例如,
grep { /P(?:S|D)?T/ } DateTime::TimeZone->all_names
返回(一个列表)一个唯一的字符串PST8PDT。该字符串在我尝试过的所有方法下似乎都有效,并且可以正确地在 DateTime 对象上设置时区。然而,正确的是,对于/E(?:S|D)?T/,这将返回列表CET EET EST EST5EDT MET WET;不好用。
很明显,这既不系统也不可靠——就像缩写一样,一开始就不是。
最好的办法是构建某种本地查找,它将您的简称转换为正确的名称,以便您知道它在您的工作中是正确的。然后,可以将添加到 OP(后来更改)的存根填充到
use DateTime;
use DateTime::Format::ISO8601;
sub convert_time_zone_for_ISO8601
{
my ($iso, $tz) = @_;
# Provide a lookup/mapping that knows locally used abbreviations
#my $tz_name = convert_local_short_name($tz);
my $tz_name = 'America/New_York'; # for a working example
# Returns a DateTime object (or generate a string in a desired format)
return DateTime::Format::ISO8601->new
-> parse_datetime($iso)
-> set_time_zone($tz_name);
}
my $dt = convert_time_zone_for_ISO8601('2019-09-17T16:15:20Z', 'ET');
# Sole stringification doesn't include timezone but there are other methods
say $dt->time_zone_short_name;
say $dt->time_zone_long_name;
say $dt->strftime("%F %T %{time_zone_short_name}");
say $dt->strftime("%a, %d %b %Y %H:%M:%S %z"); # RFC822-conformant
(请参阅有关各种打印方法的文档说明。)
构建返回对象的链式方法使用可接受的时区名称提供解析和时区更改。
为了使其与缩写一起使用,代码显然需要将本地使用的感兴趣的缩写转换(映射)到用户提供的正确时区名称。
在上面的 sn-p 中,它有一个占位符子例程,例如,它可以在模块中使用散列,其中包含正确的映射,或者更好地来自可以由其他软件管理的 JSON 文件好吧;或通过查询数据库表或本地服务或某种方式。