Pergunta

Atualmente, estamos usando uma API de terceiros que fornece DateTime no seguinte 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

No entanto, queremos armazenar esses objetos DateTime em MySQL em um campo padrão de DateTime, que requer o seguinte formato:

YYYY-MM-DD HH:MM:SS

No momento, estamos usando o seguinte código que está relatando erros para determinados fusos horários, como 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"); };

Você pode recomendar uma melhor implementação do código PERL acima para converter os objetos DateTime da API para o formato e o tempo adequados em nosso servidor, a serem inseridos em um campo MySQL DateTime?

Agradecemos antecipadamente por sua ajuda e conselhos!

Foi útil?

Solução

Armazene os tempos internamente no GMT. Faça todas as manipulações no GMT. Então, no último momento, assim como você está prestes a exibir resultados para o usuário, então converter para a hora local do usuário.

Eu recomendo usar Data :: parse, mas você terá que aumentar suas compensações horárias, porque atualmente não possui o horário de verão da Indochina e o Japão, por exemplo.

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

Resultado:

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 apoiar a consulta que você gostaria, armazene o tempo no GMT mais um deslocamento (ou seja, do GMT ao horário local da API). Observe que o código abaixo assume que se str2time pode analisar um determinado tempo, strptime também pode. Mudar o loop 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)
                 , $_
                 ];
}

Com os tempos coletados, renderizá -lo 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"

A saída é

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 podemos pintar para 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

Outras dicas

Ao armazenar datas, você deve sempre armazená -las no UTC. Dessa forma, você pode buscá -los no banco de dados e convertê -los no fuso horário apropriado, conforme necessário para a exibição para o usuário.

Para lidar com as vezes corretamente em Perl, eu recomendo sinceramente o Data hora Suite, que possui analisadores e formatados para todos os tipos de vários formatos de entrada e saída.

Não tenho certeza se as datas listadas em seu OP são um formato padrão, mas se não, seria muito fácil construir um formato DateTime a partir delas:

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

Você poderia então usar DateTime :: format :: mysql Para converter a data em um datetime compatível com MySQL.

Você provavelmente terá que informar explicitamente ao construtor DateTime com que fuso horário (s) está lidando, porque os códigos de três e quatro letras não são únicos e não padronizados.

Eu sugeriria começar com DateTime :: Filho time, e possivelmente construindo novos tipos para seus fusos horários, se você não conseguir encontrar o que está procurando na lista. Você também pode encontrar um formatador DateTime que esteja em conformidade com a sua sintaxe (há um grande número deles), mas, caso contrário, não é difícil simplesmente usar um regex para extrair os campos de data e hora e passá -lo para um construtor de tempo.

Depois de ter suas cordas analisadas em objetos DateTime com os tempos definidos corretamente, não há problema em convertê -los de volta para o MySQL Timestamps: Basta usar DateTime :: format :: mysql:

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

Tente usar o Data hora módulo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top