Page 1 of 1

DateX::GetLocalDate for all OS

Posted: Tue Jul 25, 2017 5:26 pm
by mk-soft
GetLocalDate returns the date and time as a simple structure.
We can use this for QDate, Date64, etc

Testet with:
- MacOS X86 and X64. Thanks to Wilbert
- Linux X86 and X64
- Window X86 and X64

Update v1.02
- Update structure type year to word

Update v1.03
- Added GetSystemDate(...)

Update v1.04
- Change MacOS GetSystemDate(..). Thanks to Wilbert
- Cleanup code

Code: Select all

;-TOP
; Comment: Get loacl date and time as simple structure
; Author : mk-soft
; Version: v1.04
; Created: 26.07.2016
; Updated: 

; ***************************************************************************************

DeclareModule DateX
  
  Structure sDateTime
    Year.w
    Month.b
    Day.b
    Hour.b
    Minute.b
    Second.b
  EndStructure
  
  Declare GetLocalDate(*DateTime.sDateTime)
  Declare GetSystemDate(*DateTime.sDateTime)
  
EndDeclareModule

Module DateX
  
  EnableExplicit
  
  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_MacOS
      ; Thanks to Wilbert
      ImportC ""
        CFAbsoluteTimeGetCurrent.d()
        CFCalendarCopyCurrent()
        CFCalendarSetTimeZone(*calendar, tz)
        CFCalendarDecomposeAbsoluteTime(*calendar, at.d, componentDesc.p-ascii, *year, *month, *day, *hour, *minute, *second)
        CFTimeZoneCreateWithTimeIntervalFromGMT(*allocator, ti.d)
      EndImport

      Procedure GetLocalDate(*DateTime.sDateTime)
        Protected Year.integer, Month.integer, Day.integer, Hour.integer, Minute.integer, Second.integer
        Protected timeCurrent.d = CFAbsoluteTimeGetCurrent()
        Protected *CurrentCalendar = CFCalendarCopyCurrent()
        CFCalendarDecomposeAbsoluteTime(*CurrentCalendar, timeCurrent, "yMdHms", @Year, @Month, @Day, @Hour, @Minute, @Second)
        CFRelease_(*CurrentCalendar)
        With *DateTime
          \Year = Year\i
          \Month = Month\i
          \Day = Day\i
          \Hour = Hour\i
          \Minute = Minute\i
          \Second = Second\i
        EndWith
      EndProcedure
      
      Procedure GetSystemDate(*DateTime.sDateTime)
        Protected Year.integer, Month.integer, Day.integer, Hour.integer, Minute.integer, Second.integer
        Protected timeCurrent.d
        Protected *CurrentCalendar = CFCalendarCopyCurrent()
        Protected *TimeZoneGMT = CFTimeZoneCreateWithTimeIntervalFromGMT(#Null, 0.0)
        CFCalendarSetTimeZone(*CurrentCalendar, *TimeZoneGMT)
        timeCurrent = CFAbsoluteTimeGetCurrent()
        CFCalendarDecomposeAbsoluteTime(*CurrentCalendar, timeCurrent, "yMdHms", @Year, @Month, @Day, @Hour, @Minute, @Second)
        CFRelease_(*CurrentCalendar)
        CFRelease_(*TimeZoneGMT)
        With *DateTime
          \Year = Year\i
          \Month = Month\i
          \Day = Day\i
          \Hour = Hour\i
          \Minute = Minute\i
          \Second = Second\i
        EndWith
      EndProcedure
      
    CompilerCase #PB_OS_Linux
      
      Structure tm
        tm_sec.l  ;	int	seconds after the minute	0-61*
        tm_min.l  ;	int	minutes after the hour	0-59
        tm_hour.l ;	int	hours since midnight	0-23
        tm_mday.l ;	int	day of the month	1-31
        tm_mon.l  ;	int	months since January	0-11
        tm_year.l ;	int	years since 1900	
        tm_wday.l ;	int	days since Sunday	0-6
        tm_yday.l ;	int	days since January 1	0-365
        tm_isdst.l;	int	Daylight Saving Time flag	
      EndStructure
      
      Procedure GetLocalDate(*DateTime.sDateTime)
        Protected time.i, *timeinfo.tm
        time_(@time)
        *timeinfo = localtime_(@time)
        With *DateTime
          \Year = *timeinfo\tm_year + 1900
          \Month = *timeinfo\tm_mon + 1
          \Day = *timeinfo\tm_mday
          \Hour = *timeinfo\tm_hour
          \Minute = *timeinfo\tm_min
          \Second = *timeinfo\tm_sec
        EndWith
        
      EndProcedure
      
      Procedure GetSystemDate(*DateTime.sDateTime)
        Protected time.i, *timeinfo.tm
        time_(@time)
        *timeinfo = gmtime_(@time)
        With *DateTime
          \Year = *timeinfo\tm_year + 1900
          \Month = *timeinfo\tm_mon + 1
          \Day = *timeinfo\tm_mday
          \Hour = *timeinfo\tm_hour
          \Minute = *timeinfo\tm_min
          \Second = *timeinfo\tm_sec
        EndWith
        
      EndProcedure
      
    CompilerCase #PB_OS_Windows
      
      Procedure GetLocalDate(*DateTime.sDateTime)
        Protected timeinfo.systemtime
        GetLocalTime_(timeinfo)
        With *DateTime
          \Year = timeinfo\wYear
          \Month = timeinfo\wMonth
          \Day = timeinfo\wDay
          \Hour = timeinfo\wHour
          \Minute = timeinfo\wMinute
          \Second = timeinfo\wSecond
        EndWith
      EndProcedure
      
      Procedure GetSystemDate(*DateTime.sDateTime)
        Protected timeinfo.systemtime
        GetSystemTime_(timeinfo)
        With *DateTime
          \Year = timeinfo\wYear
          \Month = timeinfo\wMonth
          \Day = timeinfo\wDay
          \Hour = timeinfo\wHour
          \Minute = timeinfo\wMinute
          \Second = timeinfo\wSecond
        EndWith
      EndProcedure
      
  CompilerEndSelect
  
  ; -----------------------------------------------------------------------------------
  
EndModule

; ***************************************************************************************

CompilerIf #PB_Compiler_IsMainFile
  
  ;-Test
  
  Define DateTime.DateX::sDateTime
  
  DateX::GetLocalDate(DateTime)
  Debug "*** Local Date ***"
  With DateTime
    Debug "Year: " + Str(\year)
    Debug "Month: " + Str(\month)
    Debug "Day: " + Str(\day)
    Debug "Hour: " + Str(\hour)
    Debug "Minute: " + Str(\minute)
    Debug "Second: " + Str(\second)
  EndWith
  
  DateX::GetSystemDate(DateTime)
  Debug "*** System Date ***"
  With DateTime
    Debug "Year: " + Str(\year)
    Debug "Month: " + Str(\month)
    Debug "Day: " + Str(\day)
    Debug "Hour: " + Str(\hour)
    Debug "Minute: " + Str(\minute)
    Debug "Second: " + Str(\second)
  EndWith
  
CompilerEndIf

Re: DateX::GetLocalDate for all OS

Posted: Tue Jul 25, 2017 6:34 pm
by Little John
mk-soft wrote:GetLocalDate returns the date and time as a simple structure.
Another way to do the same, not surprisingly also cross-platform. ;-)

