【问题标题】:Take Longitude/Latitude and get UTC Offset in Perl取经度/纬度并在 Perl 中获取 UTC 偏移量
【发布时间】:2021-07-23 06:09:01
【问题描述】:

当我对目的地时间的唯一了解是经度和纬度时,我正在尝试本地化 UTC 时间。我想出了一些可行的方法,但感觉很笨拙:

# We need to get localized time for display purposes.
state $moduleGeoLocation = require Geo::Location::TimeZone;
my $gltzobj = Geo::Location::TimeZone->new();
my $tzName = $gltzobj->lookup( lon => $params->{'longitude'}, lat => $params->{'latitude'} );
say "TimeZone: " . $tzName;

到目前为止一切顺利。这就是杂乱无章的地方。我正在使用 Time::Piece 的 strptime 解析时间,但我没有时区的 GMT 偏移量,所以在我解析了 Time::Piece 中的 UTC 时间后,我将其发送到 DateTime 以进行时区计算。同时使用 DateTime 和 Time::Piece 似乎相当笨拙:

# Get TimeZoneOffset.
state $moduleDateTime = require DateTime;
state $moduleDateTimeTimeZone = require DateTime::TimeZone;
my $timeZone = DateTime::TimeZone->new( 'name' => $tzName );

my $timePiece = Time::Piece->strptime($hour->{'time'}, '%Y-%m-%dT%H:%M:%SZ');
my $time = DateTime->from_epoch( 'epoch' => $timePiece->epoch, 'time_zone' => $timeZone );

有没有更好的方法来完成我正在做的事情?我的目标是尽可能以最快的方式获得本地化时间的结果。

【问题讨论】:

  • DateTime::Format::Strptime,所以不需要Time::Piece。是这样吗?
  • 另外,由于 Geo::Location::TimeZone 返回 Etc/GMT+X 形式的时区,这意味着不会遵守夏令时。
  • @ikegami 有没有你推荐的另一个模块,而不是你说的那样?这对您的时区来说非常糟糕。虽然,我从 G::L::TZ 中获得命名区域,而不是 GMT+X。例如。它给了我(CST/CDT)的“美国/芝加哥”,它应该适用于夏令时......
  • 准确查找 lon、lat 的时区并不简单。除了这里使用的库之外,SO answer 中还有一个漂亮的工具列表(不是 Perl,但很多是 Web 服务)。我试过google API,它使用起来非常简单,而且我认为它是准确的。但它需要一个人获得API key ...
  • @simbabque 完美。谢谢。我跟着你的引导,它似乎真的工作得更好。 GeoNames 几乎可以取代我对 OpenStreetMap 的查询,除了找出时区之外,尽管 OSM 在将文本字符串转换为可能的最合乎逻辑的位置方面似乎更准确一些,所以我仍在查询 OSM,然后通过 long/纬度到 GeoNames API。谢谢指点!

标签: perl datetime geolocation timezone


【解决方案1】:

您的问题归结为以下几点:

如何使用 %Y-%m-%dT%H:%M:%S 格式从时间戳创建 DateTime 对象。我有适当的时区作为 DateTime::TimeZone 对象。

要将日期时间解析为 DateTime,应首先查找合适的 DateTime::Format:: 模块。

DateTime::Format::Strptime 将与您当前的尝试最相似。

use DateTime::Format::Strptime qw( );
 
my $format = DateTime::Format::Strptime->new(
   pattern   => '%Y-%m-%dT%H:%M:%S',
   strict    => 1,
   time_zone => $tz,
   on_error  => 'croak',
);

my $dt = $format->parse_datetime($ts);

您也可以使用DateTime::Format::ISO8601,尽管您不能将其用作验证器,因为它不只接受规定的格式。

use DateTime::Format::ISO8601 qw( );
 
( my $dt = DateTime::Format::ISO8601->parse_datetime($ts) )
   ->set_time_zone('floating')
   ->set_time_zone($tz);

鉴于后一种解决方案会覆盖任何明确提供的时区,为了清楚起见,我将使用第一种解决方案。

【讨论】:

  • 谢谢!这很好用。我应该从 DateTime 开始——我决定尝试使用 Time::Piece,但没有意识到在时区方面我会被卡住。
  • TZ 转换可以使用 T::P 完成。但我认为 T::P 是一个相当糟糕的模块。
  • 正如@ikegami 所说,Time::Piece 中的转换是可能的,但它非常非常脆弱。你必须让星星排列得恰到好处。我只是为一个使用核心 Perl 的特定项目做了这个,这并不好玩。
  • @brian d foy,我对此感到惊讶。好吧,如果它是 Linux 系统,我会感到惊讶。这意味着时区对于所有使用 C 库的程序来说都是脆弱的,基本上就是所有这些程序。
  • 很高兴知道。我以为我错过了一些不尝试 T::P 的东西,但听起来不像。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-25
  • 2016-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多