mirror of
https://github.com/QB64Official/qb64.git
synced 2024-09-28 11:17:47 +00:00
211 lines
5.4 KiB
C
211 lines
5.4 KiB
C
/* Copyright (c) Robert Walker, support@tunesmithy.co.uk
|
|
* Free source. Do what you wish with it - treat it as you would
|
|
* example code in a book on c programming.
|
|
*/
|
|
#include "time64.h"
|
|
#undef time
|
|
#undef localtime
|
|
#undef mktime
|
|
#undef difftime
|
|
#undef gmtime
|
|
#undef time_t
|
|
|
|
#include <time.h>
|
|
#include <windows.h>
|
|
#include <assert.h>
|
|
|
|
#define SECS_TO_FT_MULT 10000000
|
|
#ifdef _DEBUG
|
|
#define DEBUG_TIME_T
|
|
#endif
|
|
|
|
/* From MSVC help:
|
|
* The gmtime, mktime, and localtime functions use the same single,
|
|
* statically allocated structure to hold their results. Each call to
|
|
* one of these functions destroys the result of any previous call.
|
|
* If timer represents a date before midnight, January 1, 1970,
|
|
* gmtime returns NULL. There is no error return.
|
|
*
|
|
* So here is the struct to use for our 64 bit implementation
|
|
*
|
|
* However, it may be useful to be able to make this thread safe
|
|
*/
|
|
|
|
#ifdef USE_THREAD_LOCAL_VARIABLES
|
|
#define TIME64_THREAD_LOCAL _declspec(thread)
|
|
#else
|
|
#define TIME64_THREAD_LOCAL
|
|
#endif
|
|
|
|
TIME64_THREAD_LOCAL static struct tm today_ret;
|
|
|
|
static void T64ToFileTime(t64 *pt,FILETIME *pft)
|
|
{
|
|
LARGE_INTEGER li;
|
|
li.QuadPart=*pt*SECS_TO_FT_MULT;
|
|
pft->dwLowDateTime=li.LowPart;
|
|
pft->dwHighDateTime=li.HighPart;
|
|
}
|
|
|
|
static void FileTimeToT64(FILETIME *pft,t64 *pt)
|
|
{
|
|
LARGE_INTEGER li;
|
|
li.LowPart = pft->dwLowDateTime;
|
|
li.HighPart = pft->dwHighDateTime;
|
|
*pt=li.QuadPart;
|
|
*pt/=SECS_TO_FT_MULT;
|
|
}
|
|
|
|
//#define FindTimeTBase() ((t64) 11644473600)
|
|
#define FindTimeTBase() (((__int64)11644)*1000000+473600)
|
|
|
|
// calculated using
|
|
/**
|
|
static t64 FindTimeTBase(void)
|
|
{
|
|
// Find 1st Jan 1970 as a FILETIME
|
|
SYSTEMTIME st;
|
|
FILETIME ft;
|
|
memset(&st,0,sizeof(st));
|
|
st.wYear=1970;
|
|
st.wMonth=1;
|
|
st.wDay=1;
|
|
SystemTimeToFileTime(&st, &ft);
|
|
FileTimeToT64(&ft,&tbase);
|
|
return tbase;
|
|
}
|
|
**/
|
|
|
|
static void SystemTimeToT64(SYSTEMTIME *pst,t64 *pt)
|
|
{
|
|
FILETIME ft;
|
|
SystemTimeToFileTime(pst, &ft);
|
|
FileTimeToT64(&ft,pt);
|
|
*pt-=FindTimeTBase();
|
|
}
|
|
|
|
|
|
static void T64ToSystemTime(t64 *pt,SYSTEMTIME *pst)
|
|
{
|
|
FILETIME ft;
|
|
t64 t=*pt;
|
|
t+=FindTimeTBase();
|
|
T64ToFileTime(&t,&ft);
|
|
FileTimeToSystemTime(&ft,pst);
|
|
}
|
|
|
|
|
|
t64 time_64(t64 *pt)
|
|
{
|
|
t64 t;
|
|
SYSTEMTIME st;
|
|
GetSystemTime(&st);
|
|
SystemTimeToT64(&st,&t);
|
|
#ifdef DEBUG_TIME_T
|
|
{
|
|
time_t t2=time(NULL);
|
|
if(t2>=0)
|
|
|
|
//2005 assert(abs(t2-(int)t)<=1);
|
|
assert(abs((long)(t2-(int)t))<=1);
|
|
|
|
// the <=1 here is in case the seconds get incremented
|
|
// betweeen the GetSystemTime(..) call and the time(..) call
|
|
}
|
|
#endif
|
|
if(pt)
|
|
*pt=t;
|
|
return t;
|
|
}
|
|
|
|
double difftime_64(t64 time1, t64 time0)
|
|
{
|
|
return (double)(time1-time0);
|
|
}
|
|
|
|
t64 mktime64( struct tm *today )
|
|
{
|
|
t64 t;
|
|
SYSTEMTIME st;
|
|
st.wDay=(WORD)today->tm_mday;
|
|
st.wDayOfWeek=(WORD)today->tm_wday;
|
|
st.wHour=(WORD)today->tm_hour;
|
|
st.wMinute=(WORD)today->tm_min;
|
|
st.wMonth=(WORD)(today->tm_mon+1);
|
|
st.wSecond=(WORD)today->tm_sec;
|
|
st.wYear=(WORD)(today->tm_year+1900);
|
|
st.wMilliseconds=0;
|
|
SystemTimeToT64(&st,&t);
|
|
return t;
|
|
}
|
|
|
|
#define DAY_IN_SECS (60*60*24)
|
|
struct tm *gmtime_64(t64 t)
|
|
{
|
|
SYSTEMTIME st;
|
|
T64ToSystemTime(&t,&st);
|
|
today_ret.tm_wday=st.wDayOfWeek;
|
|
today_ret.tm_min=st.wMinute;
|
|
today_ret.tm_sec=st.wSecond;
|
|
today_ret.tm_mon=st.wMonth-1;
|
|
today_ret.tm_mday=st.wDay;
|
|
today_ret.tm_hour=st.wHour;
|
|
today_ret.tm_year=st.wYear-1900;
|
|
{
|
|
SYSTEMTIME styear;
|
|
t64 t64Year;
|
|
memset(&styear,0,sizeof(styear));
|
|
styear.wYear=st.wYear;
|
|
styear.wMonth=1;
|
|
styear.wDay=1;
|
|
SystemTimeToT64(&styear,&t64Year);
|
|
today_ret.tm_yday=(int)((t-t64Year)/DAY_IN_SECS);
|
|
}
|
|
today_ret.tm_isdst=0;
|
|
#ifdef DEBUG_TIME_T
|
|
{
|
|
struct tm today2;
|
|
long t32=(int)t;
|
|
if(t32>=0)
|
|
{
|
|
//2005 today2=*gmtime(&t32);
|
|
today2=*gmtime((time_t*)&t32);
|
|
|
|
assert(today_ret.tm_yday==today2.tm_yday);
|
|
assert(today_ret.tm_wday==today2.tm_wday);
|
|
assert(today_ret.tm_min==today2.tm_min);
|
|
assert(today_ret.tm_sec==today2.tm_sec);
|
|
assert(today_ret.tm_mon==today2.tm_mon);
|
|
assert(today_ret.tm_mday==today2.tm_mday);
|
|
assert(today_ret.tm_hour==today2.tm_hour);
|
|
assert(today_ret.tm_year==today2.tm_year);
|
|
}
|
|
}
|
|
{
|
|
t64 t2=mktime64(&today_ret);
|
|
assert(t2==t);
|
|
}
|
|
#endif
|
|
return &today_ret;
|
|
}
|
|
|
|
struct tm *localtime_64(t64 *pt)
|
|
{
|
|
t64 t=*pt;
|
|
FILETIME ft,ftlocal;
|
|
T64ToFileTime(&t,&ft);
|
|
FileTimeToLocalFileTime(&ft,&ftlocal);
|
|
FileTimeToT64(&ftlocal,&t);
|
|
today_ret=*gmtime_64(t);
|
|
{
|
|
TIME_ZONE_INFORMATION TimeZoneInformation;
|
|
switch(GetTimeZoneInformation(&TimeZoneInformation))
|
|
{
|
|
case TIME_ZONE_ID_DAYLIGHT:today_ret.tm_isdst=1;break;
|
|
case TIME_ZONE_ID_STANDARD:today_ret.tm_isdst=0;break;
|
|
case TIME_ZONE_ID_UNKNOWN:today_ret.tm_isdst=-1;break;
|
|
}
|
|
}
|
|
return &today_ret;
|
|
}
|
|
|