使用 Perl 在日期时间格式之间进行转换

发布于 2024-08-21 01:32:41 字数 653 浏览 6 评论 0原文

我们当前正在使用提供以下格式的日期时间的第 3 方 API:

Sat Mar 06 09:00:00 ICST 2010
Fri Feb 19 19:30:00 JDT 2010
Fri Feb 19 19:30:00 PST 2010

但是,我们希望将这些日期时间对象存储在 MySQL 中的标准日期时间字段中,该字段需要以下格式:

YYYY-MM-DD HH:MM:SS

现在我们使用以下代码 :报告某些时区的错误,例如 KDT、JDT 和 ICST:

use Date::Manip;
use DateTime;
use DateTime::Format::DateManip;

my $date = ParseDate($time);
$date = DateTime::Format::DateManip->parse_datetime($date);
eval{ $time = $date->strftime("%Y-%m-%d %H:%M:%S"); };

您能否建议更好地实现上面的 Perl 代码,以将 API 中的日期时间对象转换为我们服务器上正确的格式和时间,以便插入到 MySQL 日期时间字段中?

预先感谢您的帮助&建议!

We're currently using a 3rd party API that provides datetime in the following format:

Sat Mar 06 09:00:00 ICST 2010
Fri Feb 19 19:30:00 JDT 2010
Fri Feb 19 19:30:00 PST 2010

However, we want to store these datetime objects in MySQL in a standard datetime field which requires the following format:

YYYY-MM-DD HH:MM:SS

Right now we're using the following code which is reporting errors for certain timezones such as KDT, JDT, and ICST:

use Date::Manip;
use DateTime;
use DateTime::Format::DateManip;

my $date = ParseDate($time);
$date = DateTime::Format::DateManip->parse_datetime($date);
eval{ $time = $date->strftime("%Y-%m-%d %H:%M:%S"); };

Can you recommend a better implementation of the Perl code above to convert the datetime objects from the API to the proper format and time on our server to be inserted into a MySQL datetime field?

Thanks in advance for your help & advice!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

北风几吹夏 2024-08-28 01:32:41

在内部存储 GMT 时间。在 GMT 中进行所有操作。然后在最后一刻,当您即将向用户显示结果时,然后转换为用户的当地时间。

我建议使用 Date::Parse,但你会例如,增加其时区偏移,因为它目前没有印度支那夏令时和日本夏令时。

#! /usr/bin/perl

use warnings;
use strict;

use Date::Format;
use Date::Parse;

# add timezone offsets
$Time::Zone::Zone{icst} = +7*3600;
$Time::Zone::Zone{jdt}  = +9*3600;

while (<DATA>) {
  chomp;
  warn("$0: failed conversion for $_\n"), next
    unless defined(my $time_t = str2time $_);

  my @t = gmtime($time_t);
  print $_, " => ", strftime("%Y-%m-%d %H:%M:%S", @t), "\n";
}

__DATA__
Sat Mar 06 09:00:00 ICST 2010
Fri Feb 19 19:30:00 JDT 2010
Fri Feb 19 19:30:00 PST 2010

输出:

Sat Mar 06 09:00:00 ICST 2010 => 2010-03-06 02:00:00
Fri Feb 19 19:30:00 JDT 2010 => 2010-02-19 10:30:00
Fri Feb 19 19:30:00 PST 2010 => 2010-02-20 03:30:00

为了支持您想要的查询,请存储 GMT 时间加上偏移量(,从 GMT 到 API 的本地时间)。请注意,下面的代码假设如果 str2time 可以解析给定时间,则 strptime 也可以。将循环更改为

my @dates;
while (<DATA>) {
  chomp;
  warn("$0: failed conversion for $_\n"), next
    unless defined(my $time_t = str2time $_);

  my $zone = (strptime $_)[-1];
  my @t = gmtime($time_t);
  push @dates => [ strftime("%Y-%m-%d %H:%M:%S", @t)
                 , sprintf("%+03d:%02d",
                           int($zone / 3600),
                           int($zone % 3600) / 60)
                 , $_
                 ];
}

