将UTC转换为特定位置的时间在Perl中。

huangapple go评论73阅读模式
英文:

Convert UTC to Location specific time in Perl

问题

我已经编写了一个脚本,它以UTC时间作为输入,并应该打印特定位置(站点ID)的时间。站点ID目前已硬编码,根据站点而变化。

以下是我的脚本:

#!/usr/bin/env perl5.34.0

use strict; use warnings;
use Date::Parse;
use DateTime;
use Time::Piece qw( localtime );
use POSIX 'strftime';
use Date::Format qw(!strftime);

my $site_id = 1;

my %time_zone_hash = (
                1 => 'Europe/London', #伦敦 (GMT+0)
                2 => 'Asia/Kolkata', #班加罗尔 (GMT+05:30)
        );

my $utc_now = strftime('%Y-%m-%d %H:%M:%S', gmtime());
print "UTC:$utc_now\n";

my $site_time = convertSiteTime($site_id, $utc_now);
print "site_time=$site_time\n";
print time2str('%Y-%m-%d %H:%M:%S', $site_time)."\n";

sub convertSiteTime {
        my $id = shift;
        my $time_str = shift;
        my $epoch_time = str2time($time_str);

        if (!$epoch_time) {
                print "$time_str is not a valid date. Please provide a valid date.\n";
                exit(1);
        }
        my $dt = DateTime->from_epoch(epoch => $epoch_time);
        $dt->set_time_zone($time_zone_hash{$id});

        return $dt->epoch();
}

输出:

UTC:2023-07-20 09:19:16
site_time=1689824956
2023-07-20 09:19:16

它为UTC和站点时间提供相同的结果。在这种情况下,站点时间应该是 2023-07-20 10:19:16

请问有人能告诉我脚本有什么问题。另外,我的系统(环境)设置为UTC时间。

英文:

I have written a script, which takes UTC time as an input and should print location specific (site id) time. The site id is been hard-coded as of now, which will vary according to the site.

Below is my script:

#!/usr/bin/env perl5.34.0

use strict; use warnings;
use Date::Parse;
use DateTime;
use Time::Piece qw( localtime );
use POSIX 'strftime';
use Date::Format qw(!strftime);

my $site_id = 1;

my %time_zone_hash = (
                1 => 'Europe/London', #london (GMT+0)
                2 => 'Asia/Kolkata', #bang (GMT+05:30)
        );

my $utc_now = strftime('%Y-%m-%d %H:%M:%S', gmtime());
print "UTC:$utc_now\n";

my $site_time = convertSiteTime($site_id, $utc_now);
print "site_time=$site_time\n";
print time2str('%Y-%m-%d %H:%M:%S', $site_time)."\n";

sub convertSiteTime {
        my $id = shift;
        my $time_str = shift;
        my $epoch_time = str2time($time_str);

        if (!$epoch_time) {
                print "$time_str is not a valid date. Please provide a valid date.\n";
                exit(1);
        }
        my $dt = DateTime->from_epoch(epoch => $epoch_time);
        $dt->set_time_zone($time_zone_hash{$id});

        return $dt->epoch();
}

Output:

UTC:2023-07-20 09:19:16
site_time=1689824956
2023-07-20 09:19:16

It gives same result for UTC and site time. The site time suppose to be 2023-07-20 10:19:16 in this scenario.

Could someone please let me know whats wrong in the script.
Also my system (environment) is set to UTC time.

答案1

得分: 1

你正在询问如何将日期字符串从UTC转换为另一个时区(Asia/Kolkata)。

您的流程如下:

字符串 -> 时间戳 -> 日期时间对象 -> 更改时区 -> 时间戳 -> 字符串

将日期时间从一个时区转换为另一个时区对时间戳没有影响。无论您在地球上的哪个地方,自1970-01-01T00:00:00Z以来的时间都是相同的。[1]

这意味着

my $dt = DateTime->from_epoch(epoch => $epoch_time);
$dt->set_time_zone($time_zone_hash{$id});
return $dt->epoch;

return $epoch_time;

是相同的。由于中间部分是无用的,因此您的流程实际上是以下内容:

字符串 -> 时间戳 -> 字符串

这实际上是正确的。还有正确的:

字符串 -> 对象 -> 字符串

问题在于您正在不正确地执行这些转换。

我将首先重复我之前在您早期问题的回答中提供的DateTime和Time::Piece解决方案,然后提供一个Date::Parse + Date::Format解决方案。

使用DateTime将日期字符串从UTC转换为另一个时区

