Примечание. Вопрос и заголовок были изменены после того, как он был опубликован и отредактирован, чтобы настаивать на запросе «поддержки нестандартных» сокращений.
Однако обычно не рекомендуется использовать короткие имена, поскольку вторая часть этого ответа уже подробно обсуждалась. Более того, в контексте этого вопроса это явно недопустимо, поскольку ни одна программа не может знать произвольные сокращения (и для этого также нет никаких «стандартов»).
Как только будет предоставлено сопоставление с принятыми именами, это перестанет быть проблемой, и это также было учтено в ответе. Поэтому я оставляю этот ответ как есть, с небольшими правками.
Используйте 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
говорит о "коротких именах " (аббревиатуры, такие как запрошенные)
Настоятельно рекомендуется использовать эти имена только для отображения. Эти имена не являются официальными, и многие из них просто выдуманы сопровождающими базы данных Олсона. Более того, эти имена не уникальны. Например, «EST» есть как при -0500, так и при +1000/+1100.
(первоначальный акцент)
Один из способов попытаться справиться с аббревиатурами, которые появляются у пользователя, - это 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
; не прост в использовании.
Ясно, что это не является систематическим или надежным, как и аббревиатуры, для начала.
Лучше всего было бы создать какой-то локальный поиск, который переводил бы ваше короткое имя в имя собственное, чтобы вы знали, что оно правильное в вашей работе. Затем заглушка, которая была добавлена в ОП (и позже изменена), может быть заполнена до
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
(См. примечания к документации по различным методам печати.)
Сцепленные методы, создающие возвращаемый объект, обеспечивают синтаксический анализ и изменение часового пояса, используя принятое имя часового пояса.
Для того, чтобы код работал с аббревиатурами, явно требуется преобразование (отображение) локально используемых аббревиатур, представляющих интерес, в правильные имена часовых поясов, предоставленные пользователем.
В приведенном выше фрагменте для этого есть подпрограмма-заполнитель, которая может, например, использовать хэш в модуле с прописанным прямо в нем сопоставлением или, что еще лучше, из файла JSON, которым, таким образом, может управлять и другое программное обеспечение; или запросив таблицу базы данных или, возможно, локальную службу или что-то в этом роде.
person
zdim
schedule
17.09.2019