Question

Nous utilisons actuellement une API 3ème partie qui fournit datetime dans le format suivant:

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

Cependant, nous voulons stocker ces objets dans MySQL datetime dans un champ datetime standard qui nécessite le format suivant:

YYYY-MM-DD HH:MM:SS

À l'heure actuelle, nous utilisons le code suivant qui font état d'erreurs pour certains fuseaux horaires tels que KDT, JDT et STIC:

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

Pouvez-vous recommander une meilleure mise en œuvre du code Perl ci-dessus pour convertir les objets DateTime de l'API au format approprié et l'heure sur notre serveur à insérer dans un champ datetime MySQL?

Merci d'avance pour votre aide et conseils!

Était-ce utile?

La solution

Rangez les temps interne GMT. Faites toutes les manipulations en GMT. Puis, au dernier moment, comme vous êtes sur le point d'afficher les résultats à l'utilisateur, puis convertir à l'heure locale de l'utilisateur.

Je recommande d'utiliser , mais vous « ll ont pour augmenter ses décalages de fuseau horaire, car il n'a pas d'Indochine Heure d'été et le Japon, heure avancée, par exemple.

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

Sortie:

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

Pour soutenir la requête que vous souhaitez, stocker l'heure GMT plus un décalage ( i.e.. , de GMT à l'heure locale de l'API). Notez que le code ci-dessous suppose que si str2time peut analyser un temps donné, strptime peut aussi. Changer la boucle

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

Avec le temps recueilli, rendu comme 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 sortie est

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;

et nous pouvons tuyau à 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

Autres conseils

Lors de la mémorisation des dates, vous devez toujours les stocker en UTC. De cette façon, vous pouvez les chercher dans la base de données et de les convertir au fuseau horaire approprié si nécessaire pour l'affichage à l'utilisateur.

Pour la manipulation datetimes correctement en Perl, je recommande vivement le DateTime suite, ce qui a parseurs et pour toutes sortes formatteurs de différents formats d'entrée et de sortie.

Je ne sais pas si les dates indiquées dans votre OP sont un format standard, mais sinon, il serait assez facile de construire un format DateTime d'eux:

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

Vous pouvez ensuite utiliser DateTime :: Format :: MySQL pour convertir la date à un datetime compatible avec MySQL.

Vous avez probablement de dire explicitement le constructeur DateTime qui fuseau horaire (s) que vous traitez, parce que les codes de trois et quatre lettres ne sont pas uniques et non standardisés.

Je suggère à commencer par DateTime :: TimeZone , et peut-être la construction de nouvelles types pour vos fuseaux horaires si vous ne trouvez pas ce que vous cherchez dans la liste. Vous pouvez également trouver un formatter DateTime qui est conforme à votre syntaxe (il y a un grand nombre d'entre eux), mais sinon il est difficile de ne pas utiliser simplement une expression régulière pour extraire les champs de date et d'heure et de transmettre cela à un constructeur DateTime.

Une fois que vous avez vos cordes en DateTime objets analysés avec le temps correctement réglé, il n'y a pas de problème du tout pour les reconvertir vers MySQL horodatages: il suffit d'utiliser DateTime :: Format :: MySQL :

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

Essayez d'utiliser le module DateTime .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top