Date64 - Unixtime 64bit

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.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Date64 - Unixtime 64bit

Beitrag von ts-soft »

NicTheQuick hat geschrieben:Das ist aber Unsinn. Natürlich weiß Linux, in welcher Zeitzone es sich befindet:
Ja, aber nur zur Anzeige, intern wird immer in UTC gerechnet und wenn Linux alleine installiert ist, wird auch UTC ins BIOS
eingetragen, während bei Windows normalerweise die Lokalzeit eingetragen wird.
xXRobo_CubeXx hat geschrieben:Da kennt sich einer sehr gut mit Linux aus, nicht wahr Thomas ? :mrgreen:
Trollen?
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Date64 - Unixtime 64bit

Beitrag von mk-soft »

Hi,

Bei Mac und Linux wurde noch nicht die richtige lokale Urzeit zurück gegeben.
Verwende jetzt "tm_gmtoff" für die Berechnung der lokalen Urzeit. Die unterschiede in der Struktur für Linux 32/64Bit ist etwas verwirrend.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Date64 - Unixtime 64bit

Beitrag von Sicro »

Bei den vorherigen Codes habe ich den Fehler gemacht, dass ich bei "Day64()" usw. "localtime_r_()" nochmal über "Date.q" laufen gelassen habe, wodurch von dem lokalem Datum das lokale Datum berechnet wurde, was natürlich Schwachsinn ist. Nun "missbrauche" ich zum Zerteilen des Datums "gmtime_r_()", das im Gegensatz zu "localtime_r_()" keine Anpassungen durchführt, sondern nur das Datum teilt.

Neu: LocalDateAsUTC64()

Bitte auch nochmal unter 32- und 64-Bit MacOS testen.

@mk-soft: Werde mich darüber informieren, danke.

Code: Alles auswählen

DeclareModule Date64
  Declare.q Date64(Year.i = -1, Month.i = 1, Day.i = 1, Hour.i = 0, Minute.i = 0, Second.i = 0)
  Declare.q LocalDateAsUTC64()
  Declare.i Year64(Date.q)
  Declare.i Month64(Date.q)
  Declare.i Day64(Date.q)
  Declare.i Hour64(Date.q)
  Declare.i Minute64(Date.q)
  Declare.i Second64(Date.q)
  Declare.i DayOfWeek64(Date.q)
  Declare.i DayOfYear64(Date.q)
  Declare.q AddDate64(Date.q, Type.i, Value.i)
  Declare.s FormatDate64(Mask.s, Date.q)
  Declare.q ParseDate64(Mask.s, Date.s)
EndDeclareModule