use DateTime::Format::Strptime qw( );

my $format = DateTime::Format::Strptime->new(
   pattern   => "%F %T",
   strict    => 1,
   time_zone => "UTC",
   on_error  => "croak",
);

my $dt = $format->parse_datetime( "2023-07-20 09:19:16" );
$dt->set_time_zone( "Asia/Kolkata" );
say $dt->strftime( "%F %T %z" );
2023-07-20 14:49:16 +0530
  • 不依赖于%ENV
  • 不依赖于系统定义的时区。
  • 不包含在perl中。
  • 相对较慢。
  • 具有良好的接口。

使用Time::Piece将日期字符串从UTC转换为另一个时区

use Time::Piece qw( localtime );

my $dt;

{
   local $ENV{ TZ } = "UTC";
   $dt = localtime->strptime( "2023-07-20 09:19:16", "%F %T" );
}

{
   local $ENV{ TZ } = "Asia/Kolkata";
   say $dt->strftime( "%F %T %z" );
}
2023-07-20 14:49:16 +0530
  • 即使对%ENV进行临时更改可能在多线程应用中也会有问题。
  • 依赖于系统定义的时区,因此可能不太可移植。
  • 包含在Perl中。
  • 快速。
  • Time::Piece可能很难正确使用。

使用Date::Parse + Date::Format将日期字符串从UTC转换为另一个时区

我刚刚发现这些模块处理时区的方式非常糟糕。

由于我们知道输入的偏移量,我们可以使用Date::Parse的str2time。但我们不能使用Date::Format的time2str来获得所需的输出。

除相对论效应外。

英文:

You are asking how to convert a date-string from UTC to another time zone (Asia/Kolkata).


Your flow:

string -> epoch -> DT object -> change time zone -> epoch -> string

Converting a date-time from one time zone to another has no effect on epoch. It doesn't matter where you are on Earth, the same amount of time has passed since 1970-01-01T00:00:00Z.<sup>[1]</sup>

That means that

my $dt = DateTime-&gt;from_epoch(epoch =&gt; $epoch_time);
$dt-&gt;set_time_zone($time_zone_hash{$id});
return $dt-&gt;epoch;

is the same as

return $epoch_time;

Since that whole middle bit is useless, your flow is effectively the following:

string -> epoch -> string

This is actually correct. Also correct:

string -> object -> string

The problem is that you are doing those conversions incorrectly.

I'll start with repeating the DateTime and Time::Piece solutions I already provided in my answer to your earlier question, then I'll provide a Date::Parse + Date::Format solution.


Converting a date-string from UTC to another time zone using DateTime

use DateTime::Format::Strptime qw( );

my $format = DateTime::Format::Strptime-&gt;new(
   pattern   =&gt; &quot;%F %T&quot;,
   strict    =&gt; 1,
   time_zone =&gt; &quot;UTC&quot;,
   on_error  =&gt; &quot;croak&quot;,
);

my $dt = $format-&gt;parse_datetime( &quot;2023-07-20 09:19:16&quot; );
$dt-&gt;set_time_zone( &quot;Asia/Kolkata&quot; );
say $dt-&gt;strftime( &quot;%F %T %z&quot; );
2023-07-20 14:49:16 +0530
  • Doesn't rely on %ENV.
  • Doesn't rely on the system for its definitions of time zones.
  • Not included with perl.
  • Relatively slow.
  • Decent interface.

Converting a date-string from UTC to another time zone using Time::Piece

use Time::Piece qw( localtime );

my $dt;

{
   local $ENV{ TZ } = &quot;UTC&quot;;
   $dt = localtime-&gt;strptime( &quot;2023-07-20 09:19:16&quot;, &quot;%F %T&quot; );
}

{
   local $ENV{ TZ } = &quot;Asia/Kolkata&quot;;
   say $dt-&gt;strftime( &quot;%F %T %z&quot; );
}
2023-07-20 14:49:16 +0530
  • Even temporary changes to %ENV might be problematic in a threaded application.
  • Relies on the system for its definitions of time zones, so it might be less portable.
  • Included with Perl.
  • Fast.
  • Time::Piece can be very tricky to use correctly.

Converting a date-string from UTC to another time zone using Date::Parse + Date::Format

I've just discovered the handling of time zones by those modules is complete garbage.

Since we know the offset of the input, we can Date::Parse's str2time. But we can't use Date::Format's time2str to get the desired output.


  1. Aside from relativistic effects.

huangapple
  • 本文由 发表于 2023年7月20日 17:25:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/76728459.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定