2009-11-24 3 views
2

Есть несколько программ/сценариев, которые необходимо запускать в определенное время в часовом поясе разные из системного часового пояса.Планирование сценариев в другом часовом поясе

A la crontab в Perl, но тот, который соблюдает правила часового пояса и DST в регионе, отличном от того, в котором настроена система.

Вот случай использования: я создать лист первенствовать со временем в РТ в столбце В и соответствующей программы/сценария Perl, чтобы запустить в колонке C.

Ничего конкретного об этой информации, являющейся в Excel лист - также может быть текстовым файлом/«crontab».

Perl-скрипт будет считывать данные с листа excel и запускать/запускать эти сценарии в нужное время.

Следует помнить, что скрипт Perl должен работать правильно, независимо от того, в какой временной зоне система работает.

Независимо от того, работает ли сценарий в ящике в NY или IL или CA, он должен запускать скрипты в момент, указанный в записях файла, в соответствии с Тихим Стандартным временем с DST.

Очень важно, как я уже говорил, «знать», «automagically» (без каких-либо явных программ) последних правил DST для области PT.

Что вы предложите?

Возможно, я могу посетить какой-либо веб-сайт, который показывает текущее время в этом регионе и сканировать значение времени из него и запускать скрипты, когда это подходящее время?

Любой такой удобный сайт скрепера для экрана Perl?

Или, может быть, я могу использовать некоторые смарт-модуль Perl, как Schedule::Cron

Для записи, большое количество хороших предложений пришли в http://www.perlmonks.org/index.pl?node_id=772934, однако, они, в типичном в/хронах мода, работе как за настроенный часовой пояс системы.

ответ

2

В общем, если вы интересуетесь часовыми поясами, представляете время внутри в каком-то универсальном формате и конвертируете время только для отображения.

Применяя это к своей проблеме, напишите crontab, время которого выражено в GMT. На каждом рабочем компьютере конвертируйте в локальное время и установите crontab.

вводные:

#! /usr/bin/perl 

use warnings; 
use strict; 

use feature qw/ switch /; 

use Time::Local qw/ timegm /; 

Для преобразования этой программы поддерживает, использовать сегодняшнюю дату и подставит время от текущего cronjob. Возврат скорректированный час и день недели-офсет:

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

Возьмите указание времени пять-поля из текущей cronjob и преобразовать его из GMT к местному времени. Обратите внимание, что полностью общая реализация будет поддерживать 32 (i.e., 2 ** 5) случаях.

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

    given ("$gmmin,$gmhr,$gmmday,$gmmon,$gmwday") { 
    # trivial case: no adjustment necessary 
    when (/^\d+,\*,\*,\*,\*$/) { 
     return ($gmmin,$gmhr,$gmmday,$gmmon,$gmwday); 
    } 

    # hour and maybe minute 
    when (/^(\d+|\*),\d+,\*,\*,\*$/) { 
     my($lhour) = gmtoday @_; 
     return ($gmmin,$lhour,$gmmday,$gmmon,$gmwday); 
    } 

    # day of week, hour, and maybe minute 
    when (/^(\d+|\*),\d+,\*,\*,\d+$/) { 
     my($lhour,$wdoff) = gmtoday @_; 
     return ($gmmin,$lhour,$gmmday,$gmmon,$gmwday+$wdoff); 
    } 

    default { 
     warn "$0: unhandled case: $gmmin $gmhr $gmmday $gmmon $gmwday"; 
     return; 
    } 
    } 
} 

И, наконец, основной цикл считывает каждую строку с входа и генерирует соответствующий выход. Обратите внимание, что мы не уничтожаем необработанные времена: вместо этого они появляются в качестве комментариев.

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

Для этого Сорта-кронтаб

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) 

выхода следующего при запуске в Центральных США часового пояса:

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

ОТЛИЧНАЯ РАБОТА! – PoorLuzer

1

Хотя я, конечно, считаю, что существуют «более чистые» решения, будет ли следующая работа?

  • установить хроны для запуска сценариев несколько часов вперед возможного диапазона времени вы на самом деле хотите, чтобы сценарий запуска

  • обрабатывать обнаружения временной зоны в сценарии и он спать на соответствующую сумму времени

Опять же, я знаю, что это своего рода kludgey, но я думал, что положу его туда.

+0

мне нравится. Даже не кажется, что мне нравится. Можно даже запускать cron-скрипты ежечасно, а затем разрешать им решать, будет ли это подходящее время или нет (если почасовое соответствует графику). – innaM

+0

Я думал о создании объекта DateTime, имеющего подробную информацию о времени в PT, а затем используя один из модулей планировщика Perl для выполнения выполнения задачи. Однако мне интересно, как убедиться, что это не приводит к проблемам, когда правила DST меняются/становятся недоступными. Это решение, в котором мне нужна помощь. – PoorLuzer

+0

Зачем это нужно в PT? Можете ли вы просто иметь его UTC? – malonso

2

В расписании сохраняйте количество секунд от эпохи, когда каждый прогон должен произойти, а не строка даты/времени.

Расширение немного:

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

дает мне

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

потому что 2:00 утра 14 марта 2010, когда происходит переключение. С другой стороны, используя hour => 3, я получаю: 1268553600. Теперь, в Нью-Йорке, я использую:

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

Таким образом, решение, как представляется, не планировать эти события во время несуществующего времени в вашем местного часового пояса. Это не требует сложной логики: просто заверните вызов конструктора DateTime в eval и обработайте исключительное время.

+1

@ Синан: Это работает, за исключением того, что секунды с эпохи будут меняться два раза в год, так как его сценарий должен работать в одно и то же время Тихого океана в отношении летнего времени. Осенью он должен будет добавить час и вычесть его снова весной. –

+0

ОТЛИЧНОЕ понимание Адама! Это проблема, о которой я беспокоюсь. Написание кода не является проблемой - проблема в том, что он станет настраиваемым фрагментом, а не тем, что является частью CPAN-модуля standrd. Мне интересно, не существует ли модуля/стандартизованного способа сделать это без написания специального кода (мне нужно было бы написать документацию, тестовые примеры и тестовые данные, чтобы убедиться, что мой пользовательский код верен, поскольку это, безусловно, вносит в производство код)? – PoorLuzer

0

Используйте модуль DateTime для расчета времени.

Так что, если ваша установка говорит, чтобы запустить сценарий в 2:30 утра каждый день, вы будете нуждаться в логику:

  • Try создать DateTime объект для 2:30 в часовом поясе Америки \ Los_Angeles.

  • Если ни один объект не добавляет 5 минут и повторите попытку. Отказаться после 2-часового смещения.

  • После того, как у вас есть DateTime объекта, вы можете сделать сравнение с DateTime->now или извлечь время эпохального от вашего объекта и сравнить его с результатами time.

Обратите внимание, что я выбрал 2:30 утра, поскольку это время не будет существовать не менее 1 дня в году. Вот почему вам нужен цикл, который добавляет смещение.

Смежные вопросы