Module Date64
  
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux Or #PB_Compiler_OS = #PB_OS_MacOS
    ImportC ""
      gmtime_r(time.i, result.i)
    EndImport
  CompilerEndIf
 
  CompilerIf #PB_Compiler_OS = #PB_OS_MacOS And #PB_Compiler_Processor = #PB_Processor_x86
    CompilerError "32-Bit not supported on MacOS"
  CompilerEndIf
 
  EnableExplicit
 
  ; == Windows ==
  ; >> Minimum: 01.01. 1601 00:00:00
  ; >> Maximum: 31.12.30827 23:59:59
 
  ; == Linux ==
  ; 32-Bit:
  ; >> Minimum: 01.01.1902 00:00:00
  ; >> Maximum: 18.01.2038 23:59:59
  ; 64-Bit:
  ; >> Minimum: 01.01.     0000 00:00:00
  ; >> Maximum: 31.12.999999999 23:59:59
 
  ; == MacOS ==
  ; wie bei Linux?
 
  #SecondsInOneHour = 60 * 60
  #SecondsInOneDay  = #SecondsInOneHour * 24
 
  #HundredNanosecondsInOneSecond               = 10000000
  #HundredNanosecondsFrom_1Jan1601_To_1Jan1970 = 116444736000000000
 
  CompilerIf #PB_Compiler_OS <> #PB_OS_Windows
    If Not Defined(tm, #PB_Structure)
      Structure tm Align #PB_Structure_AlignC
        tm_sec.l    ; 0 bis 59 oder bis 60 bei Schaltsekunde
        tm_min.l    ; 0 bis 59
        tm_hour.l   ; 0 bis 23
        tm_mday.l   ; Tag des Monats: 1 bis 31
        tm_mon.l    ; Monat: 0 bis 11 (Monate seit Januar)
        tm_year.l   ; Anzahl der Jahre seit dem Jahr 1900
        tm_wday.l   ; Wochentag: 0 bis 6, 0 = Sonntag
        tm_yday.l   ; Tage seit Jahresanfang: 0 bis 365 (365 ist also 366, da nach 1. Januar gezählt wird)
        tm_isdst.l  ; Ist Sommerzeit? tm_isdst > 0 = Ja
        ;                             tm_isdst = 0 = Nein
        ;                             tm_isdst < 0 = Unbekannt
        *tm_zone    ; Abkürzungsname der Zeitzone
        tm_gmtoff.l ; Offset von UTC in Sekunden
      EndStructure
    EndIf
  CompilerEndIf
 
  Procedure.i IsLeapYear(Year)
    If Year < 1600
      ; vor dem Jahr 1600 sind alle Jahre Schaltjahre, die durch 4 restlos teilbar sind
      ProcedureReturn Bool(Year % 4 = 0)
    Else
      ; ab dem Jahr 1600 sind alle Jahre Schaltjahre, die folgende Bedingungen erfüllen:
      ; => restlos durch 4 teilbar, jedoch nicht restlos durch 100 teilbar
      ; => restlos durch 400 teilbar
      ProcedureReturn Bool((Year % 4 = 0 And Year % 100 <> 0) Or Year % 400 = 0)
    EndIf
  EndProcedure
 
  Procedure.i DaysInMonth(Year, Month)
    While Month > 12
      Month - 12
    Wend
   
    Select Month
      Case 1, 3, 5, 7, 8, 10, 12: ProcedureReturn 31
      Case 4, 6, 9, 11:           ProcedureReturn 30
      Case 2:                     ProcedureReturn 28 + IsLeapYear(Year) ; Februar hat im Schaltjahr ein Tag mehr
    EndSelect
  EndProcedure
 
  Procedure.q Date64(Year.i = -1, Month.i = 1, Day.i = 1, Hour.i = 0, Minute.i = 0, Second.i = 0)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
      Protected.FILETIME   ft
     
      If Year > -1 ; Gültiges Datum
        ; Angaben evtl. korrigieren
       
        ; >>> Positive Angaben
       
        While Second > 59
          Minute + 1
          Second - 60
        Wend
       
        While Minute > 59
          Hour   + 1
          Minute - 60
        Wend
       
        While Hour > 23
          Day  + 1
          Hour - 24
        Wend
       
        While Day > DaysInMonth(Year, Month)
          Day - DaysInMonth(Year, Month)
          Month + 1
        Wend
       
        While Month > 12
          Year  + 1
          Month - 12
        Wend
       
        ; >>> Negative Angaben
       
        While Second < 0
          Minute - 1
          Second + 59
        Wend
       
        While Minute < 0
          Hour   - 1
          Minute + 59
        Wend
       
        While Hour < 0
          Day  - 1
          Hour + 23
        Wend
       
        While Day < 0
          Day + DaysInMonth(Year, Month)
          Month - 1
        Wend
       
        While Month < 0
          Year  - 1
          Month + 12
        Wend
       
        st\wYear   = Year
        st\wMonth  = Month
        st\wDay    = Day
        st\wHour   = Hour
        st\wMinute = Minute
        st\wSecond = Second
        
        SystemTimeToFileTime_(@st, @ft)
        
        ; Zeit in Sekunden umrechnen
        ProcedureReturn (PeekQ(@ft) - #HundredNanosecondsFrom_1Jan1601_To_1Jan1970) / #HundredNanosecondsInOneSecond
      Else ; Kein gültiges Datum. Systemzeit wird ermittelt
        GetLocalTime_(@st)
        SystemTimeToFileTime_(@st, @ft)
       
        ; Zeit in Sekunden umrechnen
        ProcedureReturn (PeekQ(@ft) - #HundredNanosecondsFrom_1Jan1601_To_1Jan1970) / #HundredNanosecondsInOneSecond
      EndIf
    CompilerElse
      Protected.tm tm
      Protected.q time
      Protected *Memory_localtime
     
      If Year > -1 ; Gültiges Datum
        tm\tm_year  = Year - 1900 ; Jahre ab 1900
        tm\tm_mon   = Month - 1   ; Monate ab Januar
        tm\tm_mday  = Day
        tm\tm_hour  = Hour
        tm\tm_min   = Minute
        tm\tm_sec   = Second
        tm\tm_isdst = -1
        
        ; mktime korrigiert die Angaben selber und liefert bereits Sekunden
        ProcedureReturn mktime_(@tm) + #SecondsInOneHour ; Rückgabewert von mktime ist eine Stunde zu wenig
      Else ; Kein gültiges Datum. Systemzeit wird ermittelt
        time = time_(0)
        If time > -1
          *Memory_localtime = AllocateMemory(SizeOf(tm))
          If *Memory_localtime
            localtime_r_(@time, *Memory_localtime) ; Per Memory ist es thread-sicher
            time = mktime_(*Memory_localtime) + #SecondsInOneHour ; Rückgabewert von mktime ist eine Stunde zu wenig
            FreeMemory(*Memory_localtime)
            If time > -1
              ProcedureReturn time
            EndIf
          EndIf
        EndIf
      EndIf
    CompilerEndIf
  EndProcedure
  
  Procedure.q LocalDateAsUTC64()
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
      Protected.FILETIME   ft
      
      GetSystemTime_(@st)
      SystemTimeToFileTime_(@st, @ft)
      
      ; Zeit in Sekunden umrechnen
      ProcedureReturn (PeekQ(@ft) - #HundredNanosecondsFrom_1Jan1601_To_1Jan1970) / #HundredNanosecondsInOneSecond
    CompilerElse
      ProcedureReturn time_(0)
    CompilerEndIf
  EndProcedure
 
  Procedure.i Year64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wYear
    CompilerElse
      Protected.tm *Memory_TimeStruc
      Protected.i  Year
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc)
        Year = *Memory_TimeStruc\tm_year
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn Year + 1900
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i Month64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wMonth
    CompilerElse
      Protected.tm *Memory_TimeStruc
      Protected.i  Month
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc)
        Month = *Memory_TimeStruc\tm_mon
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn Month + 1
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i Day64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wDay
    CompilerElse
      Protected.tm *Memory_TimeStruc
      Protected.i  Day
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc)
        Day = *Memory_TimeStruc\tm_mday
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn Day
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i Hour64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wHour
    CompilerElse
      Protected.tm *Memory_TimeStruc
      Protected.i  Hour
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc)
        Hour = *Memory_TimeStruc\tm_hour
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn Hour
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i Minute64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wMinute
    CompilerElse
      Protected.tm *Memory_TimeStruc
      Protected.i  Minute
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc)
        Minute = *Memory_TimeStruc\tm_min
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn Minute
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i Second64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wSecond
    CompilerElse
      Protected.tm *Memory_TimeStruc
      Protected.i Second
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc)
        Second = *Memory_TimeStruc\tm_sec
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn Second
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i DayOfWeek64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wDayOfWeek
    CompilerElse
      Protected.tm *Memory_TimeStruc
      Protected.i  DayOfWeek
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc)
        DayOfWeek = *Memory_TimeStruc\tm_wday
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn DayOfWeek
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i DayOfYear64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.q TempDate
     
      TempDate = Date64(Year64(Date))
     
      ProcedureReturn (Date - TempDate) / #SecondsInOneDay + 1
    CompilerElse
      Protected.tm *Memory_TimeStruc
      Protected.i  DayOfYear
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc)
        DayOfYear = *Memory_TimeStruc\tm_yday
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn DayOfYear + 1
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.q AddDate64(Date.q, Type.i, Value.i)
    Protected.i Day, Month, Year
   
    Select Type
      Case #PB_Date_Year:   ProcedureReturn Date64(Year64(Date) + Value, Month64(Date), Day64(Date), Hour64(Date), Minute64(Date), Second64(Date))
      Case #PB_Date_Month
        Day   = Day64(Date)
        Month = Month64(Date) + Value
        Year  = Year64(Date)
       
        If Day > DaysInMonth(Year, Month)
          ; mktime_() korrigiert das zwar auch, wendet dabei aber eine andere Methode als PB-AddDate() an:
          ; >> mktime_():    31.03.2004 => 1 Monat später => 01.05.2004
          ; >> PB-AddDate(): 31.03.2004 => 1 Monat später => 30.04.2004
         
          ; setzte Tag auf das Maximum des neuen Monats
          Day = DaysInMonth(Year, Month)
        EndIf
       
        ProcedureReturn Date64(Year64(Date), Month, Day, Hour64(Date), Minute64(Date), Second64(Date))
      Case #PB_Date_Week:   ProcedureReturn Date64(Year64(Date), Month64(Date), Day64(Date) + Value * 7, Hour64(Date), Minute64(Date), Second64(Date))
      Case #PB_Date_Day:    ProcedureReturn Date64(Year64(Date), Month64(Date), Day64(Date) + Value, Hour64(Date), Minute64(Date), Second64(Date))
      Case #PB_Date_Hour:   ProcedureReturn Date64(Year64(Date), Month64(Date), Day64(Date), Hour64(Date) + Value, Minute64(Date), Second64(Date))
      Case #PB_Date_Minute: ProcedureReturn Date64(Year64(Date), Month64(Date), Day64(Date), Hour64(Date), Minute64(Date) + Value, Second64(Date))
      Case #PB_Date_Second: ProcedureReturn Date64(Year64(Date), Month64(Date), Day64(Date), Hour64(Date), Minute64(Date), Second64(Date) + Value)
    EndSelect
  EndProcedure
 
  Procedure.s FormatDate64(Mask.s, Date.q)
    Protected.s Retval
   
    Retval = ReplaceString(Mask,   "%yyyy", RSet(Str(Year64(Date)),           4, "0"))
    Retval = ReplaceString(Retval, "%yy",   RSet(Right(Str(Year64(Date)), 2), 2, "0"))
    Retval = ReplaceString(Retval, "%mm",   RSet(Str(Month64(Date)),          2, "0"))
    Retval = ReplaceString(Retval, "%dd",   RSet(Str(Day64(Date)),            2, "0"))
    Retval = ReplaceString(Retval, "%hh",   RSet(Str(Hour64(Date)),           2, "0"))
    Retval = ReplaceString(Retval, "%ii",   RSet(Str(Minute64(Date)),         2, "0"))
    Retval = ReplaceString(Retval, "%ss",   RSet(Str(Second64(Date)),         2, "0"))
   
    ProcedureReturn Retval
  EndProcedure
 
  Procedure.q ParseDate64(Mask.s, Date.s)
    Protected.i i, DatePos = 1, IsVariableFound, Year, Month = 1, Day = 1, Hour, Minute, Second
    Protected.s MaskChar, DateChar
   
    For i = 1 To Len(Mask)
      MaskChar = Mid(Mask, i, 1)
      DateChar = Mid(Date, DatePos, 1)
     
      If MaskChar <> DateChar
        If MaskChar = "%" ; Vielleicht eine Variable?
          If Mid(Mask, i, 5) = "%yyyy"
            IsVariableFound = #True
            Year = Val(Mid(Date, DatePos, 4))
            DatePos + 4 ; Die 4 Nummern der Jahreszahl überspringen
            i + 4       ; Die 5 Zeichen der Variable "%yyyy" überspringen
            Continue
          ElseIf Mid(Mask, i, 3) = "%yy"
            IsVariableFound = #True
            Year = Val(Mid(Date, DatePos, 2))
            DatePos + 2 ; Die 2 Nummern der Jahreszahl überspringen
            i + 2       ; Die 3 Zeichen der Variable "%yy" überspringen
            Continue
          EndIf
         
          If Mid(Mask, i, 3) = "%mm"
            IsVariableFound = #True
            Month = Val(Mid(Date, DatePos, 2))
            DatePos + 2 ; Die 2 Nummern der Monatszahl überspringen
            i + 2       ; Die 3 Zeichen der Variable "%mm" überspringen
            Continue
          EndIf
         
          If Mid(Mask, i, 3) = "%dd"
            IsVariableFound = #True
            Day = Val(Mid(Date, DatePos, 2))
            DatePos + 2 ; Die 2 Nummern der Tageszahl überspringen
            i + 2       ; Die 3 Zeichen der Variable "%dd" überspringen
            Continue
          EndIf
         
          If Mid(Mask, i, 3) = "%hh"
            IsVariableFound = #True
            Hour = Val(Mid(Date, DatePos, 2))
            DatePos + 2 ; Die 2 Nummern der Stundenzahl überspringen
            i + 2       ; Die 3 Zeichen der Variable "%hh" überspringen
            Continue
          EndIf
         
          If Mid(Mask, i, 3) = "%ii"
            IsVariableFound = #True
            Minute = Val(Mid(Date, DatePos, 2))
            DatePos + 2 ; Die 2 Nummern der Minutenzahl überspringen
            i + 2       ; Die 3 Zeichen der Variable "%ii" überspringen
            Continue
          EndIf
         
          If Mid(Mask, i, 3) = "%ss"
            IsVariableFound = #True
            Second = Val(Mid(Date, DatePos, 2))
            DatePos + 2 ; Die 2 Nummern der Sekundenzahl überspringen
            i + 2       ; Die 3 Zeichen der Variable "%ss" überspringen
            Continue
          EndIf
         
          If Not IsVariableFound
            ProcedureReturn 0
          EndIf
        Else
          ProcedureReturn 0
        EndIf
      EndIf
     
      DatePos + 1
    Next
   
    ProcedureReturn Date64(Year, Month, Day, Hour, Minute, Second)
  EndProcedure
