Frage

Wir verwenden derzeit eine API von Drittanbietern, die im folgenden Format DateTime anbietet:

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

Wir möchten diese DateTime -Objekte jedoch in MySQL in einem Standard -DateTime -Feld speichern, das das folgende Format erfordert:

YYYY-MM-DD HH:MM:SS

Derzeit verwenden wir den folgenden Code, der Fehler für bestimmte Zeitzonen wie KDT, JDT und ICST meldet:

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"); };

Können Sie eine bessere Implementierung des obigen Perl -Codes empfehlen, um die DateTime -Objekte von der API in das richtige Format und die Zeit auf unserem Server in ein mySQL DateTime -Feld zu konvertieren?

Vielen Dank im Voraus für Ihre Hilfe und Ihren Rat!

War es hilfreich?

Lösung

Lagern Sie die Times intern in GMT. Machen Sie alle Manipulationen in GMT. Dann im letzten Moment, so wie Sie dem Benutzer Ergebnisse anzeigen möchten, dann Konvertieren Sie in die lokale Zeit des Benutzers.

Ich empfehle die Verwendung Datum :: analysieren, Aber Sie müssen seine Zeitzone -Offsets erhöhen, da es zum Beispiel keine Indochina -Sommerzeit und die Tageslichtzeit für die Tageslicht hat.

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

Ausgabe:

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

Lagern Sie die Zeit in GMT plus einem Offset (um die Abfrage zu unterstützen, die Sie möchten (dh, von GMT bis zur lokalen Zeit von der API). Beachten Sie, dass der folgende Code davon ausgeht, dass wenn str2time kann eine bestimmte Zeit analysieren, strptime kann auch. Ändern Sie die Schleife in

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)
                 , $_
                 ];
}

Rendern Sie es mit den Zeiten als 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"

Die Ausgabe ist

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;

und wir können es an übergeben 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

Andere Tipps

Wenn Sie Daten speichern, sollten Sie sie immer in UTC aufbewahren. Auf diese Weise können Sie sie aus der Datenbank abrufen und sie bei Bedarf in die entsprechende Zeitzone konvertieren, die für die Anzeige für den Benutzer erforderlich sind.

Für die ordnungsgemäße Umstellung von Angaben in Perl empfehle ich das von Herzen Terminzeit Suite, die Parser und Formatierungen für alle möglichen Eingangs- und Ausgangsformate hat.

Ich bin mir nicht sicher, ob die in Ihrem OP aufgeführten Daten ein Standardformat sind, aber wenn nicht, wäre es ziemlich einfach, ein DateTime -Format aus ihnen zu konstruieren:

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 );

Sie könnten dann verwenden DateTime :: Format :: Mysql Um das Datum in eine mySQL-kompatible DateTime umzuwandeln.

Sie müssen den DateTime-Konstruktor wahrscheinlich explizit mitteilen, mit welcher Zeitzone Sie es zu tun haben, da die Drei- und Vier-Buchstaben-Codes nicht eindeutig und nicht standardisiert sind.

Ich würde vorschlagen, mit Beginn mit DateTime :: TimeZone, und möglicherweise neue Typen für Ihre Zeitzonen, wenn Sie nicht finden können, wonach Sie in der Liste suchen. Möglicherweise finden Sie auch eine DateTime -Formaterin, die Ihrer Syntax entspricht (es gibt eine große Anzahl von ihnen), aber ansonsten ist es nicht schwierig, einfach einen Regex zu verwenden, um die Datums- und Uhrzeitfelder zu extrahieren und diese an einen DateTime -Konstruktor zu übergeben.

Sobald Sie Ihre Fäden in DateTime -Objekte mit ordnungsgemäßen Zeiten analysiert haben, ist es überhaupt kein Problem, sie wieder in MySQL -Zeitstempel zu konvertieren DateTime :: Format :: Mysql:

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

Versuchen Sie es mit dem Terminzeit Modul.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top