AT kleine Helferlein: Unterschied zwischen den Versionen
F Klee (Diskussion | Beiträge) KKeine Bearbeitungszusammenfassung |
F Klee (Diskussion | Beiträge) (Inhalt eingefügt) |
||
Zeile 4: | Zeile 4: | ||
=== AT am x-ten Wochentag im Monat ausführen === | === AT am x-ten Wochentag im Monat ausführen === | ||
Aufgabe ist es, das at z.B. an jedem 2. Montag im Monat auszuführen. Zusätzlich gibt es auch die Möglichkeit, das at immer am z.B. letzten Montag im Monat auszuführen.<syntaxhighlight lang="perl"> | |||
######################################## | |||
# | |||
# Berechnung des Datums des | |||
# x.ten Wochentags im Monat | |||
# | |||
# x=1-4 x.ter Wochentag im Monat | |||
# x=9 letzter Wochentag im Monat | |||
# w=1-7 Wochentag, 1=Montag | |||
# h,m,s Uhrzeit Stunde, Minute, Sekunde | |||
# | |||
sub at_xwday($$$$$) { | |||
my ($x,$w,$h,$m,$s) = @_; | |||
my $ziel_tag = 0; | |||
# akt. Datum und Uhrzeit in Variablen aufteilen | |||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = | |||
localtime(time); | |||
# bei Neuberechnung einen Monat addieren | |||
my $add = $data{AT_RECOMPUTE} ? 1 : 0; | |||
$mon = $mon + $add; | |||
my ($nm, $ny) = ($mon == 12) ? (0,$year+1) : ($mon,$year); | |||
# Letztes Vorkommen des Wochentags berechnen? | |||
if ($x == 9) { | |||
# Berechnen des letzten Tags des Monats | |||
# ersten Tag des Folgemonats als timestamp | |||
my ($xm, $xy) = ($mon == 11) ? (0,$year+1) : ($mon+1,$year); | |||
my $nt = mktime(0, 0, 0, 1, $xm, $xy); | |||
# letzter Tag des aktuellen Monats = erster Tag des Folgemonats minus ein Tag | |||
my ($letzter_tag_des_monats, $letzter_wochentag) = (localtime($nt - DAYSECONDS))[3,6]; | |||
# Prüfen, ob der letzte Wochentag im Monat mit dem gewünschten Wochentag übereinstimmt | |||
$ziel_tag = $letzter_tag_des_monats; | |||
if ($letzter_wochentag > $w) { | |||
# Falls der letzte Wochentag später im Monat ist, subtrahiere die Differenz | |||
my $differenz = $letzter_wochentag - $w; | |||
$ziel_tag -= $differenz; | |||
} elsif ($letzter_wochentag < $w) { | |||
# Falls der letzte Wochentag früher im Monat ist, subtrahiere 7 plus die Differenz | |||
my $differenz = $w - $letzter_wochentag; | |||
$ziel_tag -= (7 - $differenz); | |||
} | |||
} else { | |||
# Berechne den Tag des ersten Vorkommens des Wochentags im Monat | |||
my $erster_tag = 1; | |||
my $erster_tag_des_monats = (localtime(mktime(0,0,0,$erster_tag,$nm,$ny)))[6]; | |||
my $erstes_vorkommen = ($w - $erster_tag_des_monats + 7) % 7 + 1; | |||
# Berechne den Tag des x.ten Vorkommens des Wochentags im Monat | |||
$ziel_tag = $erstes_vorkommen + 7 * ($x - 1); | |||
# Überprüfe, ob das Datum im gültigen Bereich liegt | |||
if ($ziel_tag > 31 || $ziel_tag < 1) { | |||
return "Ungültiges Datum"; | |||
} | |||
} | |||
return mktime($s,$m,$h,$ziel_tag,$nm,$ny); | |||
} | |||
</syntaxhighlight>Als Parameter benötigt die Funktion, welches Vorkommen des Wochentags berechnet werden soll (1-4). Soll das letzte Vorkommen berechnet werden, übergibt man 9. Der Montag ist der Wochentag 1. Danach kommen als getrennte Parameter Stunde, Minute und Sekunde. | |||
=== AT alle x Wochen ausführen === | === AT alle x Wochen ausführen === | ||
Soll ein Termin z.B. alle sechs Wochen stattfinden, so kann folgende Funktion genutzt werden.<syntaxhighlight lang="perl"> | |||
######################################## | |||
# | |||
# Berechnung des Datums des | |||
# nächsten Treffens in sechs Wochen | |||
sub at_sixweek($) { | |||
my ($tm) = @_; | |||
my $delta = 3628800; # Zeit zwischen den Terminen in Sekunden, hier 6 Wochen | |||
return "Wrong timespec, use \"yyyy-mm-ddThh:mm:ss\"" if($tm !~ m/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)$/); | |||
my ($y,$m,$d,$h,$m2,$s) = ($1,$2,$3,$4,$5,$6); | |||
my $abstime = mktime($s,$m2,$h,$d,$m-1,$y-1900, 0,0,-1); | |||
if ($data{AT_RECOMPUTE}){ | |||
# bei Neuberechnung sechs Wochen zur aktuellen Zeit addieren | |||
my $now = int(time); | |||
$abstime = $now+$delta; | |||
} | |||
return $abstime; | |||
} | |||
</syntaxhighlight>Dabei wird der erste Ausführungstermin im FHEM-üblichen Format ("yyyy-mm-ddThh:mm:ss") übergeben. Die Variable $delta enthält das Intervall in Sekunden. Es kann entsprechend angepasst werden. Die Neuberechnung erfolgt ausgehend vom aktuellen Datum/Uhrzeit. Es kann also als erster Termin nur ein Termin in der Zukunft angegeben werden. | |||
[[Kategorie:Code Snippets]] | [[Kategorie:Code Snippets]] |
Version vom 20. April 2024, 17:07 Uhr
Ein AT kann statt einer Uhrzeit bzw. eines Datums mit einer Uhrzeit auch eine Perl-Funktion nutzen. Beispiel solcher Funktionen sind at_ultimo oder das Modul SUNRISE_EL. Hier sollen weitere Funktionen gezeigt werden.
Der Code kann in der 99 myUtils untergebracht werden.
AT am x-ten Wochentag im Monat ausführen
Aufgabe ist es, das at z.B. an jedem 2. Montag im Monat auszuführen. Zusätzlich gibt es auch die Möglichkeit, das at immer am z.B. letzten Montag im Monat auszuführen.
########################################
#
# Berechnung des Datums des
# x.ten Wochentags im Monat
#
# x=1-4 x.ter Wochentag im Monat
# x=9 letzter Wochentag im Monat
# w=1-7 Wochentag, 1=Montag
# h,m,s Uhrzeit Stunde, Minute, Sekunde
#
sub at_xwday($$$$$) {
my ($x,$w,$h,$m,$s) = @_;
my $ziel_tag = 0;
# akt. Datum und Uhrzeit in Variablen aufteilen
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime(time);
# bei Neuberechnung einen Monat addieren
my $add = $data{AT_RECOMPUTE} ? 1 : 0;
$mon = $mon + $add;
my ($nm, $ny) = ($mon == 12) ? (0,$year+1) : ($mon,$year);
# Letztes Vorkommen des Wochentags berechnen?
if ($x == 9) {
# Berechnen des letzten Tags des Monats
# ersten Tag des Folgemonats als timestamp
my ($xm, $xy) = ($mon == 11) ? (0,$year+1) : ($mon+1,$year);
my $nt = mktime(0, 0, 0, 1, $xm, $xy);
# letzter Tag des aktuellen Monats = erster Tag des Folgemonats minus ein Tag
my ($letzter_tag_des_monats, $letzter_wochentag) = (localtime($nt - DAYSECONDS))[3,6];
# Prüfen, ob der letzte Wochentag im Monat mit dem gewünschten Wochentag übereinstimmt
$ziel_tag = $letzter_tag_des_monats;
if ($letzter_wochentag > $w) {
# Falls der letzte Wochentag später im Monat ist, subtrahiere die Differenz
my $differenz = $letzter_wochentag - $w;
$ziel_tag -= $differenz;
} elsif ($letzter_wochentag < $w) {
# Falls der letzte Wochentag früher im Monat ist, subtrahiere 7 plus die Differenz
my $differenz = $w - $letzter_wochentag;
$ziel_tag -= (7 - $differenz);
}
} else {
# Berechne den Tag des ersten Vorkommens des Wochentags im Monat
my $erster_tag = 1;
my $erster_tag_des_monats = (localtime(mktime(0,0,0,$erster_tag,$nm,$ny)))[6];
my $erstes_vorkommen = ($w - $erster_tag_des_monats + 7) % 7 + 1;
# Berechne den Tag des x.ten Vorkommens des Wochentags im Monat
$ziel_tag = $erstes_vorkommen + 7 * ($x - 1);
# Überprüfe, ob das Datum im gültigen Bereich liegt
if ($ziel_tag > 31 || $ziel_tag < 1) {
return "Ungültiges Datum";
}
}
return mktime($s,$m,$h,$ziel_tag,$nm,$ny);
}
Als Parameter benötigt die Funktion, welches Vorkommen des Wochentags berechnet werden soll (1-4). Soll das letzte Vorkommen berechnet werden, übergibt man 9. Der Montag ist der Wochentag 1. Danach kommen als getrennte Parameter Stunde, Minute und Sekunde.
AT alle x Wochen ausführen
Soll ein Termin z.B. alle sechs Wochen stattfinden, so kann folgende Funktion genutzt werden.
########################################
#
# Berechnung des Datums des
# nächsten Treffens in sechs Wochen
sub at_sixweek($) {
my ($tm) = @_;
my $delta = 3628800; # Zeit zwischen den Terminen in Sekunden, hier 6 Wochen
return "Wrong timespec, use \"yyyy-mm-ddThh:mm:ss\"" if($tm !~ m/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)$/);
my ($y,$m,$d,$h,$m2,$s) = ($1,$2,$3,$4,$5,$6);
my $abstime = mktime($s,$m2,$h,$d,$m-1,$y-1900, 0,0,-1);
if ($data{AT_RECOMPUTE}){
# bei Neuberechnung sechs Wochen zur aktuellen Zeit addieren
my $now = int(time);
$abstime = $now+$delta;
}
return $abstime;
}
Dabei wird der erste Ausführungstermin im FHEM-üblichen Format ("yyyy-mm-ddThh:mm:ss") übergeben. Die Variable $delta enthält das Intervall in Sekunden. Es kann entsprechend angepasst werden. Die Neuberechnung erfolgt ausgehend vom aktuellen Datum/Uhrzeit. Es kann also als erster Termin nur ein Termin in der Zukunft angegeben werden.