随着收集的时间,将其呈现为 SQL:

print "DROP TABLE IF EXISTS dates;\n",
      "CREATE TABLE dates (date DATETIME, offset CHAR(6));\n",
      "INSERT INTO dates (date,offset) VALUES\n",
        join(",\n\n" =>
          map("  -- $_->[2]\n" .
              "  ('$_->[0]','$_->[1]')", @dates)),
        ";\n",
      "SELECT CONVERT_TZ(date,'+00:00',offset) FROM dates;\n"

输出为

DROP TABLE IF EXISTS dates;
CREATE TABLE dates (date DATETIME, offset CHAR(6));
INSERT INTO dates (date,offset) VALUES
  -- Sat Mar 06 09:00:00 ICST 2010
  ('2010-03-06 02:00:00','+07:00'),

  -- Fri Feb 19 19:30:00 JDT 2010
  ('2010-02-19 10:30:00','+09:00'),

  -- Fri Feb 19 19:30:00 PST 2010
  ('2010-02-20 03:30:00','-08:00');
SELECT CONVERT_TZ(date,'+00:00',offset) FROM dates;

,我们可以将其通过管道传输到 mysql

$ ./prog.pl | mysql -u username -D dbname
CONVERT_TZ(date,'+00:00',offset)
2010-03-06 09:00:00
2010-02-19 19:30:00
2010-02-19 19:30:00

Store the times internally in GMT. Do all manipulations in GMT. Then at the last moment, just as you're about to display results to the user, then convert to the user's local time.

I recommend using Date::Parse, but you'll have to augment its timezone offsets because it doesn't currently have Indochina Summer Time and Japan Daylight Time, for example.

#! /usr/bin/perl

use warnings;
use strict;

use Date::Format;
use Date::Parse;

# add timezone offsets
$Time::Zone::Zone{icst} = +7*3600;
$Time::Zone::Zone{jdt}  = +9*3600;

while (<DATA>) {
  chomp;
  warn("$0: failed conversion for $_\n"), next
    unless defined(my $time_t = str2time $_);

  my @t = gmtime($time_t);
  print $_, " => ", strftime("%Y-%m-%d %H:%M:%S", @t), "\n";
}

__DATA__
Sat Mar 06 09:00:00 ICST 2010
Fri Feb 19 19:30:00 JDT 2010
Fri Feb 19 19:30:00 PST 2010

Output:

Sat Mar 06 09:00:00 ICST 2010 => 2010-03-06 02:00:00
Fri Feb 19 19:30:00 JDT 2010 => 2010-02-19 10:30:00
Fri Feb 19 19:30:00 PST 2010 => 2010-02-20 03:30:00

To support the query you'd like, store the time in GMT plus an offset (i.e., from GMT to the local time from the API). Note that the code below assumes that if str2time can parse a given time, strptime can also. Change the loop to

my @dates;
while (<DATA>) {
  chomp;
  warn("$0: failed conversion for $_\n"), next
    unless defined(my $time_t = str2time $_);

  my $zone = (strptime $_)[-1];
  my @t = gmtime($time_t);
  push @dates => [ strftime("%Y-%m-%d %H:%M:%S", @t)
                 , sprintf("%+03d:%02d",
                           int($zone / 3600),
                           int($zone % 3600) / 60)
                 , $_
                 ];
}

With the times collected, render it as SQL:

print "DROP TABLE IF EXISTS dates;\n",
      "CREATE TABLE dates (date DATETIME, offset CHAR(6));\n",
      "INSERT INTO dates (date,offset) VALUES\n",
        join(",\n\n" =>
          map("  -- $_->[2]\n" .
              "  ('$_->[0]','$_->[1]')", @dates)),
        ";\n",
      "SELECT CONVERT_TZ(date,'+00:00',offset) FROM dates;\n"

The output is

DROP TABLE IF EXISTS dates;
CREATE TABLE dates (date DATETIME, offset CHAR(6));
INSERT INTO dates (date,offset) VALUES
  -- Sat Mar 06 09:00:00 ICST 2010
  ('2010-03-06 02:00:00','+07:00'),

  -- Fri Feb 19 19:30:00 JDT 2010
  ('2010-02-19 10:30:00','+09:00'),

  -- Fri Feb 19 19:30:00 PST 2010
  ('2010-02-20 03:30:00','-08:00');
