Niedawne kupno telefonu zainspirowało mnie do przygotowania rozkładu zajęć dla studiów zaocznych w formacie vcal. Rozkład ww. zajęć jest opracowywany w aplikacji pn. Rozkład Zajęć na Uczelni (w skrócie RZU). Układanie tegoż planu jest dość pracochłonne ponieważ nie ma tu żadnego powtarzalnego cyklu a zajęcia planuje się w skali całego semestru (a nie tygodnia jak ma to miejsce na studiach dziennych).
Gotowy plan jest zamieniany następnie na format XML a potem sortowany wg. wykładowców, grup, sal oraz chronologicznie. Na etapie drukowania/sortowania nie jest wykorzystywany program RZU, bo rezultaty są bardziej niż kiepskie ale Perl+pdfTeX. Wynik można obejrzeć tutaj. BTW skrypty Perla + style TeXa są tutaj, tyle że są mocno związane z zasadami/konwencjami tworzenia rozkładów na WZUG i w związku z tym niekoniecznie przydadzą się każdemu użytkownikowi ww. programu RZU.
Zatem zachciało mi się dodać do generowanych przez skrypt ast2x.pl
formatów vcal. Nie wchodząc w zawiłości formatu (tutaj jest ładnie sformatowana dokumentacja), mój dokument powinien zawierać wpisy postaci:
BEGIN:VEVENT
DTSTART:20070310T070000Z
DTEND:20070310T083000Z
DESCRIPTION: 501, 502/Gospodarka elektroniczna/C-21/08.00--09.30/Wrycza
UID:www.wzr.pl_l_00155_20070310T070000Z
LOCATION:C-21
SUMMARY:501, 502/Gospodarka elektroniczna/C-21
END:VEVENT
Jak widać, format jest prawie samoopisujący się. Pole UID
ma być unikatowe, co IMHO można np. osiągnąć tak, jak w przykładzie wyżej, tj. konstruując URL postaci: www.wzr.pl_l_nr-wykł_początek-zaj
. Prawdziwy kłopot to pola DTSTART/DTEND, bo czasy muszą być w UTC. Oczywiście RZU generuje czasy lokalne, więc trzeba je zamienić na UTC uwzględniając przesunięcie oraz czas letni/zimowy. Nie chciałem korzystać przy tym z jakiś egzotycznych bibliotek Perla, żeby później nie musieć tego instalować (osoba pracująca nad planem używa MS Windows, itd...). Znalazłem zatem następującą formułę wyznaczania dnia zmiany czasu (więcej jest na stronie: webexhibits.org/daylightsaving/):
sub euDaylightSavings {
# All countries in Europe except Iceland observe DST and change
# on the same date and time, starting on the last Sunday in March
# and ending on the last Sunday in October.
# cf. http://en.wikipedia.org/wiki/Daylight_saving_time_around_the_world
# The subroutine returns the exact day-of-month of DST change.
# The examplar usage: daylightSavings (2008,'march')
#
my ($yr,$when) = @_;
if ( $when =~ /mar/ ) { return (31 - (5*$yr/4 + 4) % 7); }
else { return (31 - (5*$yr/4 + 1) % 7); }
}
Powyższe pozwala na łatwe ustalenie w jakim dniu następuje przesunięcie. Np. w roku 2007 były to odpowiednio 25 marca oraz 28 października, co oznacza, że od 25 marca (włącznie) do 27 października (też włącznie) trzeba dodać jedną godzinę więcej do przesunięcia między UTC a CET.
Teraz z kolei jak stwierdzić czy dana data jest przed czy po innej? Konsultując się z Perl Receptury znalazłem:
use Date::Calc qw(Delta_Days);
my $cet_offset = 1;
## $yr, $mn, $dy -- odp. rok, miesiąc, dzień
my $dst_start = euDaylightSavings($yr, 'mar');
my $dst_end = euDaylightSavings($yr, 'oct');
## funkcja Delta_Days zwraca liczbę dni między y1, m1, d1 a y2, m2, d2
if ( ( Delta_Days($yr, 03, $dst_start, $yr, $mn, $dy) >= 0 ) &&
( Delta_Days($yr, 10, $dst_end, $yr, $mn, $dy) < 0 ) ) {
return $cet_offset + 1 }
else { return $cet_offset }
Tyle, że Date::Calc
nie jest standardowo dostępny w Perlu. Ponieważ jednak nie potrzebuję liczby dni między datami a jedynie określenia porządku więc być może wystarczy coś następującego:
sub Delta_Days{
my ( $y1, $m1, $d1, $y2, $m2, $d2 ) = @_ ;
if ($y1 < $y2) { return 1 }
elsif ($y1 > $y2) { return -1 }
else {
if ($m1 < $m2) { return 1 }
elsif ($m1 > $m2) { return -1 }
else {
if ($d1 < $d2) { return 1 }
elsif ($d1 > $d2) { return -1 }
else { return 0 }
}
}
}
Wygląda, że działa. Ale pewności nie ma:-) Dodam na koniec że na etapie testów usiłowałem też korzystać z biblioteki Net::ICal
ale zrezygnowałem--niewiele wnosi. Aha w jakim kodowaniu toto ostatecznie ma być, UTF-8? No chyba tak.
Brak komentarzy:
Prześlij komentarz