Pregunta

Actualmente estamos utilizando una API que proporciona tercera parte de fecha y hora en el siguiente 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

Sin embargo, queremos almacenar estos objetos de fecha y hora en MySQL en un campo de fecha y hora estándar que requiere el siguiente formato:

YYYY-MM-DD HH:MM:SS

En este momento estamos usando el siguiente código que está reportando errores para ciertas zonas horarias como KDT, JDT y 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"); };

Me puede recomendar una mejor aplicación del código Perl anterior para convertir los objetos de fecha y hora de la API para el formato y el momento adecuado en nuestro servidor para ser insertado en un campo de fecha y hora de MySQL?

Gracias de antemano por su ayuda y consejos!

¿Fue útil?

Solución

Guarde los tiempos internamente en GMT. Hacer todas las manipulaciones en GMT. A continuación, en el último momento, justo cuando estás a punto de mostrar resultados al usuario, después convertir en la hora local del usuario.

Fecha :: Parse , pero Tendrá que aumentar sus compensaciones de zona horaria, ya que no tiene actualmente Indochina horario de verano y Japón Hora de verano, por ejemplo.

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

Salida:

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

Para apoyar la consulta desea, almacenar la hora en GMT más un desplazamiento ( es decir. , con respecto a GMT a la hora local de la API). Tenga en cuenta que el código siguiente se supone que si str2time puede analizar un momento dado, también puede strptime. Cambiar el bucle a

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 los tiempos que recogen, hacerla como 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"

La salida es

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;

y podemos tubería 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

Otros consejos

Al almacenar fechas, siempre hay que guardarlos en UTC. De esta manera, se puede recuperar a partir de la base de datos y los convierte a la zona horaria apropiada necesaria para ser presentado al usuario.

Para el manejo de datetimes adecuadamente en Perl, recomiendo vivamente el DateTime suite, que tiene programas de análisis y formateadores para todas las clases de diversos formatos de entrada y salida.

No estoy seguro de si las fechas que figuran en su OP son un formato estándar, pero si no, sería muy fácil de construir un formato de DateTime de ellos:

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

A continuación, puede utilizar DateTime :: format :: MySQL para convertir la fecha a una fecha y hora compatible con MySQL.

Usted probablemente tiene que indicar explícitamente al constructor, que DateTime zona horaria (s) que ocupa, ya que los códigos de tres y cuatro letras no son únicas y no estandarizada.

Yo sugeriría comenzando con DateTime :: Zona horaria , y posiblemente la construcción de nuevas tipos para sus zonas horarias si no pueden encontrar lo que busca en la lista. Usted también puede encontrar un formateador DateTime que se ajusta a la sintaxis (hay un gran número de ellos), pero por lo demás no es difícil de usar simplemente una expresión regular para extraer los campos de fecha y hora y pasar eso a un constructor de DateTime.

Una vez que tenga sus cadenas analizado en DateTime objetos con los tiempos establecidos adecuadamente, no hay ningún problema en absoluto para convertir de nuevo a las marcas de tiempo de MySQL: sólo tiene que utilizar DateTime :: format :: MySQL :

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

Trate de usar la DateTime módulo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top