mirror of
https://github.com/QB64-Phoenix-Edition/QB64pe.git
synced 2024-09-04 11:10:15 +00:00
201 lines
5.4 KiB
C
201 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;
|
|
}
|