Ankündigung

Einklappen
Keine Ankündigung bisher.

Zeitfehler

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Zeitfehler

    Hallo Zusammen,

    mich beschäftigt ein eigentlich !sehr banales! Problem - ich behaupte trotzdem, das ist eine Frage an die Leute die einfach uns Eck denken können:

    Ich führe für einen Kalender Berechnungen mit dem Ostertag durch:

    Funktion: "easter_date(Jahresangabe4Stellig)"

    die Funktion liefert einen Zeitstempel im UnixStyle zurück, also z.B.
    für 2016: 1459033200 --> in Realzeit also: 27.03.2016 - 00:00:00

    Bis jetzt keine Probleme.

    Möchte ich jetzt z. B. den Ostermontag berechnen (liegt einen Tag nach dem Ostersonntag), so hatte ich mir gedacht ich addiere zu dieser Unixzeit einfach 86400 Sekunden auf (24h * 60min * 60sek).

    konkret also: 1459033200 + 86400 = 1459119600

    jetzt kommt aber das komische:

    rechne ich diesen Zeitstempel wieder nach Realzeit um (z. B. durch Funktion: "mktime"), erhalte ich folgende Ausgabe:
    1459119600 --> 28.03.2016 - 01:00:00

    meine Frage nun, woher kommt die eine Stunde (fett markiert)??

    Ich habe mich ewig eingelesen und vieles versucht, in manchen Jahren klappt es, da komme ich auf Uhrzeit 00:00:00 raus (so solls auch sein) - in anderen geht es nicht (z. B.: 2016 (Schaltjahr), 2024 (Schaltjahr), 2027 (kein Schaltjahr),...).

    Dann habe ich weitergelesen und den Fehler bei Sommer-/Winterzeit (Normalzeit) vermutet: hier lässt sich die Stunde korrigieren, zumindest manchmal... - nicht immer!

    Wo ist hier der Fehler, wo die Regelmäßigkeit, was mache ich falsch?
    Vielen Dank!!


  • #2
    Das ist keine fortgeschritte Frage, einfach nur ein Fehler dem jeder Passiert der mit Unix-Timestamps rumhantiert anstatt die Datetime-Klassen zu nutzen.
    http://www.zeitumstellung.de/zeitums...ch-archiv.html

    Zitat von dodoo Beitrag anzeigen
    Dann habe ich weitergelesen und den Fehler bei Sommer-/Winterzeit (Normalzeit) vermutet: hier lässt sich die Stunde korrigieren, zumindest manchmal... - nicht immer!
    Keine Ahnung was du damit meinst
    Zitat von nikosch
    Macht doch alle was Ihr wollt mit Eurem Billigscheiß. Von mir aus sollen alle Eure Server abrauchen.

    Kommentar


    • #3
      Zitat von dodoo Beitrag anzeigen
      Möchte ich jetzt z. B. den Ostermontag berechnen (liegt einen Tag nach dem Ostersonntag), so hatte ich mir gedacht ich addiere zu dieser Unixzeit einfach 86400 Sekunden auf (24h * 60min * 60sek).
      Falsch gedacht, es gibt jedes Jahr 2-3 Tage die eben nicht 86400 Sekunden lang sind. Verwende Datetime o.ä. um mit Zeiten zu rechnen.

      meine Frage nun, woher kommt die eine Stunde (fett markiert)??
      Das ist überhaupt nicht komisch. An dem Sonntag ist Zeitumstellung, die Stunde von 2-3 Uhr am Sonntag gibt es nicht, deswegen landest du mit +24h bei 1 Uhr am Montag. Warum das 2027 nicht funktioniert weiß ich nicht (ich würde fast auf einen Fehler von PHP tippen) aber Datetime rechnet da richtig.

      Kommentar


      • #4
        Zitat von dodoo Beitrag anzeigen
        Hallo Zusammen,

        mich beschäftigt ein eigentlich !sehr banales! Problem - ich behaupte trotzdem, das ist eine Frage an die Leute die einfach uns Eck denken können:
        Kalenderrechnung ist selten trivial.

        Ich führe für einen Kalender Berechnungen mit dem Ostertag durch:

        Funktion: "easter_date(Jahresangabe4Stellig)"

        die Funktion liefert einen Zeitstempel im UnixStyle zurück, also z.B.
        für 2016: 1459033200 --> in Realzeit also: 27.03.2016 - 00:00:00
        Wieso verwendest du eine Funktion, die einen POSIX-Timestamp zurückgibt, der in Sekunden gezählt wird, wenn du eigentlich einen Tag berechnen willst, und die Uhrzeit dir wurst ist?

        Die Funktion der Wahl für den ("weströmischen"|"katholischen") Ostersonntag ist easter_days(). Wenn man denn unbedingt PHP für sowas benutzen muss.

        Diese Funktion hat aber eine unangenehme Einschränkung: Sie gibt die Zahl der Tage nach dem 21. März an, anstatt (vernünftigererweise) die Tagesnummer im Jahr. Das lässt sich beheben, man muss aber bedenken, dass der 21. März nach dem eventuellen Schalttag im Februar kommt.

        PHP-Code:
        // get day of they year (1-based) for roman|catholic easter sunday
        function easterday($year) {
            
        $year = (int) $year;
            return 
        80 // jan 31 + feb 28 + mar 21
                
        + (int)!($year 0x03 || === $year 100 && !== $year 400// leap day
                
        easter_days($year); // + days after MAR/21st

        Für die Fanboys von DateTime:
        PHP-Code:
        class DateTimeWithEaster extends DateTime {
            
        // they are all the same:
            
        const Roman 0;
            const 
        Catholic 0;
            const 
        Western 0;
            const 
        Gregorian 0;

            
        // todo: implement these!
            
        const Julian 1;
            const 
        Orthodox 1;

            const 
        Orthodox_New_Calendrists 2;

            
        // set the DateTime to the Easter Sunday of the actual year
            
        function setEasterDate($mode self::Gregorian) {
                if (
        self::Gregorian !== $mode) {
                    throw new 
        Exception('... left as an exercise for the reader');
                }
                
        $year = (int) $this->format('Y');
                
        $daynum 80
                    
        + (int)!($year 0x03 || === $year 100 && !== $year 400// leap day
                    
        easter_days($year); // + days after MAR/21st

                // "year.daynum" is the PostGreSQL daynum format as DateTime:: knows it
                
        $this->modify(sprintf('%d.%03d'$year$daynum));
                return 
        $this;
            }

        Mit letzterer Variante kommst du relativ leicht zum Ostermontag:
        PHP-Code:
        $datum = new DateTimeWithEaster();
        $datum->setEasterDate();
        $datum->add(new DateInterval('P1D'));
        // oder:
        // $datum->modify('+1 day');
        // oder:
        // $datum->modify('next monday');
        // kapiert? 
        Bis jetzt keine Probleme.
        Ja, das denken die meisten.

        Wo ist hier der Fehler, wo die Regelmäßigkeit, was mache ich falsch?
        * Du hast die falsche Datums|Zeit-Einheit verwendet (Sekunde statt Tag),
        * Du hast nicht beachtet, dass bei Umrechnungen von Datums|Zeit-Einheiten so gut wie immer mit Unregelmäßigkeiten zu rechnen ist (hier Sommerzeit|Winterzeit).
        * Du hast Datums|Zeitberechnung für trivial ("banales! Problem") gehalten.

        Ergänzung: Ach so, die Ursachenforschung für deinen speziellen Fall hab ich noch vergessen. Die Umstellung von "Winter"- auf Sommerzeit erfolgt in unseren Landen seit längerem am letzten Sonntag im März. Dreimal darfst du raten, was passiert, wenn der Ostersonntag auf eben diesen Tag fällt (2016, 2027 bspw.).
        Wenn man die Wurst schräg anschneidet, hält sie länger, weil die Scheiben größer sind.

        Kommentar


        • #5
          Toller Beitrag!

          Zitat von fireweasel Beitrag anzeigen
          Für die Fanboys von DateTime:
          ein Nachschlag:
          PHP-Code:
          //create DateTime
          function create_easterDate($year) {
            return 
          date_create()->setDate($year,3,21+easter_days($year));

          Edit:
          Das Setzen einer Tageszahl jenseits des Realen gefällt mir genaugenommen auch nicht. Alternativ:
          PHP-Code:
          function create_easterDate($year) {
            return 
          date_create($year.'-3-21')->modify(easter_days($year).' Days');


          LG jspit
          PHP-Klassen auf github

          Kommentar


          • #6
            Zitat von jspit Beitrag anzeigen
            ...
            ein Nachschlag:
            PHP-Code:
            //create DateTime
            function create_easterDate($year) {
              return 
            date_create()->setDate($year,3,21+easter_days($year));

            Ja, das verlagert die umständlichen Berechnungen dahin, wo sie hingehören -- ins Innere des DateTime-Objekts und erspart das Umwandeln der Tagesnummer in ein "richtiges" Datum.

            Ich habe nur eine leichte Abneigung gegen diese Art der Datumsangabe wie in
            Code:
            ->setDate($year, $maerz, $Tag_gröszer_als_der_Maerz_Tage_hat);
            Aber das ist mein persönlicher Schwachpunkt, damit sollte ich nicht die Allgemeinheit belasten.

            Als Wiedergutmachung ein modifiziertes DateTime-Objekt, das ohne ->setEasterDate() auskommt:

            PHP-Code:
            class DateTimeWithEasterX extends DateTime {
                function 
            __construct(
                    
            $datetime 'now',
                    
            $timezone null
                
            ) {
                    if (
            preg_match(
                        
            '/\A(?=.*?easter(?:(?:sun)?day)?).*?\K[-+]?[0-9]{1,4}/i',
                        
            $datetime,
                        
            $h
                    
            )) {
                        
            parent::__construct('now'$timezone);
                        
            $this->setDate($h[0], 321 easter_days($h[0]));
                        
            $this->setTime(000);
                    }
                    else {
                        
            parent::__construct($datetime$timezone);
                    }
                }

            Das erzeugt direkt ein Datumsobjekt für den gewünschten Ostersonntag:

            PHP-Code:
            $easterdate = new DateTimeWithEasterX('easterday 2016');
            var_dump($easterdate);
            var_dump($easterdate->format('l')); // hoffentlich ein Sonntag 
            Wenn man die Wurst schräg anschneidet, hält sie länger, weil die Scheiben größer sind.

            Kommentar


            • #7
              Ich habe nur eine leichte Abneigung gegen diese Art der Datumsangabe wie in
              Dieses String-Geparse findest du besser?

              Da liefert aktuell etwa auch "easter monday 2016" den Ostersonntag.

              Ich würde auch nicht von DateTime erben, da das beliebig verstellt werden kann. Ab PHP 5.5 könnte man wahrscheinlich von DateTimeImmutable erben.

              (Das Interface hinter den beiden Klassen lässt sich übrigens nicht in eigenem Code implementieren: „PHP Fatal error: DateTimeInterface can't be implemented by user classes“. Solche hardgecodeten Sachen mag ich ja gar nicht.)

              Ich denke, ich würde so einen Code aber in eine Factory-Klassen packen, die DateTime-Instanzen oder DateTimeImmutable-Instanzen liefert.

              Gibt auch noch Carbon, das angeblich brauchbar ist: https://github.com/briannesbitt/Carbon
              PHP-Wissenssammlung Composer Awesome Awesomeness PHP: The Right Way @mermshaus

              Kommentar


              • #8
                Zitat von mermshaus Beitrag anzeigen
                Ich würde auch nicht von DateTime erben, da das beliebig verstellt werden kann.
                Ich verstehe nicht was du mit "verstellen" meinst. Das sich grundlegende Dinge in DateTime ändern, auf die eine Erweiterungsklasse baut?
                PHP-Klassen auf github

                Kommentar


                • #9
                  Man kann das Datum der Instanzen verstellen. Du kannst eine Instanz von DateTimeWithEasterX haben, die als Datum Weihnachten verwaltet.

                  Das ist ein wenig wie BorussiaDortmund extends Fußballverein; $bvb->setName('Schalke 04');.
                  PHP-Wissenssammlung Composer Awesome Awesomeness PHP: The Right Way @mermshaus

                  Kommentar


                  • #10
                    Nutze selber eine Klassenerweiterung und sehe noch nicht wo es Probleme geben könnte.
                    Meine Erweiterung für Ostern sieht wie folgt aus (create,format und Rest der Klasse fehlt!):
                    PHP-Code:
                    class dt extends DateTime{
                      
                      const 
                    EASTER_WEST CAL_EASTER_ALWAYS_GREGORIAN;
                      const 
                    EASTER_EAST CAL_EASTER_ALWAYS_JULIAN;  // orthodox

                     /*
                      * set Date to Eastern
                      */
                      
                    public function setEasterDate($flag self::EASTER_WEST){
                        
                    $year = (int)$this->format('Y');
                        if(
                    $flag == self::EASTER_WEST$this->setDate($year,3,21);
                        elseif( 
                    $flag == self::EASTER_EAST$this->setDate($year,4,3);
                        else return 
                    false;    
                        return 
                    $this->modify(easter_days($year$flag).' Days');
                      }

                    Test:
                    PHP-Code:
                    echo 'Ostern West | Ostern Ost<br>';
                    for(
                    $year=2000$year<2040$year++){
                      
                    $easterWest dt::create($year.'-1-1')->setEasterDate();
                      
                    $easterEast dt::create($year.'-1-1')->setEasterDate(dt::EASTER_EAST);
                      echo 
                    $easterWest->format('d.F Y').' | '.$easterEast->format('d.F Y').'<br>';

                    Ausgabe:
                    Code:
                    Ostern West | Ostern Ost
                    23.April 2000 | 30.April 2000
                    15.April 2001 | 15.April 2001
                    31.März 2002 | 05.Mai 2002
                    20.April 2003 | 27.April 2003
                    11.April 2004 | 11.April 2004
                    27.März 2005 | 01.Mai 2005
                    16.April 2006 | 23.April 2006
                    08.April 2007 | 08.April 2007
                    23.März 2008 | 27.April 2008
                    12.April 2009 | 19.April 2009
                    04.April 2010 | 04.April 2010
                    24.April 2011 | 24.April 2011
                    08.April 2012 | 15.April 2012
                    31.März 2013 | 05.Mai 2013
                    20.April 2014 | 20.April 2014
                    05.April 2015 | 12.April 2015
                    27.März 2016 | 01.Mai 2016
                    16.April 2017 | 16.April 2017
                    01.April 2018 | 08.April 2018
                    21.April 2019 | 28.April 2019
                    12.April 2020 | 19.April 2020
                    04.April 2021 | 02.Mai 2021
                    17.April 2022 | 24.April 2022
                    09.April 2023 | 16.April 2023
                    31.März 2024 | 05.Mai 2024
                    20.April 2025 | 20.April 2025
                    05.April 2026 | 12.April 2026
                    28.März 2027 | 02.Mai 2027
                    16.April 2028 | 16.April 2028
                    01.April 2029 | 08.April 2029
                    21.April 2030 | 28.April 2030
                    13.April 2031 | 13.April 2031
                    28.März 2032 | 02.Mai 2032
                    17.April 2033 | 24.April 2033
                    09.April 2034 | 09.April 2034
                    25.März 2035 | 29.April 2035
                    13.April 2036 | 20.April 2036
                    05.April 2037 | 05.April 2037
                    25.April 2038 | 25.April 2038
                    10.April 2039 | 17.April 2039
                    LG jspit
                    PHP-Klassen auf github

                    Kommentar


                    • #11
                      Oh, sorry, ich habe das falsch verstanden. Ups.

                      Jetzt ergibt das auch gleich viel mehr Sinn für mich. Hatte mich schon gewundert.

                      Ich dachte, die Klasse DateTimeWithEasterX sei explizit für Instanzen von Ostersonntagen gedacht. Das ergibt aber auch vom Code her schon keinen Sinn, weil der Konstruktor ja als Fallback auch noch den normalen DateTime-Konstruktor aufruft.

                      Da habe ich wohl den Klassennamen gesehen, falsch interpretiert und mich dann nicht mehr groß mit den Details aufgehalten…

                      Der Klassenname ist dann wohl doch nur so ein generisches DateTimeFoo, weil die Klasse halt irgendwie heißen muss.
                      PHP-Wissenssammlung Composer Awesome Awesomeness PHP: The Right Way @mermshaus

                      Kommentar


                      • #12
                        Noch 88 Tage bis Ostern ...

                        Zitat von mermshaus Beitrag anzeigen
                        Dieses String-Geparse findest du besser?
                        Um Himmels Willen, nein!
                        Das war nur als schlechte Parodie auf die Format-Parserei von DateTime gedacht.

                        Vermutlich ist es am sinnvollsten, die Erzeugung des Basis-Osterdatums als statische (Factory?[0])-Methode anzubauen, wenn man nichts anderes als diesen Ostersonntag benötigt. Für mehr bewegliche Feiertage auf anderer Basis scheint mir dein Ansatz vernünftiger.

                        PHP-Code:
                        class DateTimeFinalProposalForAnEasterSundayCreatorSuitableForSmallEnterprisesAndHomeOfficesButNotForLiturgicPurposesInTheEasternOrthodoxChurches extends DateTime {
                            static function 
                        createEasterDateForYear($year) {
                                
                        // todo: check limits for $year
                                
                        $edt = new DateTime();
                                
                        $edt->setDate($year321 easter_days($year));
                                
                        $edt->setTime(000); // 12:00:00 may be a better choice
                                
                        return $edt;
                            }

                        Da liefert aktuell etwa auch "easter monday 2016" den Ostersonntag.
                        Hoppala, dabei hab ich doch so einen "sophisticated"-ten Parser zusammengenagelt. Gerade wollte ich noch "next easter", "last easter", "first easter ever" usw. implementieren. Jetzt hast du mir den Spaß verdorben ...

                        Ich denke, ich würde so einen Code aber in eine Factory-Klassen packen, die DateTime-Instanzen oder DateTimeImmutable-Instanzen liefert.
                        So machen es die ICU-Holiday-Klassen (wenn ich das richtig verstanden habe) für den Ostersonntag und die "wichtigsten" davon abgeleiteten Festtage. Die haben sogar eine eigene Methode für den Pfannkuchendienstag. *mjamm* Irgendwann werden wir das über IntlCalendar sicher auch reinbekommen.

                        Gibt auch noch Carbon, das angeblich brauchbar ist: https://github.com/briannesbitt/Carbon
                        Hatte ich mir vor einiger Zeit mal angeschaut, scheint ganz interessant.

                        --
                        [0] Ostereierfabrik-Methode?
                        Wenn man die Wurst schräg anschneidet, hält sie länger, weil die Scheiben größer sind.

                        Kommentar


                        • #13
                          Zitat von mermshaus Beitrag anzeigen
                          Gibt auch noch Carbon, das angeblich brauchbar ist: https://github.com/briannesbitt/Carbon
                          Hab mal kurz drübergesehen. Hat so fast für jeden Fall eine Methode.
                          Was mir ins Auge stach:
                          Eine Klasse, die DateTime erweitert, sollte intern nicht den guten alten unix-timestamp benutzen :
                          PHP-Code:
                          //Test auf einem 32-bit-System !
                          $d = new carbon('2038-3-1');
                          $d2= new carbon('2038-5-1');
                          $hours $d->diffInHours($d2);
                          var_dump($hours);  //int(0) 
                          PHP-Klassen auf github

                          Kommentar


                          • #14
                            Interessante Info, würde ich dort gleich als Issue abstellen.
                            Debugging: Finde DEINE Fehler selbst! | Gegen Probleme beim E-Mail-Versand | Sicheres Passwort-Hashing | Includes niemals ohne __DIR__
                            PHP.de Wissenssammlung | Kein Support per PN

                            Kommentar


                            • #15
                              Oh Mann… Eine PHP-Klasse mit 2200+ Stars auf GitHub, in der etwas so Offensichtliches nicht beachtet wird. Manchmal falle ich echt vom Glauben ab.

                              Edit: Schön auch:

                              In 32-bit system the unix timestamp will overflow if the date goes beyond year 2038 and this method will return false.
                              - http://php.net/manual/en/datetime.ge...amp.php#114590

                              Ich kann das derzeit nicht verifizieren, aber weiter oben in der offiziellen Doku ist nur von einer int-Rückgabe die Rede…
                              PHP-Wissenssammlung Composer Awesome Awesomeness PHP: The Right Way @mermshaus

                              Kommentar

                              Lädt...
                              X