1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-07-01 15:00:38 +00:00
QB64-PE/internal/c/time64.c
2022-05-06 13:20:30 -04:00

202 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 <assert.h>
#include <time.h>
#include <windows.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;
}