Code: Select all

EnableExplicit

Structure DateTime
   Year.w
   Month.b
   Day.b
   Hour.b
   Minute.b
   Second.b
EndStructure

Procedure GetDateTime (*dt.DateTime)
   Protected now.i = Date()
   
   With *dt
      \Year   = Year(now)
      \Month  = Month(now)
      \Day    = Day(now)
      \Hour   = Hour(now)
      \Minute = Minute(now)
      \Second = Second(now)
   EndWith
EndProcedure


;-- Demo
Define now.DateTime

GetDateTime(now)

With now
   Debug "Year  : " + \Year
   Debug "Month : " + \Month
   Debug "Day   : " + \Day
   Debug "Hour  : " + \Hour
   Debug "Minute: " + \Minute
   Debug "Second: " + \Second
EndWith

Re: DateX::GetLocalDate for all OS

Posted: Tue Jul 25, 2017 7:07 pm
by Sicro
Nice, that we now have a working solution for MacOS.

The Linux code does not use thread-safe functions. Look into the Date64 code for thread-safe functions.

But why do not we all work together and create one complete date library with extended date range.
Little John wrote:Another way to do the same, not surprisingly also cross-platform.
-- code --
Your code uses the PB-Date library and therefore has the same date limits.

Edit: Code removed from the quote.

Re: DateX::GetLocalDate for all OS

Posted: Tue Jul 25, 2017 7:24 pm
by Little John
Sicro wrote:
Little John wrote:<Almost full quote not quoted again.>
Your code uses the PB-Date library and therefore has the same date limits.
These codes are not for date calculations, but for yielding the current date and time.
When a program should be compiled now or in the near future, and is supposed not to be re-compiled until 19.01.2038, then it certainly would be advantageous to use mk-soft's code. Otherwise, people (especially beginners) might like using a simpler code that only utilises built-in PB functions.

Re: DateX::GetLocalDate for all OS

Posted: Tue Jul 25, 2017 7:47 pm
by mk-soft
I've lost my way ...
The year should be a type word

Update v1.02
- Bugfix

Update v1.03
- Added GetSystemDate(...)

Small trick with MacOS. Perhaps find a better way...

P.S.
Or the type for the year should be a long?

Re: DateX::GetLocalDate for all OS

Posted: Tue Jul 25, 2017 8:57 pm
by Sicro
Little John wrote:These codes are not for date calculations, but for yielding the current date and time.
Yes, I know that, of course.
In the first post, however, mk-soft mentions "QDate" and "Date64" and so I strongly believe that with his code, he wants to enrich the existing codes that perform date calculations.

