2010-02-12 24 views
5

Actualmente estamos utilizando una API que proporciona tercera parte de fecha y hora en el siguiente formato:convertir entre formatos de fecha y hora Utilizando Perl

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

¿Puede recomendar una mejor implementación del código Perl anterior para convertir los objetos de fecha y hora de la API al formato y hora adecuados en nuestro servidor para insertarlos en un campo de fecha y hora de MySQL?

Gracias de antemano por su ayuda & consejos!

+3

Un buen lugar para comenzar: http: //datetime.perl .org /? Modules –

Respuesta

6

tienda los tiempos internos en GMT. Haz todas las manipulaciones en GMT. Luego, en el último momento, justo cuando está a punto de mostrar los resultados al usuario, , luego, convertir a la hora local del usuario.

Recomiendo usar Date::Parse, pero tendrá que aumentar sus compensaciones de zona horaria porque actualmente no tiene el horario de verano de Indochina ni el horario de verano de Japón, 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 una desviación (es decir, , con respecto a GMT a la hora local de la API). Tenga en cuenta que el código siguiente supone que si str2time puede analizar un tiempo determinado, también puede hacerlo strptime. Cambiar el bucle para

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 recogidos, 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 que puede canalizarla 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
+0

@gbacon - Esto es exactamente lo que estaba buscando. Una última pregunta. Tengo que mostrar la hora del artículo en la misma zona horaria que originalmente fue dada por la API. ¿Qué formato recomendaría? Guardo la zona horaria en mi tabla MySQL para facilitar la conversión y también el código Perl que usaría para convertir la fecha y hora almacenada en GMT y zona horaria en un formato como "Viernes, 19 de febrero de 2010". - 2:30 p.m. JDT "? –

+0

@gbacon - Si hay una manera de almacenar la zona horaria en MySQL de una forma que me permita hacer una consulta que devuelva la fecha y hora almacenada (en GMT) en el tiempo de fecha local con solo una consulta SQL (no perl) que probablemente sea una solución aún mejor. –

+0

@Russell ¿De quién hora local? ¿Lo mismo que el tiempo otorgado por la API o la máquina que aloja la base de datos? –

0

Intente utilizar el módulo DateTime.

+0

@vivin - ¿Puede proporcionar un poco más de detalle? Acabo de agregar el código que hemos estado usando a la pregunta original. ¿Alguna idea de por qué DateTime no parece ser capaz de convertir ciertas zonas horarias? –

+0

Almacenaría los datos en tiempo UTC. Aunque no estoy seguro de entender su pregunta, ¿desea saber cómo manejar la inserción de fechas en una base de datos MySQL? –

+0

Acabo de actualizar la pregunta para que quede más clara. Mi pregunta es, básicamente, ¿puede proporcionar una mejor implementación de Perl para convertir el datetime proporcionado por la API al formato de fecha y hora correcto para insertarlo en un campo de fecha y hora de MySQL? –

3

Al almacenar fechas, siempre debe almacenarlas en UTC. De esta forma, puede obtenerlos de la base de datos y convertirlos a la zona horaria adecuada según sea necesario para mostrar al usuario.

Para gestionar las fechas correctamente en Perl, recomiendo encarecidamente la suite DateTime, que tiene analizadores y formateadores para todo tipo de 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); 

entonces se podría utilizar DateTime::Format::MySQL para convertir la fecha a una fecha de tiempo compatible con MySQL.

+0

Actualmente estamos usando DateTime, pero por alguna razón no parece ser capaz de manejar ciertas zonas horarias y está reportando errores para KDT, JDT, ICST, etc. No sabía si había un módulo con un poco de apoyo más amplio? –

+0

Acabo de agregar el código en el que estamos usando la pregunta original. ¿Alguna idea de por qué DateTime no parece ser capaz de manejar ciertas zonas horarias? –

+1

Desafortunadamente no sé cómo hacerlo para admitir dichas zonas horarias; no aparecen en la lista de módulos de DateTime :: TimeZone (http://search.cpan.org/~drolsky/DateTime-TimeZone-1.10/). Es posible que necesite convertirlos a un nombre de estilo Olson, como KDT => 'Asia/Seúl' – friedo

1

Probablemente tendrá que decirle explícitamente al constructor de DateTime con qué zona (s) horaria (s) está tratando, porque los códigos de tres y cuatro letras no son únicos y no están estandarizados.

Sugiero comenzar por DateTime::TimeZone, y posiblemente construir nuevos tipos para sus zonas horarias si no puede encontrar lo que está buscando en la lista. También puede encontrar un formateador DateTime que se ajuste a su sintaxis (hay un gran número de ellos), pero de lo contrario no es difícil simplemente usar una expresión regular para extraer los campos de fecha y hora y pasarlos a un constructor DateTime.

Una vez que tenga sus cadenas analizan en objetos DateTime con los tiempos ajustados correctamente, 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); 
+0

@Ether - ¡Gracias! Dado que el consenso parece ser que necesito almacenar estas fechas en formato UTC, ¿puede proporcionar algún ejemplo de código perl sobre cómo lo haría una vez que tenga el objeto DateTime adecuado? –

+0

No tiene que almacenarlos en UTC, aunque verá una mejora en el rendimiento si está haciendo algunos cálculos con los horarios. Sin embargo, lo que debe hacer es pasar la cadena de zona horaria correcta al constructor DateTime, p. '$ my $ dt = DateTime-> new (..., timezone => 'America/Los_Angeles');' – Ether

Cuestiones relacionadas