EndModule

CompilerIf #PB_Compiler_IsMainFile
  ;-Test
 
  UseModule Date64
  
  Debug "Kleiner Kompatibilitäts-Test - Fehler:"
  For Year = 1970 To 2038
    d1 = Date(Year, 1, 1, 0, 0, 0)
    d2 = Date64(Year, 1, 1, 0, 0, 0)
    
    If d1 <> d2
      Debug d1
      Debug d2
      Debug ""
    EndIf
    
    d1$ = FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", d1)
    d2$ = FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", d2)
    If d1$ <> d2$
      Debug d1$
      Debug d2$
      Debug ""
    EndIf
  Next
  
  Debug "------------------------"
  Debug "DayOfWeek --------------"
  Debug DayOfWeek(Date())
  Debug DayOfWeek64(Date64())
  
  Debug "DayOfYear --------------"
  Debug DayOfYear(Date())
  Debug DayOfYear64(Date64())
  
  Debug "------------------------"
  Debug "Date(1600,1,1,0,0,0):   " + FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date(1600,1,1,0,0,0))
  Debug "Date64(2300,1,1,0,0,0): " + FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64(2300,1,1,0,0,0))
  Debug "Date(1971,8,20,0,0,0):  " + FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date(1971,8,20,0,0,0))
  Debug "Date64(1971,8,20):      " + FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64(1971,8,20))
  
  Debug "Aktuelles Datum --------"
  Debug FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date())
  Debug FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64())
  
  Debug "Aktuelles UTC-Datum ----"
  Debug FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", LocalDateAsUTC64())
  
  Debug "------------------------"
  a = Date64(2000, 1, 2, 11, 22, 33)
  Debug "Date64(2000, 1, 2, 11, 22, 33) => Year64(): "   + Year64(a)
  Debug "Date64(2000, 1, 2, 11, 22, 33) => Month64(): "  + Month64(a)
  Debug "Date64(2000, 1, 2, 11, 22, 33) => Day64(): "    + Day64(a)
  Debug "Date64(2000, 1, 2, 11, 22, 33) => Hour64(): "   + Hour64(a)
  Debug "Date64(2000, 1, 2, 11, 22, 33) => Minute64(): " + Minute64(a)
  Debug "Date64(2000, 1, 2, 11, 22, 33) => Second64(): " + Second64(a)
  
  Debug "Aktuelles UTC-Datum ----"
  a = LocalDateAsUTC64()
  Debug FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", a)
  
  Debug "UTC plus eine Stunde ---"
  a = AddDate64(a, #PB_Date_Hour, 1)
  Debug FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", a)
CompilerEndIf
Zuletzt geändert von Sicro am 21.12.2015 00:08, insgesamt 3-mal geändert.
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Date64 - Unixtime 64bit

Beitrag von mk-soft »

In moment gebe ich die Zeit als UTC zurück. Für Windows muss das noch angepasst werden.

Mac und Linux können den gleichen Code verwenden.
komischer weise muss ich nur bei der Sommer eine Anpassung durchführen.

P.S.
Wie es aussieht passt Dein Code :allright:

Mac und Linux können ein Code sein.

P.S.2
das mit #SecondsInOneHour gefällt mir irgend wie nicht. Wie sieht es mit einer anderen Zeitzone aus.

P.S.3
Muss es unbedingt kompatibel sein, oder sagt man der Rückgabewert es ist immer UTC
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Date64 - Unixtime 64bit

Beitrag von Sicro »

mk-soft hat geschrieben:komischer weise muss ich nur bei der Sommer eine Anpassung durchführen.
Ich habe "tm\tm_isdst = -1" hinzugefügt, wie sieht es nun aus?
mk-soft hat geschrieben:Mac und Linux können ein Code sein.
Ok, doppelter Code ist raus.
mk-soft hat geschrieben:das mit #SecondsInOneHour gefällt mir irgend wie nicht. Wie sieht es mit einer anderen Zeitzone aus.
Ja, gefällt mir auch nicht. Eine andere Zeitzone verursacht sicherlich falsche Werte. Das werde ich mal nachprüfen.
mk-soft hat geschrieben:Muss es unbedingt kompatibel sein, oder sagt man der Rückgabewert es ist immer UTC
Sehe ich als sehr wichtig an, weil so bestehende Datensätze weiterverwendet werden können.
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Date64 - Unixtime 64bit

Beitrag von mk-soft »

Deine Strucktur für "TM" ist noch nicht angepasst.
Siehe ersten Beitrag
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Date64 - Unixtime 64bit

Beitrag von mk-soft »

Update v2.02
- Windows Ok
- Mac und Linux Ok (99%)
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Date64 - Unixtime 64bit

Beitrag von Kiffi »

SQLite hat übrigens auch ganz nette Datums/Uhrzeit - Funktionalitäten:

Code: Alles auswählen

UseSQLiteDatabase()
DB = OpenDatabase(#PB_Any, ":memory:", "", "", #PB_Database_SQLite)
DatabaseQuery(DB, "SELECT strftime('%s','now') - strftime('%s','0000-12-24 00:00:00')")
NextDatabaseRow(DB)
Debug "Jesus wäre jetzt " + GetDatabaseString(DB, 0) + " Sekunden alt."
<g,d&r>
Hygge
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Date64 - Unixtime 64bit

Beitrag von Sicro »

@Kiffi: Ja, das ist auch eine Möglichkeit. Wenn die Größe der Programmdatei keine Rolle spielt oder die Datenbank-Funktionen bereits im Programm verwendet werden, kann man natürlich auch zu dieser Lösung greifen.
mk-soft hat geschrieben:Deine Strucktur für "TM" ist noch nicht angepasst.
Siehe ersten Beitrag
Habe ich nicht gemerkt, dass du den Code in deinem erstem Beitrag ausgetauscht hast. Mit der angepassten Struktur erhalte ich nun korrekte Werte; zuvor war es glaube ich immer Null. Super! :allright:
Das unschöne "#SecondsInOneHour" ist somit weg.

Im aktuellen Stand des Codes gibt es komischerweise manchmal im Monat "März" und einmal im April eine Abweichung von einer Stunde:

Code: Alles auswählen

Kleiner Kompatibilitäts-Test - Fehler:
323834400
323838000

1980.04.06 02:00:00
1980.04.06 03:00:00

386128800
386132400

1982.03.28 02:00:00
1982.03.28 03:00:00

417578400
417582000

1983.03.27 02:00:00
1983.03.27 03:00:00

449028000
449031600

1984.03.25 02:00:00
1984.03.25 03:00:00

575431200
575434800

1988.03.27 02:00:00
1988.03.27 03:00:00

606880800
606884400

1989.03.26 02:00:00
1989.03.26 03:00:00

638330400
638334000

1990.03.25 02:00:00
1990.03.25 03:00:00

733284000
733287600

1993.03.28 02:00:00
1993.03.28 03:00:00

764733600
764737200

1994.03.27 02:00:00
1994.03.27 03:00:00

796183200
796186800

1995.03.26 02:00:00
1995.03.26 03:00:00

922586400
922590000

1999.03.28 02:00:00
1999.03.28 03:00:00

954036000
954039600

2000.03.26 02:00:00
2000.03.26 03:00:00

985485600
985489200

2001.03.25 02:00:00
2001.03.25 03:00:00

1080439200
1080442800

2004.03.28 02:00:00
2004.03.28 03:00:00

1111888800
1111892400

2005.03.27 02:00:00
2005.03.27 03:00:00

1143338400
1143342000

2006.03.26 02:00:00
2006.03.26 03:00:00

1174788000
1174791600

2007.03.25 02:00:00
2007.03.25 03:00:00

1269741600
1269745200

2010.03.28 02:00:00
2010.03.28 03:00:00

1301191200
1301194800

2011.03.27 02:00:00
2011.03.27 03:00:00

1332640800
1332644400

2012.03.25 02:00:00
2012.03.25 03:00:00

1459044000
1459047600

2016.03.27 02:00:00
2016.03.27 03:00:00

1490493600
1490497200

2017.03.26 02:00:00
2017.03.26 03:00:00

1521943200
1521946800

2018.03.25 02:00:00
2018.03.25 03:00:00

1616896800
1616900400

2021.03.28 02:00:00
2021.03.28 03:00:00

1648346400
1648350000

2022.03.27 02:00:00
2022.03.27 03:00:00

1679796000
1679799600

2023.03.26 02:00:00
2023.03.26 03:00:00

1806199200
1806202800

2027.03.28 02:00:00
2027.03.28 03:00:00

1837648800
1837652400

2028.03.26 02:00:00
2028.03.26 03:00:00

1869098400
1869102000

2029.03.25 02:00:00
2029.03.25 03:00:00

1964052000
1964055600

2032.03.28 02:00:00
2032.03.28 03:00:00

1995501600
1995505200

2033.03.27 02:00:00
2033.03.27 03:00:00

2026951200
2026954800

2034.03.26 02:00:00
2034.03.26 03:00:00

2058400800
2058404400

2035.03.25 02:00:00
2035.03.25 03:00:00
Hier der aktuelle Code:

Code: Alles auswählen

DeclareModule Date64
  Declare.i IsLeapYear(Year.i)
  Declare.i DaysInMonth(Year.i, Month.i)
  Declare.q Date64(Year.i = -1, Month.i = 1, Day.i = 1, Hour.i = 0, Minute.i = 0, Second.i = 0)
  Declare.q LocalDateAsUTC64()
  Declare.i Year64(Date.q)
  Declare.i Month64(Date.q)
  Declare.i Day64(Date.q)
  Declare.i Hour64(Date.q)
  Declare.i Minute64(Date.q)
  Declare.i Second64(Date.q)
  Declare.i DayOfWeek64(Date.q)
  Declare.i DayOfYear64(Date.q)
  Declare.q AddDate64(Date.q, Type.i, Value.i)
  Declare.s FormatDate64(Mask.s, Date.q)
  Declare.q ParseDate64(Mask.s, Date.s)
EndDeclareModule

Module Date64
 
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux Or #PB_Compiler_OS = #PB_OS_MacOS
    ImportC ""
      gmtime_r(time.i, result.i)
    EndImport
  CompilerEndIf
 
  CompilerIf #PB_Compiler_OS = #PB_OS_MacOS And #PB_Compiler_Processor = #PB_Processor_x86
    CompilerError "32-Bit not supported on MacOS"
  CompilerEndIf
 
  EnableExplicit
 
  ; == Windows ==
  ; >> Minimum: 01.01. 1601 00:00:00
  ; >> Maximum: 31.12.30827 23:59:59
 
  ; == Linux ==
  ; 32-Bit:
  ; >> Minimum: 01.01.1902 00:00:00
  ; >> Maximum: 18.01.2038 23:59:59
  ; 64-Bit:
  ; >> Minimum: 01.01.     0000 00:00:00
  ; >> Maximum: 31.12.999999999 23:59:59
 
  ; == MacOS ==
  ; wie bei Linux?
 
  #SecondsInOneHour = 60 * 60
  #SecondsInOneDay  = #SecondsInOneHour * 24
 
  #HundredNanosecondsInOneSecond               = 10000000
  #HundredNanosecondsFrom_1Jan1601_To_1Jan1970 = 116444736000000000
 
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Linux
      If Not Defined(tm, #PB_Structure)
        Structure tm Align #PB_Structure_AlignC
          tm_sec.l    ; 0 bis 59 oder bis 60 bei Schaltsekunde
          tm_min.l    ; 0 bis 59
          tm_hour.l   ; 0 bis 23
          tm_mday.l   ; Tag des Monats: 1 bis 31
          tm_mon.l    ; Monat: 0 bis 11 (Monate seit Januar)
          tm_year.l   ; Anzahl der Jahre seit dem Jahr 1900
          tm_wday.l   ; Wochentag: 0 bis 6, 0 = Sonntag
          tm_yday.l   ; Tage seit Jahresanfang: 0 bis 365 (365 ist also 366, da nach 1. Januar gezählt wird)
          tm_isdst.l  ; Ist Sommerzeit? tm_isdst > 0 = Ja
          ;                             tm_isdst = 0 = Nein
          ;                             tm_isdst < 0 = Unbekannt
          CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
            tm_gmtoff.l ; Offset von UTC in Sekunden
            *tm_zone    ; Abkürzungsname der Zeitzone
          CompilerElse
            tm_zone.l   ; Abkürzungsname der Zeitzone
            tm_gmtoff.l ; Offset von UTC in Sekunden
            *tm_zone64  ; ??? Abkürzungsname der Zeitzone
          CompilerEndIf
         
        EndStructure
      EndIf
    CompilerCase #PB_OS_MacOS
      If Not Defined(tm, #PB_Structure)
        Structure tm Align #PB_Structure_AlignC
          tm_sec.l    ; 0 bis 59 oder bis 60 bei Schaltsekunde
          tm_min.l    ; 0 bis 59
          tm_hour.l   ; 0 bis 23
          tm_mday.l   ; Tag des Monats: 1 bis 31
          tm_mon.l    ; Monat: 0 bis 11 (Monate seit Januar)
          tm_year.l   ; Anzahl der Jahre seit dem Jahr 1900
          tm_wday.l   ; Wochentag: 0 bis 6, 0 = Sonntag
          tm_yday.l   ; Tage seit Jahresanfang: 0 bis 365 (365 ist also 366, da nach 1. Januar gezählt wird)
          tm_isdst.l  ; Ist Sommerzeit? tm_isdst > 0 = Ja
          ;                             tm_isdst = 0 = Nein
          ;                             tm_isdst < 0 = Unbekannt
          tm_zone.l   ; Abkürzungsname der Zeitzone (Auch bei 64bit ein 32bit Wert)
          tm_gmtoff.l ; Offset von UTC in Sekunden
          *tm_zone64  ; ??? Abkürzungsname der Zeitzone
        EndStructure
      EndIf
  CompilerEndSelect
 
  Procedure.i IsLeapYear(Year.i)
    If Year < 1600
      ; vor dem Jahr 1600 sind alle Jahre Schaltjahre, die durch 4 restlos teilbar sind
      ProcedureReturn Bool(Year % 4 = 0)
    Else
      ; ab dem Jahr 1600 sind alle Jahre Schaltjahre, die folgende Bedingungen erfüllen:
      ; => restlos durch 4 teilbar, jedoch nicht restlos durch 100 teilbar
      ; => restlos durch 400 teilbar
      ProcedureReturn Bool((Year % 4 = 0 And Year % 100 <> 0) Or Year % 400 = 0)
    EndIf
  EndProcedure
 
  Procedure.i DaysInMonth(Year.i, Month.i)
    While Month > 12
      Year  + 1
      Month - 12
    Wend
    While Month < 0
      Year  - 1
      Month + 13
    Wend
    If Month = 0
      Month = 1
    EndIf
   
    Select Month
      Case 1, 3, 5, 7, 8, 10, 12: ProcedureReturn 31
      Case 4, 6, 9, 11:           ProcedureReturn 30
      Case 2:                     ProcedureReturn 28 + IsLeapYear(Year) ; Februar hat im Schaltjahr ein Tag mehr
    EndSelect
  EndProcedure
 
  Procedure.q Date64(Year.i = -1, Month.i = 1, Day.i = 1, Hour.i = 0, Minute.i = 0, Second.i = 0)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
      Protected.FILETIME   ft
      Protected.i          DaysInMonth
     
      If Year > -1 ; Gültiges Datum
        ; Angaben evtl. korrigieren
       
        Minute + Second/60
        Second % 60
        If Second < 0
          Minute - 1
          Second + 60
        EndIf
       
        Hour + Minute/60
        Minute % 60
        If Minute < 0
          Hour   - 1
          Minute + 60
        EndIf
       
        Day + Hour/24
        Hour % 24
        If Hour < 0
          Day  - 1
          Hour + 24
        EndIf
        
        While Month > 12
          Year  + 1
          Month - 12
        Wend
        If Month = 0
          Month = 1
        EndIf
        
        DaysInMonth = DaysInMonth(Year, Month)
        While Day > DaysInMonth
          Day - DaysInMonth
          Month + 1
          If Month > 12
            Year  + 1
            Month - 12
          EndIf
          DaysInMonth = DaysInMonth(Year, Month)
        Wend
       
        If Day < 0
          Month - 1
          If Month = 0
            Year  - 1
            Month = 12
          EndIf
          Day + DaysInMonth(Year, Month)
        EndIf
       
        st\wYear   = Year
        st\wMonth  = Month
        st\wDay    = Day
        st\wHour   = Hour
        st\wMinute = Minute
        st\wSecond = Second
       
        SystemTimeToFileTime_(@st, @ft)
       
        ; Zeit in Sekunden umrechnen
        ProcedureReturn (PeekQ(@ft) - #HundredNanosecondsFrom_1Jan1601_To_1Jan1970) / #HundredNanosecondsInOneSecond
      Else ; Kein gültiges Datum. Systemzeit wird ermittelt
        GetLocalTime_(@st)
        SystemTimeToFileTime_(@st, @ft)
       
        ; Zeit in Sekunden umrechnen
        ProcedureReturn (PeekQ(@ft) - #HundredNanosecondsFrom_1Jan1601_To_1Jan1970) / #HundredNanosecondsInOneSecond
      EndIf
    CompilerElse ; Linux oder Mac
      Protected.tm tm
      Protected.q time
      Protected.tm *Memory_localtime
     
      If Year > -1 ; Gültiges Datum
        tm\tm_year  = Year - 1900 ; Jahre ab 1900
        tm\tm_mon   = Month - 1   ; Monate ab Januar
        tm\tm_mday  = Day
        tm\tm_hour  = Hour
        tm\tm_min   = Minute
        tm\tm_sec   = Second
        tm\tm_isdst = -1 ; <<<<<< ist wichtig, sonst sind viele Werte falsch, die mktime() zurückgibt
       
        ; mktime korrigiert die Angaben selber und liefert bereits Sekunden
        time = mktime_(@tm)
        time + tm\tm_gmtoff
        ProcedureReturn time
      Else ; Kein gültiges Datum. Systemzeit wird ermittelt
        time = time_(0)
        If time > -1
          *Memory_localtime = AllocateMemory(SizeOf(tm))
          If *Memory_localtime
            localtime_r_(@time, *Memory_localtime) ; Per Memory ist es thread-sicher
            time = mktime_(*Memory_localtime)
            time + *Memory_localtime\tm_gmtoff
            FreeMemory(*Memory_localtime)
            If time > -1
              ProcedureReturn time
            EndIf
          EndIf
        EndIf
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.q LocalDateAsUTC64()
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
      Protected.FILETIME   ft
     
      GetSystemTime_(@st)
      SystemTimeToFileTime_(@st, @ft)
     
      ; Zeit in Sekunden umrechnen
      ProcedureReturn (PeekQ(@ft) - #HundredNanosecondsFrom_1Jan1601_To_1Jan1970) / #HundredNanosecondsInOneSecond
    CompilerElse ; Linux oder Mac
      ProcedureReturn time_(0)
    CompilerEndIf
  EndProcedure
 
  Procedure.i Year64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wYear
    CompilerElse ; Linux oder Mac
      Protected.tm *Memory_TimeStruc
      Protected.i  Year
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc) ; Per Memory ist es thread-sicher
        Year = *Memory_TimeStruc\tm_year
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn Year + 1900
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i Month64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wMonth
    CompilerElse ; Linux oder Mac
      Protected.tm *Memory_TimeStruc
      Protected.i  Month
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc) ; Per Memory ist es thread-sicher
        Month = *Memory_TimeStruc\tm_mon
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn Month + 1
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i Day64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wDay
    CompilerElse ; Linux oder Mac
      Protected.tm *Memory_TimeStruc
      Protected.i  Day
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc) ; Per Memory ist es thread-sicher
        Day = *Memory_TimeStruc\tm_mday
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn Day
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i Hour64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wHour
    CompilerElse ; Linux oder Mac
      Protected.tm *Memory_TimeStruc
      Protected.i  Hour
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc) ; Per Memory ist es thread-sicher
        Hour = *Memory_TimeStruc\tm_hour
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn Hour
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i Minute64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wMinute
    CompilerElse ; Linux oder Mac
      Protected.tm *Memory_TimeStruc
      Protected.i  Minute
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc) ; Per Memory ist es thread-sicher
        Minute = *Memory_TimeStruc\tm_min
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn Minute
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i Second64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wSecond
    CompilerElse ; Linux oder Mac
      Protected.tm *Memory_TimeStruc
      Protected.i Second
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc) ; Per Memory ist es thread-sicher
        Second = *Memory_TimeStruc\tm_sec
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn Second
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i DayOfWeek64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.SYSTEMTIME st
     
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
     
      ProcedureReturn st\wDayOfWeek
    CompilerElse ; Linux oder Mac
      Protected.tm *Memory_TimeStruc
      Protected.i  DayOfWeek
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc) ; Per Memory ist es thread-sicher
        DayOfWeek = *Memory_TimeStruc\tm_wday
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn DayOfWeek
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.i DayOfYear64(Date.q)
    CompilerIf #PB_Compiler_OS = #PB_OS_Windows
      Protected.q TempDate
     
      TempDate = Date64(Year64(Date))
     
      ProcedureReturn (Date - TempDate) / #SecondsInOneDay + 1
    CompilerElse ; Linux oder Mac
      Protected.tm *Memory_TimeStruc
      Protected.i  DayOfYear
     
      *Memory_TimeStruc = AllocateMemory(SizeOf(tm))
     
      If *Memory_TimeStruc
        gmtime_r(@Date, *Memory_TimeStruc) ; Per Memory ist es thread-sicher
        DayOfYear = *Memory_TimeStruc\tm_yday
        FreeMemory(*Memory_TimeStruc)
       
        ProcedureReturn DayOfYear + 1
      Else
        ProcedureReturn -1
      EndIf
    CompilerEndIf
  EndProcedure
 
  Procedure.q AddDate64(Date.q, Type.i, Value.i)
    Protected.i Day, Month, Year
   
    Select Type
      Case #PB_Date_Year:   ProcedureReturn Date64(Year64(Date) + Value, Month64(Date), Day64(Date), Hour64(Date), Minute64(Date), Second64(Date))
      Case #PB_Date_Month
        Day   = Day64(Date)
        Month = Month64(Date) + Value
        Year  = Year64(Date)
       
        If Day > DaysInMonth(Year, Month)
          ; mktime_() korrigiert das zwar auch, wendet dabei aber eine andere Methode als PB-AddDate() an:
          ; >> mktime_():    31.03.2004 => 1 Monat später => 01.05.2004
          ; >> PB-AddDate(): 31.03.2004 => 1 Monat später => 30.04.2004
         
          ; setzte Tag auf das Maximum des neuen Monats
          Day = DaysInMonth(Year, Month)
        EndIf
       
        ProcedureReturn Date64(Year64(Date), Month, Day, Hour64(Date), Minute64(Date), Second64(Date))
      Case #PB_Date_Week:   ProcedureReturn Date64(Year64(Date), Month64(Date), Day64(Date) + Value * 7, Hour64(Date), Minute64(Date), Second64(Date))
      Case #PB_Date_Day:    ProcedureReturn Date64(Year64(Date), Month64(Date), Day64(Date) + Value, Hour64(Date), Minute64(Date), Second64(Date))
      Case #PB_Date_Hour:   ProcedureReturn Date64(Year64(Date), Month64(Date), Day64(Date), Hour64(Date) + Value, Minute64(Date), Second64(Date))
      Case #PB_Date_Minute: ProcedureReturn Date64(Year64(Date), Month64(Date), Day64(Date), Hour64(Date), Minute64(Date) + Value, Second64(Date))
      Case #PB_Date_Second: ProcedureReturn Date64(Year64(Date), Month64(Date), Day64(Date), Hour64(Date), Minute64(Date), Second64(Date) + Value)
    EndSelect
  EndProcedure
 
  Procedure.s FormatDate64(Mask.s, Date.q)
    Protected.s Retval
   
    Retval = ReplaceString(Mask,   "%yyyy", RSet(Str(Year64(Date)),           4, "0"))
    Retval = ReplaceString(Retval, "%yy",   RSet(Right(Str(Year64(Date)), 2), 2, "0"))
    Retval = ReplaceString(Retval, "%mm",   RSet(Str(Month64(Date)),          2, "0"))
    Retval = ReplaceString(Retval, "%dd",   RSet(Str(Day64(Date)),            2, "0"))
    Retval = ReplaceString(Retval, "%hh",   RSet(Str(Hour64(Date)),           2, "0"))
    Retval = ReplaceString(Retval, "%ii",   RSet(Str(Minute64(Date)),         2, "0"))
    Retval = ReplaceString(Retval, "%ss",   RSet(Str(Second64(Date)),         2, "0"))
   
    ProcedureReturn Retval
  EndProcedure
 
  Procedure.q ParseDate64(Mask.s, Date.s)
    Protected.i i, DatePos = 1, IsVariableFound, Year, Month = 1, Day = 1, Hour, Minute, Second
    Protected.s MaskChar, DateChar
   
    For i = 1 To Len(Mask)
      MaskChar = Mid(Mask, i, 1)
      DateChar = Mid(Date, DatePos, 1)
     
      If MaskChar <> DateChar
        If MaskChar = "%" ; Vielleicht eine Variable?
          If Mid(Mask, i, 5) = "%yyyy"
            IsVariableFound = #True
            Year = Val(Mid(Date, DatePos, 4))
            DatePos + 4 ; Die 4 Nummern der Jahreszahl überspringen
            i + 4       ; Die 5 Zeichen der Variable "%yyyy" überspringen
            Continue
          ElseIf Mid(Mask, i, 3) = "%yy"
            IsVariableFound = #True
            Year = Val(Mid(Date, DatePos, 2))
            DatePos + 2 ; Die 2 Nummern der Jahreszahl überspringen
            i + 2       ; Die 3 Zeichen der Variable "%yy" überspringen
            Continue
          EndIf
         
          If Mid(Mask, i, 3) = "%mm"
            IsVariableFound = #True
            Month = Val(Mid(Date, DatePos, 2))
            DatePos + 2 ; Die 2 Nummern der Monatszahl überspringen
            i + 2       ; Die 3 Zeichen der Variable "%mm" überspringen
            Continue
          EndIf
         
          If Mid(Mask, i, 3) = "%dd"
            IsVariableFound = #True
            Day = Val(Mid(Date, DatePos, 2))
            DatePos + 2 ; Die 2 Nummern der Tageszahl überspringen
            i + 2       ; Die 3 Zeichen der Variable "%dd" überspringen
            Continue
          EndIf
         
          If Mid(Mask, i, 3) = "%hh"
            IsVariableFound = #True
            Hour = Val(Mid(Date, DatePos, 2))
            DatePos + 2 ; Die 2 Nummern der Stundenzahl überspringen
            i + 2       ; Die 3 Zeichen der Variable "%hh" überspringen
            Continue
          EndIf
         
          If Mid(Mask, i, 3) = "%ii"
            IsVariableFound = #True
            Minute = Val(Mid(Date, DatePos, 2))
            DatePos + 2 ; Die 2 Nummern der Minutenzahl überspringen
            i + 2       ; Die 3 Zeichen der Variable "%ii" überspringen
            Continue
          EndIf
         
          If Mid(Mask, i, 3) = "%ss"
            IsVariableFound = #True
            Second = Val(Mid(Date, DatePos, 2))
            DatePos + 2 ; Die 2 Nummern der Sekundenzahl überspringen
            i + 2       ; Die 3 Zeichen der Variable "%ss" überspringen
            Continue
          EndIf
         
          If Not IsVariableFound
            ProcedureReturn 0
          EndIf
        Else
          ProcedureReturn 0
        EndIf
      EndIf
     
      DatePos + 1
    Next
   
    ProcedureReturn Date64(Year, Month, Day, Hour, Minute, Second)
  EndProcedure
