Hallo,
ich habe einen Geburtstagskalender eingebunden. Darin sind auch Personen , die vor 1970 geboren sind. Ein solcher Geburtstag ist eine jährlich wiederkehrender Eintrag im Kalender. Das Modul 57_Calendar.pm berechnet daraus die nächste Startzeit (also den Geburtstag im Jahr 2015, wenn er dieses Jahr noch nicht war oder halt für 2016, wenn er bereits stattfand). Dabei verwendet die Funktion sub tm die fhem Funktion fhemTimeLocal aus der fhem.pl. Diese wiederum ruft dann fhemTimeGm auf.
Es sollen die Skunden (epoch) seit Thu Jan 1 01:00:00 1970 berechnet werden. Und dazu notwendig ist auch die Berechnung, wieviel Schaltjahre es bis zu dem gegebene Datum gibt.
Implementiert ist:
my $leapyears= int(($year-1969)/4) - int(($year-1901)/100) + int(($year-1601)/400);
Diese Formel liefert aber eine falsche Anzahl von Schaltjahren für Daten, die vor 1970 sind.
ich hab mal folgendes mit Erfolg ausprobiert:
my $leapyears_date = ( int(($year-1)/4) - int(($year-1)/100) + int(($year-1)/400) ); # Schaltjahre seit 01.01.01 00:00:00 bis $year
my $leapyears_1970 = ( int((1970-1)/4) - int((1970-1)/100) + int((1970-1)/400) ); # Schaltjahre seit 01.01.01 00:00:00 bis 1970
my $leapyears = $leapyears_date - $leapyears_1970; # Schaltjahre seit 1970 (positiv, wenn größer 1970 - negativ, wenn kleiner 1970)
Habs mal tabellarisch dargestellt. Die alte Formel verrechnet sich um 1 Schaltjahr.
Jahr Anzahl Schaltjahre
alte neue
Formel Formel
1946 -5 -6
1947 -5 -6
1948 -5 -6
1949 -5 -5
1950 -4 -5
1951 -4 -5
1952 -4 -5
1953 -4 -4
1954 -3 -4
1955 -3 -4
1956 -3 -4
1957 -3 -3
1958 -2 -3
1959 -2 -3
1960 -2 -3
1961 -2 -2
1962 -1 -2
1963 -1 -2
1964 -1 -2
1965 -1 -1
1966 0 -1
1967 0 -1
1968 0 -1
1969 0 0
1970 0 0
1971 0 0
1972 0 0
1973 1 1
1974 1 1
1975 1 1
1976 1 1
1977 2 2
1978 2 2
1979 2 2
1980 2 2
Das Kalendermodul macht z.B. while($self->{end} < $t and $self->advanceToNextOccurance()) { ; }. Darin wir auch tm() verwendet, und zwar viele male.
Daraus folgen ergebliche Abweichungen vom richtigen geburtstag.
Könnte diese Korrektur der Schlatjahre in die offizielle fhem.pl aufgenommen werden?
Hallo,
genau das Problem (Schaltjahre i.V.m. wiederkehrenden Terminen, deren Serie vor 1970 beginnt) hatten wir schon mal erörtert.
http://forum.fhem.de/index.php/topic,25881.msg196767.html#msg196767 (http://forum.fhem.de/index.php/topic,25881.msg196767.html#msg196767)
Mangels Interesse der damals Beteiligten verlief die Lösung im Sande. Daher Danke für Deine Initiative und den Patch. Das aktuelle Problem kommt vom int ().
Eine effiziente Version sollte m.E. aufgenommen werden.
Grüße
Boris
ZitatDas aktuelle Problem kommt vom int
Genauer gesagt: du willst immer nach unten runden, nicht zur Null hin. Folglich:
if (x<0) x=-int(-x); else x=int(x)
Habs eingecheckt.
Per Definition liefert die Funktion fhemTimeGm die Anzahl der Sekunden seit 1970 fuer einen gegebene Dateum/Uhrzeit. zurueck. Ich verstehe noch nicht, warum man diese Funktion mit einem Jahr < 1970 aufrufen will.
Das mit den leapyears ist aber nicht geändert in fhem.pl. Habs eben upgedatet.
Warum man diese Funktion mit einem Jahr < 1970 aufrufen will? Da mnusst du den ersten Beitrag lesen. (Stichworte Geburtstagskalender, Personen die vor 1970 geboren sind)
Nochmal zum Code:
my $leapyears_1970 = ( int((1970-1)/4) - int((1970-1)/100) + int((1970-1)/400) );
$leapyears_1970 wäre eine Konstante, nämlich 477, und müsste nicht jedesmal berechnet werden.
Man hätte also nur noch:
my $leapyears = ( int(($year-1)/4) - int(($year-1)/100) + int(($year-1)/400) ) - 477;
smurfix's weg wäre:
my $leapyears= floor(($year-1969)/4) - floor(($year-1901)/100) + floor(($year-1601)/400);
Gibts eine floor Funktion in perl?
floor ist aber evtl. aufwendiger als int und minus, meine ich.
Was meinen die perl experten?
ZitatWas meinen die perl experten?
Das Dateien fuer update nur einmal am Tag, kurz vor 8 bereitgestellt werden.
@rudolfkoenig
Eigentlich meinte ich, was die Experten zu floor für eine meinung haben. Und welche methode man nun implementiert.
Aber ich denke du weisst das und möchtest nur ein wenig lustig sein. Und dich vielleicht drüber sarkastisch lustig machen, dass ich nicht wusste, dass Dateien fuer update nur einmal am Tag, kurz vor 8 (in der Früh?) bereitgestellt werden.
Schade.
Zitat von: rudolfkoenig am 28 Juni 2015, 17:06:03
Habs eingecheckt.
$leapyears_1970 ist 477 (wenn ich mich nicht verrechnet habe). Ich hoffe, dass der Compiler so schlau ist, dass zu verstehen.
Bist Du sicher, dass das auch unter MacOS funktioniert? M.E. muss man die Anzahl der Schaltjahre seit dem Jahr 0 bis zur Epoche abziehen: 1970 bei Unix und 1904 bei MacOS.
Grüße
Boris
Eigentlich wollte ich wissen, wieso man die Sekunden fuer < 1970 braucht, Antwort habe ich darauf aber keins bekommen (natuerlich habe ich vorher alles gelesen), und ich dachte, aneinander vorbeireden ist in dieser Diskussion gewollt.
@Boris: $^O eq "MacOS" ist Geschichte, ich glaube nicht, dass jemand FHEM damit verwendet, und wenn, dann ist das mir auch egal. Unter OSX kommt:
perl -e 'print $^O'
darwin
Zitat von: rudolfkoenig am 28 Juni 2015, 19:53:55
Eigentlich wollte ich wissen, wieso man die Sekunden fuer < 1970 braucht, Antwort habe ich darauf aber keins bekommen (natuerlich habe ich vorher alles gelesen), und ich dachte, aneinander vorbeireden ist in dieser Diskussion gewollt.
Mein Calendar-Modul berechnet den nächsten Termin in einer Terminserie, indem vom Starttermin aus das Intervall solange draufgerechnet wird, bis zum ersten Mal bei einem Termin in der Zukunft angekommen wird. Ich habe einen kurzen Blick in den Code geworfen und sehe gerade nicht, wie die Schaltjahresproblematik da rein spielt. Aber sie besteht.
Jahre vor 1970 kommen dabei ins Spiel, wenn man Serientermine mit Starttermin vor 1970 einstellt. Bei Geburtstagen kann das der Fall sein. Das ist kein besonders cleverer Use Case, wie ich schon in dem weiter oben von mir referenzierten Posting angemerkt hatte. Aber wenn sich die Problematik so leicht lösen lässt, finde ich es gut, dass wir sie implementiert haben.
Zitat
@Boris: $^O eq "MacOS" ist Geschichte, ich glaube nicht, dass jemand FHEM damit verwendet, und wenn, dann ist das mir auch egal. Unter OSX kommt:
perl -e 'print $^O'
darwin
Wie fremd mir doch die Mac-Welt ist...
Viele Grüße
Boris
OSX ist ein BSD Derivat, mit ein paar grafischen Bibliotheken und Programmen oben drauf, Nachfolger von NeXTStep. Das was vor OS X da war (MacOS <= 9, aka $^O eq "MacOS") kenne ich auch nicht, es ist aber auch seit 15 Jahren irrelevant.