I did not say your code is useless.

Re: DateX::GetLocalDate for all OS

Posted: Wed Jul 26, 2017 1:25 am
by Little John
Sicro wrote:
Little John wrote:These codes are not for date calculations, but for yielding the current date and time.
Yes, I know that, of course.
In the first post, however, mk-soft mentions "QDate" and "Date64"
Yes, I know.
Anyway, as I wrote, the limit of PB's built-in function for the current date will not be reached until 19.01.2038 -- regardless for what purpose the current date will be used.

Re: DateX::GetLocalDate for all OS

Posted: Wed Jul 26, 2017 8:36 am
by walbus
Thanks for sharing

Re: DateX::GetLocalDate for all OS

Posted: Wed Jul 26, 2017 9:00 am
by wilbert
mk-soft wrote:Update v1.03
- Added GetSystemDate(...)

Small trick with MacOS. Perhaps find a better way...
You can set the timezone of the calendar to GMT but it's about the same amount of code so maybe not really a better way.

Code: Select all

ImportC ""
  CFCalendarCopyCurrent()
  CFCalendarDecomposeAbsoluteTime(calendar, at.d, componentDesc.p-ascii, 
                                  *year, *month, *day, *hour, *min, *sec)
  CFCalendarSetTimeZone(calendar, tz)
  CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ti.d)
EndImport

CurrentCalendar.i = CFCalendarCopyCurrent()
TimeZoneGMT.i = CFTimeZoneCreateWithTimeIntervalFromGMT(#Null, 0)
CFCalendarSetTimeZone(CurrentCalendar, TimeZoneGMT)
CFCalendarDecomposeAbsoluteTime(CurrentCalendar, CFAbsoluteTimeGetCurrent_(), "yMdHms", 
                                @year, @month, @day, @hour, @min, @sec)
CFRelease_(TimeZoneGMT)
CFRelease_(CurrentCalendar)

Debug "Year: " + Str(year)
Debug "Month: " + Str(month)
Debug "Day: " + Str(day)
Debug "Hour: " + Str(hour)
Debug "Minute: " + Str(min)
Debug "Second: " + Str(sec)

Re: DateX::GetLocalDate for all OS

Posted: Wed Jul 26, 2017 5:09 pm
by Sicro
Little John wrote:Anyway, as I wrote, the limit of PB's built-in function for the current date will not be reached until 19.01.2038 -- regardless for what purpose the current date will be used.
I understand you very well.

2038 - 2017 = 21 years
Perhaps it's silly to think of a program that would be in use after compiling so long. I have however experienced that some companies use their programs for a very long time. Some companies still use DOS programs for their warehouse management.

As I see here we have the same opinion:
Little John wrote:When a program should be compiled now or in the near future, and is supposed not to be re-compiled until 19.01.2038, then it certainly would be advantageous to use mk-soft's code.
Now we are back at my real question from above:
Sicro wrote:But why do not we all work together and create one complete date library with extended date range.

Re: DateX::GetLocalDate for all OS

Posted: Wed Jul 26, 2017 8:42 pm
by mk-soft
Update v1.04
- Change MacOS GetSystemDate(..). Thanks to Wilbert
- Cleanup code

@Wilbert,
I think your code is better :wink:

@All,
The problem is which basis for the sequential time for Purebasic take.
Windows automation takes Double as days, Mac is Double in seconds, Linux takes whole numbers.
Have not found an alternative for 'time _ (...) and' localtime (...) for Linux yet.

(Sorry, goggle translator)

Re: DateX::GetLocalDate for all OS

Posted: Thu Jul 27, 2017 5:23 am
by wilbert
mk-soft wrote:The problem is which basis for the sequential time for Purebasic take.
Windows automation takes Double as days, Mac is Double in seconds, Linux takes whole numbers.
I'm not exactly sure what you mean by the PureBasic sequential time. :?

Re: DateX::GetLocalDate for all OS

Posted: Thu Jul 27, 2017 7:25 am
by mk-soft
I mean internal timeformat for Purebasic. Sorry, my english :(

I think double for seconds since jear x.

P.S.
We can simple calculate to
- MacOS : Jan 1 2001 00:00:00 GMT; Double; Resulution 1 sencond
- Windows Filetime: January 1, 1601; Quad; Resulution 100 nanoseconds
- Windows Variant VT_Date: January 1, 100; Double; Resulution Days and part of day
- Linux: Unix time format or other

Re: DateX::GetLocalDate for all OS

Posted: Thu Jul 27, 2017 9:13 am
by wilbert
mk-soft wrote:MacOS : Jan 1 2001 00:00:00 GMT; Double; Resulution 1 second
According to what I read online, the resolution is microseconds (it's based on gettimeofday).

Code: Select all

Structure timeval
  tv_sec.i
  tv_usec.l
EndStructure

gettimeofday_(@t.timeval, #Null)
at.d = 1e-6 * t\tv_usec + t\tv_sec - 978307200

Debug at; same as CFAbsoluteTimeGetCurrent_()