datum nach sekunden vor dem 1.1.1970 (ab den 1.1.1600)

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
KeyPusher
Beiträge: 52
Registriert: 04.10.2006 10:56

datum nach sekunden vor dem 1.1.1970 (ab den 1.1.1600)

Beitrag von KeyPusher »

vor kurzem gab es hier im forum mal zwei anfragen bezüglich umrechnung eines datum vor dem 1.1.1970 in sekunden. dazu hab ich mir ein paar gedanken gemacht und zwei proceduren geschrieben, die ein datum ausgehend vom 1.1.1600 in sekunden und wieder zurück rechnen können. das jahr 1600 hab ich deswegen gewählt, weil unser heutiger kalender erst am 15.10.1582 eingeführt wurde ich dieses datum ein bisschen "krumm" fand.

entweder ist in meinen routinen ein fehler oder der fehler liegt bei PB. als variable für die sekunden verwende ich quad und bei werte grösser 2^47 gibt es programmaufhänger. ist jetzt nicht ganz so schlimm, weil mit 2^47 sekunden kommt man schon etwas weiter als 4 millionen jahre ;-). deswegen hab ich auch nicht weiter nach dem problem gesucht. aber wenn jemand den fehler findet, wäre ich für eine info dankbar.

die beiden proceduren mit ein paar beispielen:

Code: Alles auswählen

OpenConsole()
;
; Die date-Structure muss nicht unbedingt definiert werde, nur wenn man diese auch
; verwenden möchte.
Structure date
    Jahr.l
    Monat.l
    Tag.l
    Stunde.l
    Minute.l
    Sekunde.l
    WTag.l
EndStructure

; #################################################################################
; DateToSek wandelt ein Datum in Sekunden seit dem 1.1.1600 0 Uhr um.
; Wenn das Datum mittels eines Pointers auf die Structure date übergeben wird,
; werden Date$ und Form$ ignoriert. 
; Wird das Datum per Date$ übergeben, muss in Form$ die reihen der Daten übergeben werden.
; Z.B.: Date$="18.08.1968 um 12 Uhr 25" : Form$="%TT%MM%JJ%SS%MI"
; Angegeben werden kann:
;   %JJ -> Jahr
;   %MM -> den Monat
;   %TT -> den Tag
;   %SS -> die Stunden
;   %MI -> Minuten
;   %SE -> Sekunden
; Werden Stunden, Minuten und Sekunden nicht angegeben, werden sie auf 0 gesetzt.
;
Procedure.q DateToSek(Date$,Form$,*Date=0)
    If *Date
        Jahr=PeekL(*Date)
        Monat=PeekL(*Date+4)
        Tag=PeekL(*Date+8)
        Stunde=PeekL(*Date+12)
        Minute=PeekL(*Date+16)
        Sekunde=PeekL(*Date+20)
    Else
        Stunde=0
        Minute=0
        Sekunde=0
        
        *Str.Character=@Date$
        Sp=0
        p=-2
        Repeat
            p=FindString(Form$,"%",p+3)
            If p=0 : Break : EndIf
            a$=Mid(Form$,p+1,2)
            While *Str\c<48 Or *Str\c>57 : If *Str\c=0 : Break 2 : EndIf : *Str+1 : Sp+1 : Wend
            p1=Sp
            While *Str\c>47 And *Str\c<58 : *Str+1 : Sp+1 : Wend
            Value=Val(Mid(Date$,p1+1,Sp-p1))
            Select a$
                Case "JJ" : Jahr=Value : If Jahr<1600 : Jahr+2000 : EndIf
                Case "MM" : Monat=Value
                Case "TT" : Tag=Value
                Case "SS" : Stunde=Value
                Case "MI" : Minute=Value
                Case "SE" : Sekunde=Value
            EndSelect
        ForEver
    EndIf

    Monat-1
    Tag-1
    
    If Jahr>1600
        For i=1600 To Jahr-1 Step 4
            If  ( i%4=0 And Not i%100=0 ) Or i%400=0
                SchaltTage+1
            EndIf
        Next i
    EndIf

    If (( Jahr%4=0 And Not Jahr%100=0 ) Or Jahr%400=0) And Monat>1
        SchaltTagJetzt=1
    Else
        SchaltTagJetzt=0
    EndIf

    Jahr-1600
    
    MTag=PeekW(?MonatsTage+(Monat*2))

    Sek.q=Jahr*365
    Sek=(Sek+SchaltTage+MTag+SchaltTagJetzt+Tag)*24
    Sek=(Sek+Stunde)*60
    Sek=(Sek+Minute)*60
    Sek+Sekunde
    ProcedureReturn Sek.q
    
    DataSection
      MonatsTage:
        Data.w 0,31,59,90,120,151,181,212,243,273,304,334,365
    EndDataSection
