2009-11-24 5 views
2

Certains programmes/scripts doivent être exécutés à des heures spécifiques dans un fuseau horaire différent du fuseau horaire du système.Programmation de scripts dans un fuseau horaire différent

A la crontab en Perl, mais qui respecte un fuseau horaire et des règles DST dans une région différente de celle dans laquelle le système est configuré.

Voici le cas d'utilisation: Je vais créer une feuille Excel avec le temps PT dans la colonne B et le programme correspondant/script Perl pour exécuter dans la colonne C.

Rien précis sur ces informations étant dans un Excel feuille - pourrait être le fichier texte brut/"crontab" entrée aussi. Un script Perl lira les données de la feuille Excel et exécutera/produira ces scripts au bon moment. La chose à garder à l'esprit est que le script Perl devrait fonctionner correctement quel que soit le fuseau horaire sur lequel le système est en cours d'exécution. Indépendamment du fait que le script s'exécute sur une boîte dans NY ou IL ou CA, il doit générer les scripts à l'heure mentionnée dans les entrées de fichier selon l'heure standard du Pacifique avec DST à l'esprit. Comme je l'ai déjà dit, il est très important de savoir "automagiquement" (sans programmation explicite) des dernières règles DST pour la région PT.

Que suggéreriez-vous? Peut-être que je peux visiter un site web qui montre l'heure actuelle dans cette région et en analyser la valeur, et exécuter les scripts quand c'est l'heure correcte?

Un tel site convivial de grattoir d'écran de Perl?

Ou peut-être que je peux utiliser un module Perl intelligent, comme Schedule::Cron

Pour mémoire, un grand nombre de bonnes suggestions est venu à http://www.perlmonks.org/index.pl?node_id=772934, cependant, ils, de façon typique à/Cron, travail par le système configuré fuseau horaire.

Répondre

2

En général, si vous vous souciez des fuseaux horaires, représentez les heures en interne dans un format universel et convertissez les heures à des fins d'affichage uniquement.

En appliquant cela à votre problème, écrivez une crontab dont les heures sont exprimées en GMT. Sur chaque machine de travail, convertissez en heure locale et installez le crontab.

matière avant:

#! /usr/bin/perl 

use warnings; 
use strict; 

use feature qw/ switch /; 

use Time::Local qw/ timegm /; 

Pour les conversions de ce programme prend en charge, utilisez la date d'aujourd'hui et de remplacer le temps de la cronjob actuelle. Retour à l'heure ajustée et jour de la semaine offset:

sub gmtoday { 
    my($gmmin,$gmhr,$gmmday,$gmmon,$gmwday) = @_; 

    my @gmtime = gmtime $^T; 
    my(undef,undef,$hour,$mday,$mon,$year,$wday) = @gmtime; 

    my @args = (
    0, # sec 
    $gmmin eq "*" ? "0" : $gmmin, 
    $gmhr, 
    $mday,       
    $mon, 
    $year, 
); 

    my($lhour,$lwday) = (localtime timegm @args)[2,6]; 

    ($lhour, $lwday - $wday); 
} 