EndModule

CompilerIf #PB_Compiler_IsMainFile
  ;-Test
 
  UseModule Date64
 
  Debug "Kleiner Kompatibilitäts-Test - Fehler:"
  For Year = 1970 To 2037
    For Month = 1 To 12
      For Day = 1 To 28
        For Hour = 0 To 23
          ;For Minute = 0 To 59
            ;For Second = 0 To 59
              d1 = Date(Year, Month, Day, Hour, Minute, Second)
              d2 = Date64(Year, Month, Day, Hour, Minute, Second)
             
              If d1 <> d2
                Debug d1
                Debug d2
                Debug ""
              EndIf
             
              d1$ = FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", d1)
              d2$ = FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", d2)
              If d1$ <> d2$
                Debug d1$
                Debug d2$
                Debug ""
              EndIf
             
            ;Next Second
          ;Next Minute
        Next Hour
      Next Day
    Next Month
  Next Year
 
  Debug "------------------------"
  Debug "DayOfWeek --------------"
  Debug DayOfWeek(Date())
  Debug DayOfWeek64(Date64())
 
  Debug "DayOfYear --------------"
  Debug DayOfYear(Date())
  Debug DayOfYear64(Date64())
 
  Debug "------------------------"
  Debug "Date(1600,1,1,0,0,0):   " + FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date(1600,1,1,0,0,0))
  Debug "Date64(2300,1,1,0,0,0): " + FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64(2300,1,1,0,0,0))
  Debug "Date(1971,8,20,0,0,0):  " + FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date(1971,8,20,0,0,0))
  Debug "Date64(1971,8,20):      " + FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64(1971,8,20))
 
  Debug "Aktuelles Datum --------"
  Debug FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date())
  Debug FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64())
 
  Debug "Aktuelles UTC-Datum ----"
  Debug FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", LocalDateAsUTC64())
 
  Debug "------------------------"
  a = Date64(2000, 1, 2, 11, 22, 33)
  Debug "Date64(2000, 1, 2, 11, 22, 33) => Year64(): "   + Year64(a)
  Debug "Date64(2000, 1, 2, 11, 22, 33) => Month64(): "  + Month64(a)
  Debug "Date64(2000, 1, 2, 11, 22, 33) => Day64(): "    + Day64(a)
  Debug "Date64(2000, 1, 2, 11, 22, 33) => Hour64(): "   + Hour64(a)
  Debug "Date64(2000, 1, 2, 11, 22, 33) => Minute64(): " + Minute64(a)
  Debug "Date64(2000, 1, 2, 11, 22, 33) => Second64(): " + Second64(a)
 
  Debug "Aktuelles UTC-Datum ----"
  a = LocalDateAsUTC64()
  Debug FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", a)
 
  Debug "UTC plus eine Stunde ---"
  a = AddDate64(a, #PB_Date_Hour, 1)
  Debug FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", a)
CompilerEndIf
Code aktualisiert:
- IsLeapYear() und DaysInMonth() ist nun auch extern verwendbar
- DaysInMonth() unterstützt nun Unter- und Überlauf bei Monatsangabe
- While-Schleifen weitestgehend durch Modulo ersetzt
- Fehler behoben (März- und April-Bug existiert unter Linux leider noch)
Zuletzt geändert von Sicro am 21.02.2016 18:49, insgesamt 1-mal geändert.
Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Date64 - Unixtime 64bit

Beitrag von NicTheQuick »

Wieso ersetzt du diese langsamen While-Schleifen nicht durch Modulo?

Code: Alles auswählen

        While Second > 59
          Minute + 1
          Second - 60
        Wend
Und wieso wird hier + 59, statt + 60 gemacht?

Code: Alles auswählen

        While Second < 0
          Minute - 1
          Second + 59
        Wend
Ohne Schleife ist es effizienter und wird immer in konstanter Zeit ausgeführt, auch wenn "Second" gleich 1000000000 sein sollte.

Code: Alles auswählen

Second = -90
Minute = 0

Minute + Second / 60
Second % 60
If Second < 0
	Minute - 1
	Second + 60
EndIf

Debug Second
Debug Minute
Bild
Antworten