EndProcedure
; #################################################################################
; SekToDate wandelt Sekunden (ausgehen vom 1.1.1600 0 Uhr) zurück in ein Datum ähnlich der
; FormatDate() Function von PureBasic.
; Z.B.: SekToDate(11632854310,"%WTAG, den %TT.%MM.%JJJJ um %SS Uhr %MI und %SE Sekunden")
; wird "Sonntag, den 18.08.1968 um 12 Uhr 25 und 10 Sekunden" zurück geben.
; Wird zusätzlich ein Pointer auf eine date-Structure mit übergeben, wird das Datum dort
; gespeichert.
; In Form$ werden folgende Zeichen entsprechende Werte zurück liefern:"
;   %JJJJ -> 4 stellige Jahreszahl, z.B. 1968
;   %JJ   -> 2 stellige Jahreszahl, z.B. 68
;   %MM   -> Monat als Zahl 2 stellig
;   %MMM  -> Monat als abgekürztes Wort, z.B.: Aug
;   %MMMM -> Monat als Wort, z.B.: August
;   %TT   -> Tag als 2 stellige Zahl, z.B.: 18
;   %WTAG -> Wochentag, z.B.: Sonntag
;   %WT   -> Wochentag abgekürzt, z.B.: So
;   %SS   -> Stunden 2 stellig
;   %MI   -> Minuten 2 stellig
;   %SE   -> Sekunden 2 stellig
;
Procedure.s SekToDate(Sek.q,Form$,*Date=0)
    #TagSek=86400
    #JahrSek=365*#TagSek
    #SchaltJahrSek=#JahrSek+#TagSek
    
    Days=Sek/#TagSek
    Day=(Days+6)%7
    
    Jahr=1600
    Repeat
        If (( Jahr%4=0 And Not Jahr%100=0 ) Or Jahr%400=0)
            If Sek-#SchaltJahrSek>=0
                Jahr+1
                Sek-#SchaltJahrSek
            Else
                Break
            EndIf
        Else
            If Sek-#JahrSek>=0
                Jahr+1
                Sek-#JahrSek
            Else
                Break
            EndIf
        EndIf
    ForEver
    
    If (( Jahr%4=0 And Not Jahr%100=0 ) Or Jahr%400=0)
        SchaltJahr=1
    Else
        SchaltJahr=0
    EndIf
    
    Tage=Sek/#TagSek
    Zeit=Sek%#TagSek
    
    For i=1 To 12
        MTag=PeekW(?MonatsTageII+(i*2))
        If SchaltJahr And i>1 : MTag+1 : EndIf
        If MTag>Tage : Break : EndIf
        vorMTag=MTag
    Next i
    Monat=i
    Tag=Tage-vorMTag+1

    Stunde=Zeit/3600 : Zeit=Zeit%3600
    Minute=Zeit/60 : Sekunde=Zeit%60
    
    If *Date
        PokeL(*Date,Jahr)
        PokeL(*Date+4,Monat)
        PokeL(*Date+8,Tag)
        PokeL(*Date+12,Stunde)
        PokeL(*Date+16,Minute)
        PokeL(*Date+20,Sekunde)
        PokeL(*Date+24,Day)
    EndIf

    If Len(Form$)>3
        MonatNr=Monat-1
        Form$=ReplaceString(Form$,"%JJJJ",StrQ(Jahr))
        Form$=ReplaceString(Form$,"%JJ",Right(StrQ(Jahr),2))
        Form$=ReplaceString(Form$,"%MMMM",PeekS(?MonatStrings+MonatNr*10))
        Form$=ReplaceString(Form$,"%MMM",PeekS(?MonatStrings+MonatNr*10,3))
        Form$=ReplaceString(Form$,"%MM",RSet(StrQ(Monat),2,"0"))
        Form$=ReplaceString(Form$,"%TT",RSet(StrQ(Tag),2,"0"))
        Form$=ReplaceString(Form$,"%WTAG",PeekS(?WTagStrings+Day*11))
        Form$=ReplaceString(Form$,"%WT",PeekS(?WTagStrings+Day*11,2))
        Form$=ReplaceString(Form$,"%SS",RSet(StrQ(Stunde),2,"0"))
        Form$=ReplaceString(Form$,"%MI",RSet(StrQ(Minute),2,"0"))
        Form$=ReplaceString(Form$,"%SE",RSet(StrQ(Sekunde),2,"0"))
    EndIf
    
    ProcedureReturn Form$
    
    DataSection
      MonatsTageII:
        Data.w 0,31,59,90,120,151,181,212,243,273,304,334,365
      WTagStrings:
        Data.c 'S','o','n','n','t','a','g',0,0,0,0,'M','o','n','t','a','g',0,0,0,0,0
        Data.c 'D','i','e','n','s','t','a','g',0,0,0,'M','i','t','t','w','o','c','h',0,0,0
        Data.c 'D','o','n','n','e','r','s','t','a','g',0,'F','r','e','i','t','a','g',0,0,0,0
        Data.c 'S','a','m','s','t','a','g',0,0,0,0
      MonatStrings:
        Data.c 'J','a','n','u','a','r',0,0,0,0,'F','e','b','r','u','a','r',0,0,0
        Data.c 'M','ä','r','z',0,0,0,0,0,0,'A','p','r','i','l',0,0,0,0,0
        Data.c 'M','a','i',0,0,0,0,0,0,0,'J','u','n','i',0,0,0,0,0,0
        Data.c 'J','u','l','i',0,0,0,0,0,0,'A','u','g','u','s','t',0,0,0,0
        Data.c 'S','e','p','t','e','m','b','e','r',0,'O','k','t','o','b','e','r',0,0,0
        Data.c 'N','o','v','e','m','b','e','r',0,0,'D','e','z','e','m','b','e','r',0,0
    EndDataSection
