Domanda

Al momento stiamo utilizzando un API di terze parti che fornisce datetime nel seguente formato:

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

Tuttavia, vogliamo memorizzare questi oggetti datetime in MySQL in un campo datetime standard che richiede il seguente formato:

YYYY-MM-DD HH:MM:SS

In questo momento stiamo utilizzando il seguente codice che segnala gli errori per alcuni fusi orari, come KDT, JDT e 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"); };

Mi può consigliare una migliore attuazione del codice Perl sopra per convertire gli oggetti datetime dalla API per il formato corretto e il tempo sul nostro server da inserire in un campo datetime MySQL?

Grazie in anticipo per il vostro aiuto e consigli!

È stato utile?

Soluzione

Conservare i tempi internamente GMT. Fare tutte le manipolazioni in GMT. Poi, all'ultimo momento, proprio mentre stai per visualizzare i risultati per l'utente, poi Converti ora locale dell'utente.

Mi consiglia di utilizzare Date :: Parse , ma si 'll deve aumentare i suoi offset di fuso orario, perché non ha attualmente Indocina Summer Time e Giappone dell'ora, per esempio.

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

Per supportare la query vuoi, memorizzare l'ora in GMT più un offset ( cioè. , dal GMT per l'ora locale dal API). Si noti che il codice che segue presuppone che se str2time può analizzare un dato momento, strptime può anche. Modificare il ciclo per

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

Con i tempi raccolti, renderla come 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"

L'uscita è

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;

e possiamo pipe a 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

Altri suggerimenti

Quando si conserva date, si dovrebbe sempre memorizzarli in UTC. In questo modo, è possibile recuperare dal database e convertirli al fuso orario appropriato come necessari per la visualizzazione per l'utente.

Per la gestione datetimes correttamente in Perl, vi consiglio vivamente il DateTime suite, che ha parser e formattatori per tutti i tipi di vari formati di input e di output.

Non sono sicuro se le date elencate nel vostro OP un formato standard, ma in caso contrario, sarebbe piuttosto facile da costruire un formato DateTime da loro:

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

È quindi possibile utilizzare DateTime :: Format :: MySQL per convertire la data a un datetime compatibile con MySQL.

Si avrà probabilmente bisogno di dire esplicitamente il costruttore DateTime che fuso orario (s) si sta trattando, perché i codici a tre e quattro lettere non sono univoche e non standardizzato.

vorrei suggerire a partire da DateTime :: TimeZone , e possibilmente costruzione di nuove tipi per la vostra fusi orari, se non riesci a trovare quello che stai cercando nella lista. È inoltre possibile trovare un formattatore DateTime conforme a tale sintassi (ci sono un numero enorme di loro), ma per il resto non è difficile usare semplicemente una regex per estrarre i campi di data e ora e passare che per un costruttore DateTime.

Una volta che hai le corde analizzato in DateTime oggetti con i tempi impostati correttamente, non è un problema a tutti per convertirli di nuovo fuori al timestamp di MySQL: basta usare DateTime :: Format :: MySQL :

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

Provare a utilizzare il DateTime modulo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top