Prenez la spécification de temps de cinq champs de l'cronjob en cours et de le convertir à l'heure GMT à l'heure locale. Il convient de noter qu'une implémentation entièrement générale prendrait en charge 32 cas (, c'est-à-dire, 2 ** 5). Enfin, la boucle principale lit chaque ligne à partir de l'entrée et génère la sortie appropriée. Notez que nous ne détruisons pas les temps non traités: ils apparaissent plutôt dans la sortie comme des commentaires.

while (<>) { 
    if (/^\s*(?:#.*)?$/) { 
    print; 
    next; 
    } 

    chomp; 
    my @gmcron = split " ", $_, 6; 

    my $cmd = pop @gmcron; 
    my @localcron = localcron @gmcron; 

    if (@localcron) { 
    print join(" " => @localcron), "\t", $cmd, "\n" 
    } 
    else { 
    print "# ", $_, "\n"; 
    } 
} 

Pour ce sorta-crontab

33 * * * * minute only 
0 0 * * * minute and hour 
0 10 * * 1 minute, hour, and wday (same day) 
0 2 * * 1 minute, hour, and wday (cross day) 

la sortie est la suivante lorsqu'il est exécuté dans le fuseau horaire central des États-Unis:

33 * * * * minute only 
0 18 * * * minute and hour 
0 4 * * 1 minute, hour, and wday (same day) 
0 20 * * 0 minute, hour, and wday (cross day) 
+0

EXCELLENT travail! – PoorLuzer

1

Même si je pense certainement qu'il existe des solutions «plus propres», est-ce que ce qui suit fonctionnerait?

  • définir le cron pour exécuter les scripts plusieurs heures d'avance sur la gamme possible de fois que vous voulez réellement le script à exécuter

  • poignée de détection de fuseau horaire dans le script et avoir le sommeil pour le montant approprié de temps

Encore une fois, je sais que c'est un peu kludgey mais je pensais que je mettrais dehors là.

+0

J'aime ça. Cela ne me semble même pas très clair. On pourrait même lancer les scripts cron toutes les heures et ensuite les laisser décider si c'est le bon moment ou pas (si horaire correspond à l'horaire). – innaM

+0

Je pensais à créer un objet DateTime ayant les détails de l'heure dans PT, puis à utiliser l'un des modules du planificateur Perl pour effectuer l'exécution de la tâche. Je me demande toutefois comment m'assurer que cela n'entraîne pas de problèmes lorsque les règles DST changent/sont désactivées. C'est une décision sur laquelle j'ai besoin d'aide. – PoorLuzer

+0

Pourquoi doit-il être en PT? Pouvez-vous juste nous avoir UTC? – malonso

2

Dans la planification, stockez le nombre de secondes à partir de l'époque où chaque exécution doit avoir lieu plutôt qu'une chaîne de date/heure.

expansion un peu:

#!/usr/bin/perl 

use strict; use warnings; 

use DateTime; 

my $dt = DateTime->new(
    year => 2010, 
    month => 3, 
    day => 14, 
    hour => 2, 
    minute => 0, 
    second => 0, 
    time_zone => 'America/Chicago', 
); 

print $dt->epoch, "\n"; 

me donne

 
Invalid local time for date in time zone: America/Chicago 

parce 02h00 le 14 Mars 2010 est lorsque l'interrupteur se produit. D'autre part, en utilisant hour => 3, j'obtiens: 1268553600. Maintenant, à New York, je l'utilise:

 
C:\Temp> perl -e "print scalar localtime 1268553600" 
Sun Mar 14 04:00:00 2010 

Ainsi, la solution semble être d'éviter de programmer ces événements pendant les périodes inexistants dans votre zone locale temps. Cela ne nécessite pas de logique élaborée: Il suffit d'entourer l'appel DateTime constructeur dans un eval et de faire face à l'heure exceptionnelle.

+1

@Sinan: Cela fonctionne sauf que les secondes de l'époque changeront deux fois par an, car son script doit fonctionner au même moment du Pacifique en ce qui concerne l'heure d'été. À l'automne, il devra ajouter une heure et la soustraire à nouveau au printemps. –

+0

EXCELLENTE compréhension d'Adam! C'est un problème qui m'inquiète. L'écriture de code n'est pas le problème - le problème est qu'il deviendrait un extrait personnalisé au lieu de quelque chose qui fait partie d'un module CPAN autonome. Ce que je me demande est - est-il déjà aucun module/manière standardisée de faire ceci sans écrire le code fait sur commande (je devrais écrire la documentation, les cas de test et les données de test pour m'assurer que mon code est correct code)? – PoorLuzer

0

Utilisez le module DateTime pour calculer les heures.

Donc, si votre configuration dit d'exécuter un script à 02h30 tous les jours, vous aurez besoin logique:

  • Essayez de créer un objet DateTime pour 02h30 dans le fuseau horaire Amérique \ Los_Angeles.

  • Si aucun objet n'ajoute 5 minutes à l'heure et réessayez. Abandonner après 2 heures de décalage.

  • Une fois que vous avez un objet DateTime, vous pouvez faire des comparaisons avec DateTime->now ou extraire un temps d'époque de votre objet et les comparer avec les résultats de time.

Notez que j'ai choisi 2:30 am, puisque ce temps n'existera pas au moins 1 jour par an. C'est pourquoi vous devez avoir une boucle qui ajoute un décalage.

Questions connexes