سؤال

نحن نستخدم حاليًا واجهة برمجة تطبيقات الطرف الثالث التي توفر DateTime بالتنسيق التالي:

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

ومع ذلك ، نريد تخزين كائنات DateTime هذه في MySQL في حقل DateTime القياسي الذي يتطلب التنسيق التالي:

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 أعلاه لتحويل كائنات DateTime من واجهة برمجة التطبيقات إلى التنسيق المناسب والوقت على خادمنا ليتم إدراجهم في حقل DateTime MySQL؟

شكرا مقدما لمساعدتكم ونصائحك!

هل كانت مفيدة؟

المحلول

تخزين الأوقات الداخلية في GMT. هل كل التلاعب في GMT. ثم في اللحظة الأخيرة ، تمامًا كما كنت على وشك عرض النتائج للمستخدم ، ومن بعد تحويل إلى الوقت المحلي للمستخدم.

أوصي باستخدام التاريخ :: تحليل, ، ولكن سيتعين عليك زيادة تعويضاتها الزمنية لأنها لا تتمتع حاليًا بالوقت الصيفي للهندتشينا ووقت النهار في اليابان ، على سبيل المثال.

#! /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

نصائح أخرى

عند تخزين التواريخ ، يجب عليك دائمًا تخزينها في UTC. وبهذه الطريقة ، يمكنك جلبها من قاعدة البيانات وتحويلها إلى المنطقة الزمنية المناسبة حسب الضرورة للعرض للمستخدم.

للتعامل مع DateTimes بشكل صحيح في 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 لتحويل التاريخ إلى DateTime متوافق مع MySQL.

من المحتمل أن تضطر إلى إخبار مُنشئ وقت البيانات صراحةً بالمنطقة الزمنية التي تتعامل معها ، لأن الرموز الثلاثة والأربعة أحرف ليست فريدة من نوعها وليست موحدة.

أود أن أقترح البدء مع DateTime :: timezone, ، وربما بناء أنواع جديدة لمناطقك الزمنية إذا لم تتمكن من العثور على ما تبحث عنه في القائمة. يمكنك أيضًا العثور على تنسيق في وقت البيانات يتوافق مع بناء الجملة الخاص بك (هناك عدد كبير منها) ، ولكن على خلاف ذلك ، ليس من الصعب ببساطة استخدام regex لاستخراج حقول التاريخ والوقت وتمرير ذلك إلى مُنشئ وقت البيانات.

بمجرد أن تحصل على سلاسلك في كائنات DateTime مع تعيين الأوقات بشكل صحيح ، لا توجد مشكلة على الإطلاق في تحويلها إلى MySQL Timestamps: فقط استخدم DateTime :: Format :: Mysql:

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

حاول استخدام DateTime وحدة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top