EndProcedure
; #################################################################################


Sek.q=DateToSek(FormatDate("%dd.%mm.%yyyy %hh:%ii:%ss", Date()),"%TT%MM%JJ%SS%MI%SE")
;Sek.q=DateToSek("18.8.1968 12 Uhr 25 und 10 Sekunden","%TT%MM%JJ%SS%MI%SE")
PrintN("Jetziges Datum in Sekunden seit dem 01.01.1600 0 Uhr:")
PrintN(StrQ(Sek))
PrintN("")
PrintN("Und die Sekunden zurueck in ein lesbares Datum:")
PrintN(SekToDate(Sek,"%TT.%MM.%JJJJ  %SS:%MI:%SE"))
PrintN("")
PrintN("oder mal anders ...")
PrintN(SekToDate(Sek,"%WTAG, den %TT. %MMMM %JJJJ um %SS Uhr %MI Minuten und %SE Sekunden",Datum.date))
PrintN("")
PrintN("Und das ganze noch bei bedarf aus der Structur date ausgelesen:")
PrintN("Jahr: "+StrQ(Datum\Jahr))
PrintN("Monat: "+StrQ(Datum\Monat))
PrintN("Tag: "+StrQ(Datum\Tag))
PrintN("Stunde: "+StrQ(Datum\Stunde))
PrintN("Minute: "+StrQ(Datum\Minute))
PrintN("Sekunde: "+StrQ(Datum\Sekunde))
PrintN("Wochentag: "+StrQ(Datum\WTag))
PrintN("")
PrintN("Uebergabe des Datums '18.08.1968 12:05:37' per Variable und Ausgabe aller moeglichen Formate ...")
Datum.date\Jahr=1968
Datum.date\Monat=8
Datum.date\Tag=18
Datum.date\Stunde=12
Datum.date\Minute=05
Datum.date\Sekunde=37
Sek.q=DateToSek("","",Datum.date)
Print("Jahreszahen: ")
PrintN(SekToDate(Sek,"%JJJJ und %JJ"))
Print("Monat: ")
PrintN(SekToDate(Sek,"%MM und %MMM und %MMMM"))
Print("Tag und Wochentag: ")
PrintN(SekToDate(Sek,"%WT oder %WTAG, den %TT."))
Print("Uhrzeit: ")
PrintN(SekToDate(Sek,"%SS Uhr %MI Minuten und %SE Sekunden"))


Input()
CloseConsole()