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
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Date64 - Unixtime 64bit

Beitrag von mk-soft »

Im jahr 2038 ist es aus mit den Datumsfunktionen mit Unix Time Format 32. Weiss nicht wann PB da umgestellt wird.

Vielen Dank an Sicro und ts-soft für die Erweiterung für Linux und Mac

Update v2.02

Update v2.04
- Stand CodeArchiv von 12.08.2018

Code: Alles auswählen

;-TOP
;
;   Description: Support for enlarged date range (64 bit unix timestamp)
;            OS: Windows, Linux, Mac
; English-Forum: 
;  French-Forum: 
;  German-Forum: http://www.purebasic.fr/german/viewtopic.php?p=335727#p335727
; -----------------------------------------------------------------------------

; MIT License
; 
; Copyright (c) 2012 mk-soft
; Copyright (c) 2013-2017 Sicro
; Copyright (c) 2014 ts-soft
; Copyright (c) 2017 wilbert
; 
; Permission is hereby granted, free of charge, to any person obtaining a copy
; of this software and associated documentation files (the "Software"), to deal
; in the Software without restriction, including without limitation the rights
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
; copies of the Software, and to permit persons to whom the Software is
; furnished to do so, subject to the following conditions:
; 
; The above copyright notice and this permission notice shall be included in all
; copies or substantial portions of the Software.
; 
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
; SOFTWARE.

; -----------------------------------------------------------------------------

; Version : v2.04
; Create  : 22.10.2012
; Update  : 12.08.2018
; OS      : All
; Link DE : http://www.purebasic.fr/german/viewtopic.php?f=8&t=26001

DeclareModule Date64
  Declare.i IsLeapYear64(Year.i)
  Declare.i DaysInMonth64(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.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$, Date.q)
  Declare.q ParseDate64(Mask$, Date$)
EndDeclareModule

