Here's an example of how your procedures can look on MacOS with support for a bigger date range and also working on x86.
It contains an init procedure to initialize a few global values that would be private to the module.
Code: Select all
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()
Procedure.q Date64(Year.i=-1, Month.i=1, Day.i=1, Hour.i=0, Minute.i=0, Second.i=0)
Protected at.d
If Year > -1
CFCalendarComposeAbsoluteTime(GregorianGMT, @at, "yMdHms", Year, Month, Day, Hour, Minute, Second)
Else
at = CFAbsoluteTimeGetCurrent_()
at + CFTimeZoneGetSecondsFromGMT(TimeZone, at)
EndIf
ProcedureReturn at + 978307200
EndProcedure
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)
Mac_ReturnDatePart("y")
EndProcedure
Procedure.i Month64(Date.q)
Mac_ReturnDatePart("M")
EndProcedure
Procedure.i Day64(Date.q)
Mac_ReturnDatePart("d")
EndProcedure
Procedure.i Hour64(Date.q)
Mac_ReturnDatePart("H")
EndProcedure
Procedure.i Minute64(Date.q)
Mac_ReturnDatePart("m")
EndProcedure
Procedure.i Second64(Date.q)
Mac_ReturnDatePart("s")
EndProcedure
Procedure.i DayOfWeek64(Date.q)
Mac_ReturnDatePart("E")
EndProcedure
Procedure.i DayOfYear64(Date.q)
Mac_ReturnDatePart("D")
EndProcedure
Procedure.q AddDate64(Date.q, Type.i, Value.i)
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
EndProcedure
; Test
Date.q = Date64(1510,2)
Date = AddDate64(Date, #PB_Date_Month, -1)
Debug "Year: " + Str(Year64(Date))
Debug "Month: " + Str(Month64(Date))
Debug "Day: " + Str(Day64(Date))
Debug "Hour: " + Str(Hour64(Date))
Debug "Minute: " + Str(Minute64(Date))
Debug "Second: " + Str(Second64(Date))
Debug "Day of year: " + Str(DayOfYear64(Date))
Debug "Day of week: " + Str(DayOfWeek64(Date))
The same but now using the ICU library (the library could be compiled for Windows and Linux as well).
Code: Select all
#UCAL_GREGORIAN = 1
#UCAL_YEAR = 1
#UCAL_MONTH = 2
#UCAL_WEEK_OF_YEAR = 3
#UCAL_DAY_OF_MONTH = 5
#UCAL_DAY_OF_YEAR = 6
#UCAL_DAY_OF_WEEK = 7
#UCAL_HOUR_OF_DAY = 11
#UCAL_MINUTE = 12
#UCAL_SECOND = 13
#UCAL_ZONE_OFFSET = 15
#UCAL_DST_OFFSET = 16
#UCAL_EXTENDED_YEAR = 19
ImportC "-licucore"
ucal_add(*cal, field, amount.l, *status.Long)
ucal_clear(*cal)
ucal_clone(*cal, *status.Long)
ucal_close(*cal)
ucal_get.l(*cal, field, *status.Long)
ucal_getMillis.d(*cal, *status.Long)
ucal_getNow.d()
ucal_open(*zoneID, len.l, *locale, type, *status.Long)
ucal_setDateTime(*cal, year.l, month.l, date.l, hour.l, minute.l, second.l, *status.Long)
ucal_setMillis(*cal, dateTime.d, *status.Long)
EndImport
Global *cal_GMT, *cal_local
Procedure Date64Init()
Protected status.l, GMT.q = $47004D0054; 'GMT'
*cal_GMT = ucal_open(@GMT, -1, #Null, #UCAL_GREGORIAN, @status); Gregorian GMT
*cal_local = ucal_open(#Null, 0, #Null, #UCAL_GREGORIAN, @status); Gregorian local
ucal_clear(*cal_GMT)
ucal_clear(*cal_local)
EndProcedure
Date64Init()
Procedure.q Date64(Year.i=$7fffffff, Month.i=1, Day.i=1, Hour.i=0, Minute.i=0, Second.i=0)
Protected *cal, status.l, at.d
If Year <> $7fffffff
*cal = ucal_clone(*cal_GMT, @status)
ucal_setDateTime(*cal, Year, Month - 1, Day, Hour, Minute, Second, @status)
at = ucal_getMillis(*cal, @status)
Else
*cal = ucal_clone(*cal_local, @status)
at = ucal_getNow()
ucal_setMillis(*cal, at, @status)
at + ucal_get(*cal, #UCAL_ZONE_OFFSET, @status)
at + ucal_get(*cal, #UCAL_DST_OFFSET, @status)
EndIf
ucal_close(*cal)
ProcedureReturn at * 1e-3
EndProcedure
Macro Mac_ReturnDatePart(Type)
Protected *cal, status.l, datepart.i
*cal = ucal_clone(*cal_GMT, @status)
ucal_setMillis(*cal, Date * 1e3, @status)
CompilerIf Type = #UCAL_MONTH
datepart = ucal_get(*cal, Type, @status) + 1
CompilerElseIf Type = #UCAL_DAY_OF_WEEK
datepart = ucal_get(*cal, Type, @status) - 1
CompilerElse
datepart = ucal_get(*cal, Type, @status)
CompilerEndIf
ucal_close(*cal)
ProcedureReturn datepart
EndMacro
Procedure.i Year64(Date.q)
Mac_ReturnDatePart(#UCAL_EXTENDED_YEAR)
EndProcedure
Procedure.i Month64(Date.q)
Mac_ReturnDatePart(#UCAL_MONTH)
EndProcedure
Procedure.i Day64(Date.q)
Mac_ReturnDatePart(#UCAL_DAY_OF_MONTH)
EndProcedure
Procedure.i Hour64(Date.q)
Mac_ReturnDatePart(#UCAL_HOUR_OF_DAY)
EndProcedure
Procedure.i Minute64(Date.q)
Mac_ReturnDatePart(#UCAL_MINUTE)
EndProcedure
Procedure.i Second64(Date.q)
Mac_ReturnDatePart(#UCAL_SECOND)
EndProcedure
Procedure.i DayOfWeek64(Date.q)
Mac_ReturnDatePart(#UCAL_DAY_OF_WEEK)
EndProcedure
Procedure.i DayOfYear64(Date.q)
Mac_ReturnDatePart(#UCAL_DAY_OF_YEAR)
EndProcedure
Procedure.q AddDate64(Date.q, Type.i, Value.i)
Protected *cal, status.l, at.d
*cal = ucal_clone(*cal_GMT, @status)
ucal_setMillis(*cal, Date * 1e3, @status)
Select Type
Case #PB_Date_Year: ucal_add(*cal, #UCAL_YEAR, Value, @status)
Case #PB_Date_Month: ucal_add(*cal, #UCAL_MONTH, Value, @status)
Case #PB_Date_Week: ucal_add(*cal, #UCAL_DAY_OF_MONTH, Value * 7, @status)
Case #PB_Date_Day: ucal_add(*cal, #UCAL_DAY_OF_MONTH, Value, @status)
Case #PB_Date_Hour: ucal_add(*cal, #UCAL_HOUR_OF_DAY, Value, @status)
Case #PB_Date_Minute: ucal_add(*cal, #UCAL_MINUTE, Value, @status)
Case #PB_Date_Second: ucal_add(*cal, #UCAL_SECOND, Value, @status)
EndSelect
at = ucal_getMillis(*cal, @status)
ucal_close(*cal)
ProcedureReturn at * 1e-3
EndProcedure
; Test
Date.q = Date64(1510,2)
Date = AddDate64(Date, #PB_Date_Month, -1)
Debug "Year: " + Str(Year64(Date))
Debug "Month: " + Str(Month64(Date))
Debug "Day: " + Str(Day64(Date))
Debug "Hour: " + Str(Hour64(Date))
Debug "Minute: " + Str(Minute64(Date))
Debug "Second: " + Str(Second64(Date))
Debug "Day of year: " + Str(DayOfYear64(Date))
Debug "Day of week: " + Str(DayOfWeek64(Date))