Perl:从考虑夏令时的纪元开始以秒为单位输入时间时,获取 gmtime 和本地时间之间的偏移量

Posted

技术标签:

【中文标题】Perl:从考虑夏令时的纪元开始以秒为单位输入时间时,获取 gmtime 和本地时间之间的偏移量【英文标题】:Perl : Get offset between gmtime and localtime when input time in seconds since epoch which considers daylight savings time 【发布时间】:2019-10-17 04:43:14 【问题描述】:

我想获得自纪元以来给定微秒的本地时间和 gmtime 之间的小时偏移量。我到目前为止是这样的

# Microseconds since Epoch 
my $msec = 555329743301750;

# Convert to seconds 
my $sec = $msec/1000000;

my $val = (POSIX::mktime(localtime $sec) - POSIX::mktime(gmtime $sec)) / 60 / 60;

print "$val\n";

1) 我得到的输出是-6。(CST 本地时间)但是我期待-5。我期望的行为类似于运行 bash 命令的结果

`date -d 20190514 "+%z"`; 

2) 长话短说,我如何计算类似于 perl 中的date -d 20190514 "+%z" 的偏移量?

【问题讨论】:

What's the best way to get the UTC offset in Perl?的可能重复 最坏的情况,你也可以减去isdst的值。 my @tmp = localtime($sec); $val = $val - $tmp[8]; 【参考方案1】:

使用核心Time::Piece:

use strict;
use warnings;
use Time::Piece;

# Microseconds since Epoch 
my $usec = 555329743301750;

# Convert to seconds 
my $sec = $usec/1000000;

my $offset = localtime($sec)->tzoffset / 3600;

Time::Moment 和 DateTime 也可以返回这个值,如果你按照我在your other question 上展示的那样构造它们。

my $offset = $time_moment->offset / 60;

my $offset = $datetime->offset / 3600;

您也可以根据日期创建这些对象,但它当然会在当天的午夜(当地时间)为您提供偏移量。

use Time::Piece;
my $time = localtime->strptime('20190514', '%Y%m%d');

use Time::Moment;
use Role::Tiny ();
my $class = Role::Tiny->create_class_with_roles('Time::Moment', 'Time::Moment::Role::TimeZone');
my $time = $class->new(year => 2019, month => 5, day => 14)->with_system_offset_same_local;

use DateTime;
my $time = DateTime->new(year => 2019, month => 5, day => 14, time_zone => 'local');

【讨论】:

谢谢。我有几个后续问题。 1)如果我知道日期,那么最好的方法是什么? 2)您能否指出我的实施问题。我不太明白它不考虑夏令时的原因。 添加了从日期构造每个对象的示例。我不确定您的实现有什么问题,但也许您需要类似于with_system_offset_same_instant 确定要设置的偏移量的方法。 use Time::Piece; my $time = localtime->strptime('20190514', '%Y%m%d'); my $offset = localtime($sec)->tzoffset / 3600; 我原来的实现遇到了同样的问题。不要得到夏令时的差异。我不能使用 Time::Moment 或 DateTime,因为它们没有安装并且可能没有。 @EternalLearner 您创建了两个不同的 Time::Piece 对象。确保你在你想要的那个上调用 tzoffset。【参考方案2】:

这将为您提供与 Linux "%z" 格式相同的 [+-]HHMM 格式:

use POSIX qw[mktime];

my $tz = (localtime time)[8] * 60 - mktime(gmtime 0) / 60;
$tz = sprintf "%+03d%02d\n", $tz / 60, abs($tz) % 60;

如果您只想要以小时为单位的偏移量,您可以这样做:

my $tz_offset_hours = (localtime time)[8] - mktime(gmtime 0)) / 3600;

奖励:以下子例程将返回带有时区偏移和微秒的完整时间戳,如“YYYY-MM-DD HH:MM:SS.nnnnnn [+-]HHMM”:

use POSIX qw[mktime strftime];
use Time::HiRes qw[gettimeofday];

sub timestamp () 
  my @now = gettimeofday;
  my $tz  = (localtime $now[0])[8] * 60 - mktime(gmtime 0) / 60;
  my $ts  = strftime("%Y-%m-%d %H:%M:%S", localtime $now[0]);
  return sprintf "%s.%06d %+03d%02d", $ts, $now[1], $tz / 60, abs($tz) % 60;

【讨论】:

以上是关于Perl:从考虑夏令时的纪元开始以秒为单位输入时间时,获取 gmtime 和本地时间之间的偏移量的主要内容,如果未能解决你的问题,请参考以下文章

如何从给定城市的给定日期和时间获取 unix 纪元时间戳(以秒为单位)?

Javascript 日增量(以秒为单位)在下午 5:00 翻转

如何使用 Perl 找到今天(本地时区)的最小纪元时间?

从键盘输入一个以秒为单位的时间值(如10000秒),将其转化为以时、分、秒表示的时间

计算 SQL 中组的重叠时间(以秒为单位)

如何从 postgres 获取时间戳作为 Unix 纪元?