Module Date64
  EnableExplicit

  ; !!! >>> WARNING <<< !!!
  ; The Gregorian calendar was introduced in many regions at different times.
  ; This module uses the API date functions of the operating system and these have implemented a
  ; uniform introduction time, so that date calculations before the introduction of the Gregorian
  ; calendar usually lead to wrong results.

  ; == Windows ==
  ; >> Minimum: 01.01.1601 00:00:00
  ; >> Maximum: 31.12.9999 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.9999 23:59:59

  ; == MacOS ==
  ; >> Minimum: 31.12.1969 23:59:59
  ; >> Maximum: 31.12.9999 23:59:59

  #SecondsInOneHour = 60 * 60
  #SecondsInOneDay  = #SecondsInOneHour * 24

  #HundredNanosecondsInOneSecond               = 10000000
  #HundredNanosecondsFrom_1Jan1601_To_1Jan1970 = 116444736000000000

  CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
    ImportC ""
      CFCalendarAddComponents(calendar, *at, options, componentDesc.p-ascii, value)
      CFCalendarComposeAbsoluteTime(calendar, *at, componentDesc.p-ascii, year, month, day, hour, minute, second)
      CFCalendarCreateWithIdentifier(allocator, identifier)
      CFCalendarDecomposeAbsoluteTime(calendar, at.d, componentDesc.p-ascii, *component)
      CFCalendarSetTimeZone(calendar, tz)
      CFTimeZoneCopyDefault()
      CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ti.d)
      CFTimeZoneGetSecondsFromGMT.d(tz, at.d)
    EndImport

    Global.i GregorianGMT, TimeZone

    Procedure Date64Init(); Init global variables GregorianGMT and TimeZone
      Protected *kCFGregorianCalendar.Integer = dlsym_(#RTLD_DEFAULT, "kCFGregorianCalendar")
      TimeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(0, 0)
      GregorianGMT = CFCalendarCreateWithIdentifier(0, *kCFGregorianCalendar\i)
      CFCalendarSetTimeZone(GregorianGMT, TimeZone)
      CFRelease_(TimeZone)
      TimeZone = CFTimeZoneCopyDefault()
    EndProcedure

    Date64Init()
  CompilerEndIf

  ;{ Structure definition for "tm"
  CompilerIf #PB_Compiler_OS = #PB_OS_Linux
    If Not Defined(tm, #PB_Structure)
      Structure tm Align #PB_Structure_AlignC
        tm_sec.l    ; 0 to 59 or up to 60 at leap second
        tm_min.l    ; 0 to 59
        tm_hour.l   ; 0 to 23
        tm_mday.l   ; Day of the month: 1 to 31
        tm_mon.l    ; Month: 0 to 11 (0 = January)
        tm_year.l   ; Number of years since the year 1900
        tm_wday.l   ; Weekday: 0 to 6, 0 = Sunday
        tm_yday.l   ; Days since the beginning of the year: 0 to 365 (365 is therefore 366 because after 1. January is counted)
        tm_isdst.l  ; Is summer time? tm_isdst > 0 = Yes
                    ;                             tm_isdst = 0 = No
                    ;                             tm_isdst < 0 = Unknown
        CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
          tm_gmtoff.l ; Offset of UTC in seconds
          *tm_zone    ; Abbreviation of the time zone
        CompilerElse
          tm_zone.l   ; Placeholder
          tm_gmtoff.l ; Offset of UTC in seconds
          *tm_zone64  ; Abbreviation of the time zone
        CompilerEndIf

      EndStructure
    EndIf
  CompilerEndIf
  ;}

  Procedure.i IsLeapYear64(Year.i)
    If Year < 1600
      ; Every year before 1600 are leap years if they are divisible by 4 with no remainder
      ProcedureReturn Bool(Year % 4 = 0)
    Else
      ; From the year 1600 are all year leap years that meet the following conditions:
      ; => Can be divided by 4 without remainder, but can not be divided by 100 without remainder
      ; => Divisible by 400 without remainder
      ProcedureReturn Bool((Year % 4 = 0 And Year % 100 <> 0) Or Year % 400 = 0)
    EndIf
  EndProcedure

  Procedure.i DaysInMonth64(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 + IsLeapYear64(Year) ; February has one more day in the leap year
    EndSelect
  EndProcedure

  Procedure.q Date64(Year.i=-1, Month.i=1, Day.i=1, Hour.i=0, Minute.i=0, Second.i=0)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
        Protected.FILETIME   ft, ft2
        Protected.i          DaysInMonth

        If Year > -1 ; Valid date

          ; Correct the data, if necessary

          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 = DaysInMonth64(Year, Month)
          While Day > DaysInMonth
            Day - DaysInMonth
            Month + 1
            If Month > 12
              Year  + 1
              Month - 12
            EndIf
            DaysInMonth = DaysInMonth64(Year, Month)
          Wend

          If Day < 0
            Month - 1
            If Month = 0
              Year  - 1
              Month = 12
            EndIf
            Day + DaysInMonth64(Year, Month)
          EndIf

          st\wYear   = Year
          st\wMonth  = Month
          st\wDay    = Day
          st\wHour   = Hour
          st\wMinute = Minute
          st\wSecond = Second

          ; Convert system time (UTC) to file time (UTC)
          SystemTimeToFileTime_(@st, @ft)

          ; Convert UTC time to seconds
          ProcedureReturn (PeekQ(@ft) - #HundredNanosecondsFrom_1Jan1601_To_1Jan1970) / #HundredNanosecondsInOneSecond
        Else
          ; No valid date. Local system time is determined
          GetLocalTime_(@st)
          SystemTimeToFileTime_(@st, @ft) ; "st" is read as UTC and convert to file time

          ; Convert UTC time to seconds
          ProcedureReturn (PeekQ(@ft) - #HundredNanosecondsFrom_1Jan1601_To_1Jan1970) / #HundredNanosecondsInOneSecond
        EndIf

      CompilerCase #PB_OS_Linux
        Protected.tm tm
        Protected.q time
        
        If Year > -1 ; Valid date
          tm\tm_year  = Year - 1900 ; Years from 1900
          tm\tm_mon   = Month - 1   ; Months from January
          tm\tm_mday  = Day
          tm\tm_hour  = Hour
          tm\tm_min   = Minute
          tm\tm_sec   = Second

          ; mktime corrects the data itself and delivers seconds
          time = timegm_(@tm) ; Convert structured UTC time to UTC time as seconds

          ProcedureReturn time ; UTC time in seconds
        Else
          ; No valid date. Local system time is determined
          time = time_(0)
          If localtime_r_(@time, @tm) <> 0
            time = timegm_(@tm)
          EndIf

          ProcedureReturn time  ; UTC time in seconds
        EndIf

      CompilerCase #PB_OS_MacOS
        Protected at.d
        If Year > -1 ; Valid date
          CFCalendarComposeAbsoluteTime(GregorianGMT, @at, "yMdHms", Year, Month, Day, Hour, Minute, Second)
        Else ; No valid date. Local system time is determined
          at = CFAbsoluteTimeGetCurrent_()
          at + CFTimeZoneGetSecondsFromGMT(TimeZone, at)
        EndIf
        ProcedureReturn at + 978307200
    CompilerEndSelect
  EndProcedure

  Macro Windows_ReturnDatePart(Type)
    Protected.SYSTEMTIME st

    Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
    FileTimeToSystemTime_(@Date, @st)

    ProcedureReturn st\Type
  EndMacro

  Macro Linux_ReturnDatePart(Type, ReturnCode)
    Protected.tm *tm
    Protected.i  Value

    *tm = gmtime_(@Date)
    If *tm
      Value = *tm\Type
    EndIf

    ProcedureReturn ReturnCode
  EndMacro

  Macro Mac_ReturnDatePart(Type)
    Protected.i DatePart

    CFCalendarDecomposeAbsoluteTime(GregorianGMT, Date - 978307200, Type, @DatePart)

    CompilerIf Type = "E"
      ProcedureReturn DatePart - 1
    CompilerElse
      ProcedureReturn DatePart
    CompilerEndIf
  EndMacro

  Procedure.i Year64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows : Windows_ReturnDatePart(wYear)
      CompilerCase #PB_OS_Linux   : Linux_ReturnDatePart(tm_year, Value + 1900)
      CompilerCase #PB_OS_MacOS   : Mac_ReturnDatePart("y")
    CompilerEndSelect
  EndProcedure

  Procedure.i Month64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows : Windows_ReturnDatePart(wMonth)
      CompilerCase #PB_OS_Linux   : Linux_ReturnDatePart(tm_mon, Value + 1)
      CompilerCase #PB_OS_MacOS   : Mac_ReturnDatePart("M")
    CompilerEndSelect
  EndProcedure

  Procedure.i Day64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows : Windows_ReturnDatePart(wDay)
      CompilerCase #PB_OS_Linux   : Linux_ReturnDatePart(tm_mday, Value)
      CompilerCase #PB_OS_MacOS   : Mac_ReturnDatePart("d")
    CompilerEndSelect
  EndProcedure

  Procedure.i Hour64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows : Windows_ReturnDatePart(wHour)
      CompilerCase #PB_OS_Linux   : Linux_ReturnDatePart(tm_hour, Value)
      CompilerCase #PB_OS_MacOS   : Mac_ReturnDatePart("H")
    CompilerEndSelect
  EndProcedure

  Procedure.i Minute64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows : Windows_ReturnDatePart(wMinute)
      CompilerCase #PB_OS_Linux   : Linux_ReturnDatePart(tm_min, Value)
      CompilerCase #PB_OS_MacOS   : Mac_ReturnDatePart("m")
    CompilerEndSelect
  EndProcedure

  Procedure.i Second64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows : Windows_ReturnDatePart(wSecond)
      CompilerCase #PB_OS_Linux   : Linux_ReturnDatePart(tm_sec, Value)
      CompilerCase #PB_OS_MacOS   : Mac_ReturnDatePart("s")
    CompilerEndSelect
  EndProcedure

  Procedure.i DayOfWeek64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows : Windows_ReturnDatePart(wDayOfWeek)
      CompilerCase #PB_OS_Linux   : Linux_ReturnDatePart(tm_wday, Value)
      CompilerCase #PB_OS_MacOS   : Mac_ReturnDatePart("E")
    CompilerEndSelect
  EndProcedure

  Procedure.i DayOfYear64(Date.q)
    CompilerSelect #PB_Compiler_OS

      CompilerCase #PB_OS_Windows
        Protected.q TempDate
        TempDate = Date64(Year64(Date))
        ProcedureReturn (Date - TempDate) / #SecondsInOneDay + 1

      CompilerCase #PB_OS_Linux
        Linux_ReturnDatePart(tm_yday, Value + 1)

      CompilerCase #PB_OS_MacOS
        Mac_ReturnDatePart("D")

    CompilerEndSelect
  EndProcedure

  Procedure.q AddDate64(Date.q, Type.i, Value.i)
    CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
      Protected at.d = Date - 978307200

      Select Type
        Case #PB_Date_Year:   CFCalendarAddComponents(GregorianGMT, @at, 0, "y", Value)
        Case #PB_Date_Month:  CFCalendarAddComponents(GregorianGMT, @at, 0, "M", Value)
        Case #PB_Date_Week:   CFCalendarAddComponents(GregorianGMT, @at, 0, "d", Value * 7)
        Case #PB_Date_Day:    CFCalendarAddComponents(GregorianGMT, @at, 0, "d", Value)
        Case #PB_Date_Hour:   CFCalendarAddComponents(GregorianGMT, @at, 0, "H", Value)
        Case #PB_Date_Minute: CFCalendarAddComponents(GregorianGMT, @at, 0, "m", Value)
        Case #PB_Date_Second: CFCalendarAddComponents(GregorianGMT, @at, 0, "s", Value)
      EndSelect

      ProcedureReturn at + 978307200 
    CompilerElse ; Windows or Linux
      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 > DaysInMonth64(Year, Month)
            ; Mktime corrects the date unlike PB-AddDate it does
            ; >> mktime:     31.03.2004 => 1 month later => 01.05.2004
            ; >> PB-AddDate: 31.03.2004 => 1 month later => 30.04.2004

            ; Set day to the maximum of the new month
            Day = DaysInMonth64(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
    CompilerEndIf

  EndProcedure

  Procedure.s FormatDate64(Mask$, Date.q)
    Protected Result$

    Result$ = ReplaceString(Mask$,   "%yyyy", RSet(Str(Year64(Date)),           4, "0"))
    Result$ = ReplaceString(Result$, "%yy",   RSet(Right(Str(Year64(Date)), 2), 2, "0"))
    Result$ = ReplaceString(Result$, "%mm",   RSet(Str(Month64(Date)),          2, "0"))
    Result$ = ReplaceString(Result$, "%dd",   RSet(Str(Day64(Date)),            2, "0"))
    Result$ = ReplaceString(Result$, "%hh",   RSet(Str(Hour64(Date)),           2, "0"))
    Result$ = ReplaceString(Result$, "%ii",   RSet(Str(Minute64(Date)),         2, "0"))
    Result$ = ReplaceString(Result$, "%ss",   RSet(Str(Second64(Date)),         2, "0"))

    ProcedureReturn Result$
  EndProcedure

  Macro ReadMaskVariable(MaskVariable, ReturnVariable)
    If Mid(Mask$, i, 3) = MaskVariable
      IsVariableFound = #True
      ReturnVariable = Val(Mid(Date$, DatePos, 2))
      DatePos + 2 ; Skip the 2 numbers of the number
      i + 2       ; Skip the 3 characters of the variable
      Continue
    EndIf
  EndMacro

  Procedure.q ParseDate64(Mask$, Date$)
    Protected.i i, DatePos = 1, IsVariableFound, Year, Month = 1, Day = 1, Hour, Minute, Second
    Protected MaskChar$, DateChar$

    For i = 1 To Len(Mask$)
      MaskChar$ = Mid(Mask$, i, 1)
      DateChar$ = Mid(Date$, DatePos, 1)

      If MaskChar$ <> DateChar$
        If MaskChar$ = "%" ; Maybe a variable?

          If Mid(Mask$, i, 5) = "%yyyy"
            IsVariableFound = #True
            Year = Val(Mid(Date$, DatePos, 4))
            DatePos + 4 ; Skip the 4 numbers of the year
            i + 4       ; Skip the 5 characters of the variable "%yyyy"
            Continue

          ElseIf Mid(Mask$, i, 3) = "%yy"
            IsVariableFound = #True
            Year = Val(Mid(Date$, DatePos, 2))
            DatePos + 2 ; Skip the 2 numbers of the year
            i + 2       ; Skip the 3 characters of the variable "%yy"
            Continue

          EndIf

          ReadMaskVariable("%mm", Month)
          ReadMaskVariable("%dd", Day)
          ReadMaskVariable("%hh", Hour)
          ReadMaskVariable("%ii", Minute)
          ReadMaskVariable("%ss", Second)

          If Not IsVariableFound
            ProcedureReturn 0
          EndIf

        Else
          ProcedureReturn 0
        EndIf

      EndIf

      DatePos + 1
    Next

    ProcedureReturn Date64(Year, Month, Day, Hour, Minute, Second)
  EndProcedure
EndModule

;-Example
CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
  
  ;-Test
  
  UseModule Date64
  
  Define.i Year, Month, Day, Hour, Minute, Second, Result, Result64
  Define.q Date, Date64
  Define   Date$, Date64$, Result64$
  
  Debug "Small compatibility test - error:"

  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

          Date = Date(Year, Month, Day, Hour, Minute, Second)
          Date64 = Date64(Year, Month, Day, Hour, Minute, Second)
          
          If Date <> Date64
            Debug "Date() <> Date64()"
            Debug Date
            Debug Date64
            Debug ""
          EndIf
          
          Date$ = FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date)
          Date64$ = FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64)
          If Date$ <> Date64$
            Debug "FormatDate() <> FormatDate64()"
            Debug Date$
            Debug Date64$
            Debug ""
          EndIf
          
          Result = ParseDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date$)
          Result64 = ParseDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64$)
          If Result <> Result64
            Debug "ParseDate() <> ParseDate64()"
            Debug Result
            Debug Result64
            Debug ""
          EndIf
          
          Result = DayOfWeek(Date)
          Result64 = DayOfWeek64(Date64)
          If Result <> Result64
            Debug "DayOfWeek() <> DayOfWeek64()"
            Debug Result
            Debug Result64
            Debug ""
          EndIf
          
          Result = DayOfYear(Date)
          Result64 = DayOfYear64(Date64)
          If Result <> Result64
            Debug "DayOfYear() <> DayOfYear64()"
            Debug Result
            Debug Result64
            Debug ""
          EndIf
          
          ;Next Second
          ;Next Minute
        Next Hour
      Next Day
    Next Month
  Next Year
  
  If Date() <> Date64()
    Debug "Date() <> Date64()"
  EndIf
  
  Macro AddDateTest(Type, TypeS)
    
    If AddDate(Date(), #PB_Date_#Type, 1) <> AddDate64(Date64(), #PB_Date_#Type, 1)
      Debug "AddDate(Date(), #PB_Date_" + TypeS + ", 1) <> AddDate64(Date64(), #PB_Date_" + TypeS + ", 1)"
    EndIf
    
    If AddDate(Date(), #PB_Date_#Type, -1) <> AddDate64(Date64(), #PB_Date_#Type, -1)
      Debug "AddDate(Date(), #PB_Date_" + TypeS + ", -1) <> AddDate64(Date64(), #PB_Date_" + TypeS + ", -1)"
    EndIf
    
  EndMacro
  
  AddDateTest(Year,   "Year")
  AddDateTest(Month,  "Month")
  AddDateTest(Day,    "Day")
  AddDateTest(Hour,   "Hour")
  AddDateTest(Minute, "Minute")
  AddDateTest(Second, "Second")
  AddDateTest(Week,   "Week")
  
  Macro TestDateLimits(Minimum, Maximum)
    
    Date64$ = Minimum
    Date64 = ParseDate64("%dd.%mm.%yyyy %hh:%ii:%ss", Date64$)
    Result64$ = FormatDate64("%dd.%mm.%yyyy %hh:%ii:%ss", Date64)
    If Date64$ <> Result64$
      Debug "Minimum is wrong:"
      Debug "> Expected was: " + Date64$
      Debug "> It was returned: " + Result64$
    EndIf
    
    Date64$ = Maximum
    Date64 = ParseDate64("%dd.%mm.%yyyy %hh:%ii:%ss", Date64$)
    Result64$ = FormatDate64("%dd.%mm.%yyyy %hh:%ii:%ss", Date64)
    If Date64$ <> Result64$
      Debug "Maximum is wrong:"
      Debug "> Expected was: " + Date64$
      Debug "> It was returned: " + Result64$
    EndIf
    
  EndMacro
  
  Debug "---------------------"
  Debug "Test of date limits - error:"
  
  CompilerSelect #PB_Compiler_OS
      
    CompilerCase #PB_OS_Windows
      TestDateLimits("01.01.1601 00:00:00", "31.12.9999 23:59:59")
      
    CompilerCase #PB_OS_Linux
      CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
        TestDateLimits("01.01.1902 00:00:00", "18.01.2038 23:59:59")
      CompilerElse
        TestDateLimits("01.01.0000 00:00:00", "31.12.9999 23:59:59")
      CompilerEndIf
      
    CompilerCase #PB_OS_MacOS
      TestDateLimits("31.12.1969 23:59:59", "31.12.9999 23:59:59")
      
  CompilerEndSelect
  
  Debug "---------------------"
  Debug "Test was carried out"
CompilerEndIf
Zuletzt geändert von mk-soft am 22.07.2019 22:41, insgesamt 6-mal geändert.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Date64 - Unixtime 64bit

Beitrag von STARGÅTE »

Na hoffentlich erinnern wir uns in 26 Jahren noch an
diesen Thread,
dieses Forum,
die Sprache Pure Basic,
das Betriebssystem Windows
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Date64 - Unixtime 64bit

Beitrag von Sicro »

Hab mal einen komplett neuen Code geschrieben, der unter allen 3 Betriebssystemen laufen sollte.
Unter Windows (Windows 7 HE) und Linux (Xubuntu) läuft alles, MacOS kann ich nicht testen.

Code: Alles auswählen

#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
        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
      EndStructure
    EndIf
  CompilerCase #PB_OS_MacOS
    If Not Defined(tm, #PB_Structure)
      Structure tm
        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   ; Offset von UTC in Sekunden
      EndStructure
    EndIf
CompilerEndSelect

; == 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?

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)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #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
    CompilerCase #PB_OS_Linux
      Protected.tm tm
      Protected.q time
              
      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
        
        ; 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
          CompilerSelect #PB_Compiler_Processor
            CompilerCase #PB_Processor_x86
              *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
            CompilerCase #PB_Processor_x64
              *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
          CompilerEndSelect
          
          If *Memory_localtime
            localtime_r_(@time, *Memory_localtime) ; Per Memory ist es thread-sicher
            time = mktime_(*Memory_localtime)
            FreeMemory(*Memory_localtime)
            If time > -1
              ProcedureReturn time
            EndIf
          EndIf
        EndIf
      EndIf
    CompilerCase #PB_OS_MacOS
      Protected.tm tm
      Protected.q time
              
      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
        
        ; 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)
            FreeMemory(*Memory_localtime)
            If time > -1
              ProcedureReturn time
            EndIf
          EndIf
        EndIf
      EndIf
  CompilerEndSelect
EndProcedure

Procedure.i Year64(Date.q)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      Protected.SYSTEMTIME st
  
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
    
      ProcedureReturn st\wYear
    CompilerCase #PB_OS_Linux
      Protected.tm *Memory_localtime
      Protected.i  Year
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerCase #PB_Processor_x64
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
      CompilerEndSelect
      
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        Year = *Memory_localtime\tm_year + 1900
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn Year
      Else
        ProcedureReturn -1
      EndIf
    CompilerCase #PB_OS_MacOS
      Protected.tm *Memory_localtime
      Protected.i  Year
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      *Memory_localtime = AllocateMemory(SizeOf(tm))
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        Year = *Memory_localtime\tm_year + 1900
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn Year
      Else
        ProcedureReturn -1
      EndIf
  CompilerEndSelect
EndProcedure

Procedure.i Month64(Date.q)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      Protected.SYSTEMTIME st
      
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
      
      ProcedureReturn st\wMonth
    CompilerCase #PB_OS_Linux
      Protected.tm *Memory_localtime
      Protected.i  Month
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerCase #PB_Processor_x64
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
      CompilerEndSelect
      
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        Month = *Memory_localtime\tm_mon + 1
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn Month
      Else
        ProcedureReturn -1
      EndIf
    CompilerCase #PB_OS_MacOS
      Protected.tm *Memory_localtime
      Protected.i  Month
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      *Memory_localtime = AllocateMemory(SizeOf(tm))
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        Month = *Memory_localtime\tm_mon + 1
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn Month
      Else
        ProcedureReturn -1
      EndIf
  CompilerEndSelect
EndProcedure

Procedure.i Day64(Date.q)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      Protected.SYSTEMTIME st
      
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
      
      ProcedureReturn st\wDay
    CompilerCase #PB_OS_Linux
      Protected.tm *Memory_localtime
      Protected.i  Day
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerCase #PB_Processor_x64
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
      CompilerEndSelect
      
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        Day = *Memory_localtime\tm_mday
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn Day
      Else
        ProcedureReturn -1
      EndIf
    CompilerCase #PB_OS_MacOS
      Protected.tm *Memory_localtime
      Protected.i  Day
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      *Memory_localtime = AllocateMemory(SizeOf(tm))
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        Day = *Memory_localtime\tm_mday
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn Day
      Else
        ProcedureReturn -1
      EndIf
  CompilerEndSelect
EndProcedure

Procedure.i Hour64(Date.q)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      Protected.SYSTEMTIME st
      
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
      
      ProcedureReturn st\wHour
    CompilerCase #PB_OS_Linux
      Protected.tm *Memory_localtime
      Protected.i  Hour
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerCase #PB_Processor_x64
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
      CompilerEndSelect
      
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        Hour = *Memory_localtime\tm_hour
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn Hour
      Else
        ProcedureReturn -1
      EndIf
    CompilerCase #PB_OS_MacOS
      Protected.tm *Memory_localtime
      Protected.i  Hour
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      *Memory_localtime = AllocateMemory(SizeOf(tm))
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        Hour = *Memory_localtime\tm_hour
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn Hour
      Else
        ProcedureReturn -1
      EndIf
  CompilerEndSelect
EndProcedure

Procedure.i Minute64(Date.q)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      Protected.SYSTEMTIME st
      
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
      
      ProcedureReturn st\wMinute
    CompilerCase #PB_OS_Linux
      Protected.tm *Memory_localtime
      Protected.i  Minute
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerCase #PB_Processor_x64
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
      CompilerEndSelect
      
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        Minute = *Memory_localtime\tm_min
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn Minute
      Else
        ProcedureReturn -1
      EndIf
    CompilerCase #PB_OS_MacOS
      Protected.tm *Memory_localtime
      Protected.i  Minute
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      *Memory_localtime = AllocateMemory(SizeOf(tm))
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        Minute = *Memory_localtime\tm_min
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn Minute
      Else
        ProcedureReturn -1
      EndIf
  CompilerEndSelect
EndProcedure

Procedure.i Second64(Date.q)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      Protected.SYSTEMTIME st
      
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
      
      ProcedureReturn st\wSecond
    CompilerCase #PB_OS_Linux
      Protected.tm *Memory_localtime
      Protected.i  Second
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerCase #PB_Processor_x64
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
      CompilerEndSelect
      
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        Second = *Memory_localtime\tm_sec
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn Second
      Else
        ProcedureReturn -1
      EndIf
    CompilerCase #PB_OS_MacOS
      Protected.tm *Memory_localtime
      Protected.i  Second
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      *Memory_localtime = AllocateMemory(SizeOf(tm))
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        Second = *Memory_localtime\tm_sec
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn Second
      Else
        ProcedureReturn -1
      EndIf
  CompilerEndSelect
EndProcedure

Procedure.i DayOfWeek64(Date.q)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      Protected.SYSTEMTIME st
      
      Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
      FileTimeToSystemTime_(@Date, @st)
      
      ProcedureReturn st\wDayOfWeek
    CompilerCase #PB_OS_Linux
      Protected.tm *Memory_localtime
      Protected.i  DayOfWeek
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerCase #PB_Processor_x64
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
      CompilerEndSelect
      
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        DayOfWeek = *Memory_localtime\tm_wday
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn DayOfWeek
      Else
        ProcedureReturn -1
      EndIf
    CompilerCase #PB_OS_MacOS
      Protected.tm *Memory_localtime
      Protected.i  DayOfWeek
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      *Memory_localtime = AllocateMemory(SizeOf(tm))
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        DayOfWeek = *Memory_localtime\tm_wday
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn DayOfWeek
      Else
        ProcedureReturn -1
      EndIf
  CompilerEndSelect
EndProcedure

Procedure.i DayOfYear64(Date.q)
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      Protected.q TempDate
      
      TempDate = Date64(Year64(Date))
      
      ProcedureReturn (Date - TempDate) / #SecondsInOneDay + 1
    CompilerCase #PB_OS_Linux
      Protected.tm *Memory_localtime
      Protected.i  DayOfYear
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerCase #PB_Processor_x64
          *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
      CompilerEndSelect
      
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        DayOfYear = *Memory_localtime\tm_yday
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn DayOfYear + 1
      Else
        ProcedureReturn -1
      EndIf
    CompilerCase #PB_OS_MacOS
      Protected.tm *Memory_localtime
      Protected.i  DayOfYear
      
      Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
      
      *Memory_localtime = AllocateMemory(SizeOf(tm))
      If *Memory_localtime
        localtime_r_(@Date, *Memory_localtime)
        DayOfYear = *Memory_localtime\tm_yday
        FreeMemory(*Memory_localtime)
        
        ProcedureReturn DayOfYear + 1
      Else
        ProcedureReturn -1
      EndIf
  CompilerEndSelect
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
          Debug "Year: " + Str(Year)
          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
          Debug "Year: " + Str(Year)
          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
          Debug "Month: " + Str(Month)
          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
          Debug "Day: " + Str(Day)
          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
          Debug "Hour: " + Str(Hour)
          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
          Debug "Minute: " + Str(Minute)
          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
          Debug "Second: " + Str(Second)
          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

; ======== Funktionstests ========

Define.i i, Date
Define.q Date64

For i = 1970 To 2038
  Date   = Date  (i, 1, 1, 22, 49, 33)
  Date64 = Date64(i, 1, 1, 22, 49, 33)
  
  If Date <> Date64
    Debug "Date-Unterschied bei Jahr: " + Str(i)
  EndIf
  
  If Year(Date) <> Year64(Date64)
    Debug "Year-Unterschied bei Jahr: " + Str(i)
  EndIf
  
  If Month(Date) <> Month64(Date64)
    Debug "Month-Unterschied bei Jahr: " + Str(i)
  EndIf
  
  If Day(Date) <> Day64(Date64)
    Debug "Day-Unterschied bei Jahr: " + Str(i)
  EndIf
  
  If Hour(Date) <> Hour64(Date64)
    Debug "Hour-Unterschied bei Jahr: " + Str(i)
  EndIf
  
  If Minute(Date) <> Minute64(Date64)
    Debug "Minute-Unterschied bei Jahr: " + Str(i)
  EndIf
  
  If Second(Date) <> Second64(Date64)
    Debug "Second-Unterschied bei Jahr: " + Str(i)
  EndIf
  
  If DayOfWeek(Date) <> DayOfWeek64(Date64)
    Debug "DayOfWeek-Unterschied bei Jahr: " + Str(i)
  EndIf
  
  If DayOfYear(Date) <> DayOfYear64(Date64)
    Debug "DayOfYear-Unterschied bei Jahr: " + Str(i)
  EndIf
Next

; Schaltjahr-Test
Date64 = Date64(2004, 2, 1)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Debug "29 Tage später:"
Date64 = AddDate64(Date64, #PB_Date_Day, 29)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Debug "==================================="
Date64 = Date64(2005, 2, 1)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Debug "29 Tage später:"
Date64 = AddDate64(Date64, #PB_Date_Day, 29)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)

; Überlauf-Test
Date64 = Date64(2004, 3, 31)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Debug "1 Monat später:"
Date64 = AddDate64(Date64, #PB_Date_Month, 1)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)

; Unterlauf-Test
Date64 = Date64(2004, 7, 31)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Debug "1 Monat früher:"
Date64 = AddDate64(Date64, #PB_Date_Month, -1)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)

; Parse Datum
Date64 = ParseDate64("%dd.%mm.%yyyy - %hh:%ii:%ss", "21.05.2013 - 16:47:12")
Debug FormatDate64("%dd.%mm.%yyyy - %hh:%ii:%ss", Date64)
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
Lord
Beiträge: 313
Registriert: 21.01.2008 19:11

Re: Date64 - Unixtime 64bit

Beitrag von Lord »

Hallo sicro!

Mach ich etwas falsch?
Beispiel:

Code: Alles auswählen

date64=Date64(1950, 1, 1)
Debug Date
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Date64=AddDate64(Date, #PB_Date_Year, -100)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Debug "-------------"
date64=Date64(1950, 1, 1)
Debug Date
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Date64=AddDate64(Date, #PB_Date_Year, 100)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Debug "-------------"
date64=Date64(2050, 1, 1)
Debug Date
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Date64=AddDate64(Date, #PB_Date_Year, -100)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Debug "-------------"
date64=Date64(2050, 1, 1)
Debug Date
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Date64=AddDate64(Date, #PB_Date_Year, 100)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Ich erhalte:
Debug hat geschrieben: 2145998973
01.01.1950
01.01.1938
-------------
2145998973
01.01.1950
01.01.2138
-------------
2145998973
01.01.2050
01.01.1938
-------------
2145998973
01.01.2050
01.01.2138
Bild
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Date64 - Unixtime 64bit

Beitrag von Sicro »

Du verwendest zwei unterschiedliche Date-Variablen:
Lord hat geschrieben:date64=Date64(1950, 1, 1)
Debug Date
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Date64=AddDate64(Date, #PB_Date_Year, -100)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Debug "-------------"
date64=Date64(1950, 1, 1)
Debug Date
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Date64=AddDate64(Date, #PB_Date_Year, 100)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Debug "-------------"
date64=Date64(2050, 1, 1)
Debug Date
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Date64=AddDate64(Date, #PB_Date_Year, -100)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Debug "-------------"
date64=Date64(2050, 1, 1)
Debug Date
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
Date64=AddDate64(Date, #PB_Date_Year, 100)
Debug FormatDate64("%dd.%mm.%yyyy", Date64)
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
Lord
Beiträge: 313
Registriert: 21.01.2008 19:11

Re: Date64 - Unixtime 64bit

Beitrag von Lord »

Hallo Sicro!

Da kann man nur eines dazu sagen:
"Kartoffeln auf den Augen!" :oops:
Bild
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Date64 - Unixtime 64bit

Beitrag von Sicro »

Ich habe den Code nun auch mal in ein Modul umgeschrieben:

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.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
  ; == 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
          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
        EndStructure
      EndIf
    CompilerCase #PB_OS_MacOS
      If Not Defined(tm, #PB_Structure)
        Structure tm
          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   ; Offset von UTC in Sekunden
        EndStructure
      EndIf
  CompilerEndSelect
    
  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)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #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
      CompilerCase #PB_OS_Linux
        Protected.tm tm
        Protected.q time
               
        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
         
          ; 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
            CompilerSelect #PB_Compiler_Processor
              CompilerCase #PB_Processor_x86
                *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
              CompilerCase #PB_Processor_x64
                *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
            CompilerEndSelect
           
            If *Memory_localtime
              localtime_r_(@time, *Memory_localtime) ; Per Memory ist es thread-sicher
              time = mktime_(*Memory_localtime)
              FreeMemory(*Memory_localtime)
              If time > -1
                ProcedureReturn time
              EndIf
            EndIf
          EndIf
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm tm
        Protected.q time
               
        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
         
          ; 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)
              FreeMemory(*Memory_localtime)
              If time > -1
                ProcedureReturn time
              EndIf
            EndIf
          EndIf
        EndIf
    CompilerEndSelect
  EndProcedure
  
  Procedure.i Year64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
   
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
     
        ProcedureReturn st\wYear
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  Year
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        CompilerSelect #PB_Compiler_Processor
          CompilerCase #PB_Processor_x86
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
          CompilerCase #PB_Processor_x64
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerEndSelect
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Year = *Memory_localtime\tm_year + 1900
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Year
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  Year
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Year = *Memory_localtime\tm_year + 1900
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Year
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
  
  Procedure.i Month64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wMonth
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  Month
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        CompilerSelect #PB_Compiler_Processor
          CompilerCase #PB_Processor_x86
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
          CompilerCase #PB_Processor_x64
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerEndSelect
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Month = *Memory_localtime\tm_mon + 1
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Month
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  Month
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Month = *Memory_localtime\tm_mon + 1
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Month
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
  
  Procedure.i Day64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wDay
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  Day
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        CompilerSelect #PB_Compiler_Processor
          CompilerCase #PB_Processor_x86
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
          CompilerCase #PB_Processor_x64
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerEndSelect
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Day = *Memory_localtime\tm_mday
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Day
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  Day
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Day = *Memory_localtime\tm_mday
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Day
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
  
  Procedure.i Hour64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wHour
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  Hour
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        CompilerSelect #PB_Compiler_Processor
          CompilerCase #PB_Processor_x86
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
          CompilerCase #PB_Processor_x64
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerEndSelect
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Hour = *Memory_localtime\tm_hour
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Hour
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  Hour
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Hour = *Memory_localtime\tm_hour
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Hour
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
  
  Procedure.i Minute64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wMinute
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  Minute
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        CompilerSelect #PB_Compiler_Processor
          CompilerCase #PB_Processor_x86
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
          CompilerCase #PB_Processor_x64
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerEndSelect
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Minute = *Memory_localtime\tm_min
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Minute
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  Minute
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Minute = *Memory_localtime\tm_min
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Minute
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
  
  Procedure.i Second64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wSecond
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  Second
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        CompilerSelect #PB_Compiler_Processor
          CompilerCase #PB_Processor_x86
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
          CompilerCase #PB_Processor_x64
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerEndSelect
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Second = *Memory_localtime\tm_sec
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Second
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  Second
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Second = *Memory_localtime\tm_sec
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Second
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
  
  Procedure.i DayOfWeek64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wDayOfWeek
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  DayOfWeek
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        CompilerSelect #PB_Compiler_Processor
          CompilerCase #PB_Processor_x86
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
          CompilerCase #PB_Processor_x64
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerEndSelect
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          DayOfWeek = *Memory_localtime\tm_wday
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn DayOfWeek
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  DayOfWeek
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          DayOfWeek = *Memory_localtime\tm_wday
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn DayOfWeek
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
  
  Procedure.i DayOfYear64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.q TempDate
       
        TempDate = Date64(Year64(Date))
       
        ProcedureReturn (Date - TempDate) / #SecondsInOneDay + 1
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  DayOfYear
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        CompilerSelect #PB_Compiler_Processor
          CompilerCase #PB_Processor_x86
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 8)  ; Wenn keine 8 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
          CompilerCase #PB_Processor_x64
            *Memory_localtime = AllocateMemory(SizeOf(tm) + 20) ; Wenn keine 20 Bytes zusätzlich reserviert werden, kommt ein Überlauf. Struktur falsch?
        CompilerEndSelect
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          DayOfYear = *Memory_localtime\tm_yday
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn DayOfYear + 1
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  DayOfYear
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          DayOfYear = *Memory_localtime\tm_yday
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn DayOfYear + 1
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  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
            Debug "Year: " + Str(Year)
            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
            Debug "Year: " + Str(Year)
            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
            Debug "Month: " + Str(Month)
            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
            Debug "Day: " + Str(Day)
            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
            Debug "Hour: " + Str(Hour)
            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
            Debug "Minute: " + Str(Minute)
            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
            Debug "Second: " + Str(Second)
            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
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
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 »

Danke Sicro :allright:

Hab jetzt noch kleinere Anpassungen vorgenommen, vor allem die Structure für Linux und Mac angepasst.
Unter MacOS sollte noch mal jemand testen, der die Möglichkeit hat, bei mir läuft es unter Win und Lin in
allen Modi.

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.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_MacOS
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
      CompilerError "32-Bit not supported on MacOS"
    CompilerEndIf
  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_Windows
    CompilerDefault
      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
  CompilerEndSelect
 
  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)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #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
      CompilerCase #PB_OS_Linux
        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
         
          ; 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)
              FreeMemory(*Memory_localtime)
              If time > -1
                ProcedureReturn time
              EndIf
            EndIf
          EndIf
        EndIf
      CompilerCase #PB_OS_MacOS
        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
         
          ; 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)
              FreeMemory(*Memory_localtime)
              If time > -1
                ProcedureReturn time
              EndIf
            EndIf
          EndIf
        EndIf
    CompilerEndSelect
  EndProcedure
 
  Procedure.i Year64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wYear
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  Year
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Year = *Memory_localtime\tm_year + 1900
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Year
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  Year
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Year = *Memory_localtime\tm_year + 1900
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Year
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
 
  Procedure.i Month64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wMonth
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  Month
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
        *Memory_localtime = AllocateMemory(SizeOf(tm))

        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Month = *Memory_localtime\tm_mon + 1
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Month
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  Month
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Month = *Memory_localtime\tm_mon + 1
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Month
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
 
  Procedure.i Day64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wDay
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  Day
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
        *Memory_localtime = AllocateMemory(SizeOf(tm))
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Day = *Memory_localtime\tm_mday
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Day
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  Day
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Day = *Memory_localtime\tm_mday
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Day
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
 
  Procedure.i Hour64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wHour
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  Hour
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
        *Memory_localtime = AllocateMemory(SizeOf(tm))
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Hour = *Memory_localtime\tm_hour
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Hour
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  Hour
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Hour = *Memory_localtime\tm_hour
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Hour
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
 
  Procedure.i Minute64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wMinute
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  Minute
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
        *Memory_localtime = AllocateMemory(SizeOf(tm))
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Minute = *Memory_localtime\tm_min
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Minute
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  Minute
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Minute = *Memory_localtime\tm_min
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Minute
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
 
  Procedure.i Second64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wSecond
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  Second
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Second = *Memory_localtime\tm_sec
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Second
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  Second
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          Second = *Memory_localtime\tm_sec
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn Second
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
 
  Procedure.i DayOfWeek64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.SYSTEMTIME st
       
        Date = Date * #HundredNanosecondsInOneSecond + #HundredNanosecondsFrom_1Jan1601_To_1Jan1970
        FileTimeToSystemTime_(@Date, @st)
       
        ProcedureReturn st\wDayOfWeek
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  DayOfWeek
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          DayOfWeek = *Memory_localtime\tm_wday
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn DayOfWeek
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  DayOfWeek
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          DayOfWeek = *Memory_localtime\tm_wday
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn DayOfWeek
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  EndProcedure
 
  Procedure.i DayOfYear64(Date.q)
    CompilerSelect #PB_Compiler_OS
      CompilerCase #PB_OS_Windows
        Protected.q TempDate
       
        TempDate = Date64(Year64(Date))
       
        ProcedureReturn (Date - TempDate) / #SecondsInOneDay + 1
      CompilerCase #PB_OS_Linux
        Protected.tm *Memory_localtime
        Protected.i  DayOfYear
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
       
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          DayOfYear = *Memory_localtime\tm_yday
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn DayOfYear + 1
        Else
          ProcedureReturn -1
        EndIf
      CompilerCase #PB_OS_MacOS
        Protected.tm *Memory_localtime
        Protected.i  DayOfYear
       
        Date - #SecondsInOneHour ; Hinzugerechnete Stunde wieder abziehen
       
        *Memory_localtime = AllocateMemory(SizeOf(tm))
        If *Memory_localtime
          localtime_r_(@Date, *Memory_localtime)
          DayOfYear = *Memory_localtime\tm_yday
          FreeMemory(*Memory_localtime)
         
          ProcedureReturn DayOfYear + 1
        Else
          ProcedureReturn -1
        EndIf
    CompilerEndSelect
  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
            Debug "Year: " + Str(Year)
            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
            Debug "Year: " + Str(Year)
            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
            Debug "Month: " + Str(Month)
            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
            Debug "Day: " + Str(Day)
            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
            Debug "Hour: " + Str(Hour)
            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
            Debug "Minute: " + Str(Minute)
            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
            Debug "Second: " + Str(Second)
            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
 
  For jahr = 1970 To 2038 Step 1
    d1.s = FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date(jahr,3,1,0,0,0))
    d2.s = FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64(jahr,3,1,0,0,0))
    If d1 <> d2
      Debug d1
      Debug d2
      Debug ""
    EndIf
  Next
 
  Debug DayOfWeek(Date())
  Debug DayOfWeek64(Date64())
  Debug ""
  Debug FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date(1600,1,1,0,0,0))
  Debug FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64(2300,1,1,0,0,0))
  Debug FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date(1971,8,20,0,0,0))
  Debug FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64(1971,8,20))
  Debug FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date())
  Debug FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64())
CompilerEndIf 
Gruß
Thomas
Zuletzt geändert von ts-soft am 24.03.2014 09:13, insgesamt 2-mal geändert.
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
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Date64 - Unixtime 64bit

Beitrag von Danilo »

ts-soft hat geschrieben:Hab jetzt noch kleinere Anpassungen vorgenommen, vor allem die Structure für Linux und Mac angepasst.
Unter MacOS sollte noch mal jemand testen, der die Möglichkeit hat, bei mir läuft es unter Win und Lin in allen Modi.
In der Procedure Date64 fehlte ein 'Protected *Memory_localtime' für Mac OS X. Habe es als Zeile 200 eingefügt.

Die Zeilen 197 bis 202:

Code: Alles auswählen

      CompilerCase #PB_OS_MacOS
        Protected.tm tm
        Protected.q time
        Protected *Memory_localtime ; Hinzugefügt
        
        If Year > -1 ; Gültiges Datum
Danach lief es.

Ausgabe mit PB 32bit auf Mac OS X:

Code: Alles auswählen

1969.12.31 23:59:59
1970.01.01 00:59:59

1
1

1969.12.31 23:59:59
1970.01.01 00:59:59
1971.08.20 00:00:00
1971.08.20 00:00:00
2014.03.24 07:27:19
2014.03.24 06:27:19
Ausgabe mit PB 64bit auf Mac OS X:

Code: Alles auswählen

1969.12.31 23:59:59
2038.03.01 00:00:00

1
1

1969.12.31 23:59:59
2300.01.01 00:00:00
1971.08.20 00:00:00
1971.08.20 00:00:00
2014.03.24 07:30:02
2014.03.24 06:30:02
Habe es jetzt nicht weiter angeschaut, aber scheint wohl nur mit 64bit brauchbar zu sein.
Wenn dem so ist, wäre es wohl besser einen CompilerError einzufügen, wenn man PB 32bit verwendet.

Aber:

Code: Alles auswählen

  Debug FormatDate("%yyyy.%mm.%dd %hh:%ii:%ss", Date(1600,1,1,0,0,0))
  Debug FormatDate64("%yyyy.%mm.%dd %hh:%ii:%ss", Date64(1600,1,1,0,0,0))
Ausgabe mit PB 64bit auf Mac OS X:

Code: Alles auswählen

1969.12.31 23:59:59
1970.01.01 00:59:59
Da stimmt etwas noch nicht mit kleinen Jahreszahlen. 2300 funktioniert aber.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
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 »

Danke Danilo fürs testen :allright:

Hab jetzt im obigen Code die fehlende Deklaration für MacOS eingefügt, sowie den CompilerError für MacOS 32-Bit.

Gruß
Thomas
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
Antworten