SELECT CONVERT_TZ(date,'+00:00',offset) FROM dates;

and we can pipe it to mysql:

$ ./prog.pl | mysql -u username -D dbname
CONVERT_TZ(date,'+00:00',offset)
2010-03-06 09:00:00
2010-02-19 19:30:00
2010-02-19 19:30:00
落在眉间の轻吻 2024-08-28 01:32:41

存储日期时,应始终以 UTC 格式存储。这样,您可以从数据库中获取它们,并根据需要将它们转换为适当的时区,以便显示给用户。

为了在 Perl 中正确处理日期时间,我衷心推荐 DateTime 套件,它具有解析器和格式化程序各种不同的输入和输出格式。

我不确定你的OP中列出的日期是否是标准格式,但如果不是,那么从它们构建日期时间格式将非常容易:

my $str = 'Sat Mar 06 09:00:00 ICST 2010';
my ( $month, $day, $hour, $min, $sec, $tz, $year ) = ( $str =~ m{\w{3}\s(\w{3})\s(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s(\w+)\s(\d{4})} );

my $dt = DateTime->new( year => $year, month => $month, day => $day, 
                        hour => $hour, minute => $min, second => $sec, 
                        time_zone => $tz );

然后你可以使用 DateTime::Format::MySQL 将日期转换为与 MySQL 兼容的日期时间。

When storing dates, you should always store them in UTC. That way, you can fetch them from the database and convert them to the appropriate timezone as necessary for display to the user.

For handling datetimes properly in Perl, I heartily recommend the DateTime suite, which has parsers and formatters for all sorts of various input and output formats.

I'm not sure if the dates listed in your OP are a standard format, but if not, it would be pretty easy to construct a DateTime format from them:

my $str = 'Sat Mar 06 09:00:00 ICST 2010';
my ( $month, $day, $hour, $min, $sec, $tz, $year ) = ( $str =~ m{\w{3}\s(\w{3})\s(\d{2})\s(\d{2}):(\d{2}):(\d{2})\s(\w+)\s(\d{4})} );

my $dt = DateTime->new( year => $year, month => $month, day => $day, 
                        hour => $hour, minute => $min, second => $sec, 
                        time_zone => $tz );

You could then use DateTime::Format::MySQL to convert the date to a MySQL-compatible datetime.

ぇ气 2024-08-28 01:32:41

您可能必须明确告诉 DateTime 构造函数您正在处理哪个时区,因为三字母和四字母代码不是唯一的且不是标准化的。

我建议从 DateTime::TimeZone 开始,并可能为您构建新类型如果您在列表中找不到所需的时区。您还可能会找到符合您的语法的 DateTime 格式化程序(它们数量巨大),但除此之外,简单地使用正则表达式提取日期和时间字段并将其传递给 DateTime 构造函数并不困难。

一旦你将字符串解析为 DateTime 对象并正确设置了时间,将它们转换回 MySQL 时间戳就完全没有问题了:只需使用 日期时间::格式::MySQL:

my $string = DateTime::Format::MySQL->format_datetime($dt);

You will probably have to explicitly tell the DateTime constructor which timezone(s) you are dealing with, because the three- and four-letter codes are not unique and not standardized.

I would suggest starting with DateTime::TimeZone, and possibly constructing new types for your timezones if you cannot find what you are looking for in the list. You may also find a DateTime formatter that conforms to your syntax (there are a huge number of them), but otherwise it's not difficult to simply use a regex to extract the date and time fields and pass that to a DateTime constructor.

Once you've got your strings parsed into DateTime objects with the times properly set, it's no problem at all to convert them back out to MySQL timestamps: just use DateTime::Format::MySQL:

my $string = DateTime::Format::MySQL->format_datetime($dt);
怎会甘心 2024-08-28 01:32:41

尝试使用 DateTime 模块。

Try using the DateTime module.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文