Windows: use native Win32 API for dates
Allows conversion of negative "seconds" to reach dates before 1970, and fixes year-varying DST tracking for versions of Windows that know about those details. As far as I can tell, we have to compute ourselves whether a date is in daylight-saving time based on specifications of when daylight and standard times start. That part seems tricky and could use extra review.
This commit is contained in:
parent
816d09bb24
commit
135ccf094e
|
@ -579,9 +579,7 @@
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# define TIME_SYNTAX
|
# define TIME_SYNTAX
|
||||||
# define USE_FTIME
|
# define USE_WIN32_TIME
|
||||||
# define USE_TIMEZONE_VAR_W_DLS
|
|
||||||
# define USE_TZNAME_VAR
|
|
||||||
# define WINDOWS_GET_PROCESS_TIMES
|
# define WINDOWS_GET_PROCESS_TIMES
|
||||||
# define GETENV_FUNCTION
|
# define GETENV_FUNCTION
|
||||||
# define DIR_FUNCTION
|
# define DIR_FUNCTION
|
||||||
|
@ -991,6 +989,8 @@
|
||||||
|
|
||||||
/* USE_MACTIME uses the Mac toolbox to implement time functions. */
|
/* USE_MACTIME uses the Mac toolbox to implement time functions. */
|
||||||
|
|
||||||
|
/* USE_WIN32_TIME uses the Win32 API to implement time functions. */
|
||||||
|
|
||||||
/* CLOCK_IS_USER_TIME uses the system time for user milliseconds. */
|
/* CLOCK_IS_USER_TIME uses the system time for user milliseconds. */
|
||||||
|
|
||||||
/* USER_TIME_IS_CLOCK uses the user time for system milliseconds. */
|
/* USER_TIME_IS_CLOCK uses the user time for system milliseconds. */
|
||||||
|
|
|
@ -36,9 +36,8 @@
|
||||||
/* The implementations of the time primitives, such as
|
/* The implementations of the time primitives, such as
|
||||||
`current-seconds', vary a lot from platform to platform. */
|
`current-seconds', vary a lot from platform to platform. */
|
||||||
#ifdef TIME_SYNTAX
|
#ifdef TIME_SYNTAX
|
||||||
# ifdef USE_MACTIME
|
# ifdef USE_WIN32_TIME
|
||||||
# include <OSUtils.h>
|
# include <Windows.h>
|
||||||
# include <Timer.h>
|
|
||||||
# else
|
# else
|
||||||
# ifndef USE_PALMTIME
|
# ifndef USE_PALMTIME
|
||||||
# if defined(OSKIT) && !defined(OSKIT_TEST)
|
# if defined(OSKIT) && !defined(OSKIT_TEST)
|
||||||
|
@ -217,6 +216,15 @@ typedef void (*DW_PrePost_Proc)(void *);
|
||||||
static void register_traversers(void);
|
static void register_traversers(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_WIN32_TIME
|
||||||
|
typedef BOOL (WINAPI*GetTimeZoneInformationForYearProc_t)(USHORT wYear, void* pdtzi, LPTIME_ZONE_INFORMATION ptzi);
|
||||||
|
static GetTimeZoneInformationForYearProc_t GetTimeZoneInformationForYearProc;
|
||||||
|
|
||||||
|
typedef BOOL (WINAPI*SystemTimeToTzSpecificLocalTimeExProc_t)(void *lpTimeZoneInformation,
|
||||||
|
const SYSTEMTIME *lpUniversalTime,
|
||||||
|
LPSYSTEMTIME lpLocalTime);
|
||||||
|
static SystemTimeToTzSpecificLocalTimeExProc_t SystemTimeToTzSpecificLocalTimeExProc;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* See call_cc: */
|
/* See call_cc: */
|
||||||
typedef struct Scheme_Dynamic_Wind_List {
|
typedef struct Scheme_Dynamic_Wind_List {
|
||||||
|
@ -665,6 +673,20 @@ scheme_init_fun (Scheme_Env *env)
|
||||||
original_default_prompt = MALLOC_ONE_TAGGED(Scheme_Prompt);
|
original_default_prompt = MALLOC_ONE_TAGGED(Scheme_Prompt);
|
||||||
original_default_prompt->so.type = scheme_prompt_type;
|
original_default_prompt->so.type = scheme_prompt_type;
|
||||||
original_default_prompt->tag = scheme_default_prompt_tag;
|
original_default_prompt->tag = scheme_default_prompt_tag;
|
||||||
|
|
||||||
|
#ifdef USE_WIN32_TIME
|
||||||
|
{
|
||||||
|
HMODULE hm;
|
||||||
|
hm = LoadLibrary("kernel32.dll");
|
||||||
|
|
||||||
|
GetTimeZoneInformationForYearProc
|
||||||
|
= (GetTimeZoneInformationForYearProc_t)GetProcAddress(hm, "GetTimeZoneInformationForYear");
|
||||||
|
SystemTimeToTzSpecificLocalTimeExProc
|
||||||
|
= (SystemTimeToTzSpecificLocalTimeExProc_t)GetProcAddress(hm, "SystemTimeToTzSpecificLocalTimeEx");
|
||||||
|
|
||||||
|
FreeLibrary(hm);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -9222,6 +9244,11 @@ static Scheme_Object *jump_to_alt_continuation()
|
||||||
#define CLOCKS_PER_SEC 1000000
|
#define CLOCKS_PER_SEC 1000000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_WIN32_TIME
|
||||||
|
/* Number of milliseconds from 1601 to 1970: */
|
||||||
|
# define MSEC_OFFSET 11644473600000
|
||||||
|
#endif
|
||||||
|
|
||||||
intptr_t scheme_get_milliseconds(void)
|
intptr_t scheme_get_milliseconds(void)
|
||||||
XFORM_SKIP_PROC
|
XFORM_SKIP_PROC
|
||||||
/* this function can be called from any OS thread */
|
/* this function can be called from any OS thread */
|
||||||
|
@ -9234,9 +9261,13 @@ intptr_t scheme_get_milliseconds(void)
|
||||||
MSC_IZE(ftime)(&now);
|
MSC_IZE(ftime)(&now);
|
||||||
return (intptr_t)(now.time * 1000 + now.millitm);
|
return (intptr_t)(now.time * 1000 + now.millitm);
|
||||||
# else
|
# else
|
||||||
# ifdef PALMOS_STUFF
|
# ifdef USE_WIN32_TIME
|
||||||
/* FIXME */
|
FILETIME ft;
|
||||||
return 0;
|
mzlonglong v;
|
||||||
|
GetSystemTimeAsFileTime(&ft);
|
||||||
|
v = ((mzlonglong)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
|
||||||
|
v = (v / 10000) - MSEC_OFFSET;
|
||||||
|
return (intptr_t)v;
|
||||||
# else
|
# else
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
|
@ -9265,9 +9296,13 @@ double scheme_get_inexact_milliseconds(void)
|
||||||
MSC_IZE(ftime)(&now);
|
MSC_IZE(ftime)(&now);
|
||||||
return (double)now.time * 1000.0 + (double)now.millitm;
|
return (double)now.time * 1000.0 + (double)now.millitm;
|
||||||
# else
|
# else
|
||||||
# ifdef PALMOS_STUFF
|
# ifdef USE_WIN32_TIME
|
||||||
/* FIXME */
|
FILETIME ft;
|
||||||
return 0;
|
mzlonglong v;
|
||||||
|
GetSystemTimeAsFileTime(&ft);
|
||||||
|
v = ((mzlonglong)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
|
||||||
|
v -= ((mzlonglong)MSEC_OFFSET) * 10000;
|
||||||
|
return (double)(v / 10000) + (((double)(v % 10000)) / 10000.0);
|
||||||
# else
|
# else
|
||||||
struct timeval now;
|
struct timeval now;
|
||||||
gettimeofday(&now, NULL);
|
gettimeofday(&now, NULL);
|
||||||
|
@ -9312,10 +9347,12 @@ intptr_t scheme_get_process_milliseconds(void)
|
||||||
v = ((((mzlonglong)kr.dwHighDateTime << 32) + kr.dwLowDateTime)
|
v = ((((mzlonglong)kr.dwHighDateTime << 32) + kr.dwLowDateTime)
|
||||||
+ (((mzlonglong)us.dwHighDateTime << 32) + us.dwLowDateTime));
|
+ (((mzlonglong)us.dwHighDateTime << 32) + us.dwLowDateTime));
|
||||||
return (uintptr_t)(v / 10000);
|
return (uintptr_t)(v / 10000);
|
||||||
}
|
} else
|
||||||
|
return 0; /* anything better to do? */
|
||||||
}
|
}
|
||||||
# endif
|
# else
|
||||||
return clock() * 1000 / CLOCKS_PER_SEC;
|
return clock() * 1000 / CLOCKS_PER_SEC;
|
||||||
|
# endif
|
||||||
|
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
@ -9338,11 +9375,8 @@ intptr_t scheme_get_thread_milliseconds(Scheme_Object *thrd)
|
||||||
|
|
||||||
intptr_t scheme_get_seconds(void)
|
intptr_t scheme_get_seconds(void)
|
||||||
{
|
{
|
||||||
#ifdef USE_MACTIME
|
#ifdef USE_WIN32_TIME
|
||||||
/* This is wrong, since it's not since January 1, 1970 */
|
return scheme_get_milliseconds() / 1000;
|
||||||
unsigned long secs;
|
|
||||||
GetDateTime(&secs);
|
|
||||||
return secs;
|
|
||||||
#else
|
#else
|
||||||
# ifdef USE_PALMTIME
|
# ifdef USE_PALMTIME
|
||||||
return TimGetSeconds();
|
return TimGetSeconds();
|
||||||
|
@ -9366,10 +9400,66 @@ intptr_t scheme_get_seconds(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_MACTIME) || defined(USE_PALMTIME)
|
#if defined(USE_WIN32_TIME)
|
||||||
static int month_offsets[12] = { 0, 31, 59, 90,
|
/* Assuming not a leap year (and adjusted elsewhere): */
|
||||||
120, 151, 181, 212,
|
static int month_offsets[13] = { 0, 31, 59, 90,
|
||||||
243, 273, 304, 334 };
|
120, 151, 181, 212,
|
||||||
|
243, 273, 304, 334,
|
||||||
|
365};
|
||||||
|
|
||||||
|
# define dtxCOMP(f) if (a->f < b->f) return 1; if (a->f > b->f) return 0;
|
||||||
|
|
||||||
|
static int is_start_day_before(SYSTEMTIME *a, SYSTEMTIME *b)
|
||||||
|
{
|
||||||
|
dtxCOMP(wYear);
|
||||||
|
|
||||||
|
/* When comparing DST boundaries, we expect to get here,
|
||||||
|
because wYear will be 0 to mean "every year". */
|
||||||
|
|
||||||
|
dtxCOMP(wMonth);
|
||||||
|
|
||||||
|
/* When comparing DST boundaries, it's unlikely that we'll get here,
|
||||||
|
because that would mean that StdT and DST start in the same month. */
|
||||||
|
|
||||||
|
dtxCOMP(wDay); /* for DST boundaires, this is a week number */
|
||||||
|
dtxCOMP(wDayOfWeek);
|
||||||
|
dtxCOMP(wHour);
|
||||||
|
dtxCOMP(wMinute);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_day_before(SYSTEMTIME *a, SYSTEMTIME *b)
|
||||||
|
/* a is a date, and b is a DST boundary spec */
|
||||||
|
{
|
||||||
|
int dos, doc;
|
||||||
|
|
||||||
|
if (b->wYear) {
|
||||||
|
dtxCOMP(wYear);
|
||||||
|
}
|
||||||
|
|
||||||
|
dtxCOMP(wMonth);
|
||||||
|
|
||||||
|
/* "Date" of a Sunday this month, 0 to 6: */
|
||||||
|
dos = ((a->wDay - a->wDayOfWeek) + 7) % 7;
|
||||||
|
/* Date of first b->wDayOfWeek this month, 1 to 7: */
|
||||||
|
doc = (dos + b->wDayOfWeek) % 7;
|
||||||
|
if (doc == 0) doc = 7;
|
||||||
|
/* Date of change this year: */
|
||||||
|
doc = doc + ((b->wDay - 1) * 7);
|
||||||
|
if (doc > (month_offsets[b->wMonth] - month_offsets[b->wMonth-1]))
|
||||||
|
doc -= 7;
|
||||||
|
/* Above assumes that a time change doesn't occur on a leap day! */
|
||||||
|
|
||||||
|
if (a->wDay < doc)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
dtxCOMP(wHour);
|
||||||
|
dtxCOMP(wMinute);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
# undef dtxCOMP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(OS_X) || defined(XONX)) && defined(__x86_64__)
|
#if (defined(OS_X) || defined(XONX)) && defined(__x86_64__)
|
||||||
|
@ -9430,9 +9520,9 @@ static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv)
|
||||||
int get_gmt;
|
int get_gmt;
|
||||||
int hour, min, sec, month, day, year, wday, yday, dst;
|
int hour, min, sec, month, day, year, wday, yday, dst;
|
||||||
long tzoffset;
|
long tzoffset;
|
||||||
#ifdef USE_MACTIME
|
#ifdef USE_WIN32_TIME
|
||||||
# define CHECK_TIME_T unsigned long
|
# define CHECK_TIME_T uintptr_t
|
||||||
DateTimeRec localTime;
|
SYSTEMTIME localTime;
|
||||||
#else
|
#else
|
||||||
# ifdef USE_PALMTIME
|
# ifdef USE_PALMTIME
|
||||||
# define CHECK_TIME_T UInt32
|
# define CHECK_TIME_T UInt32
|
||||||
|
@ -9479,9 +9569,22 @@ static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv)
|
||||||
&& VALID_TIME_RANGE(lnow)) {
|
&& VALID_TIME_RANGE(lnow)) {
|
||||||
int success;
|
int success;
|
||||||
|
|
||||||
#ifdef USE_MACTIME
|
#ifdef USE_WIN32_TIME
|
||||||
SecondsToDate(lnow, &localTime);
|
{
|
||||||
success = 1;
|
mzlonglong nsC;
|
||||||
|
FILETIME ft;
|
||||||
|
nsC = (((mzlonglong)lnow) * 10000000) + ((mzlonglong)MSEC_OFFSET * 10000);
|
||||||
|
ft.dwLowDateTime = nsC & (mzlonglong)0xFFFFFFFF;
|
||||||
|
ft.dwHighDateTime = nsC >> 32;
|
||||||
|
success = FileTimeToSystemTime(&ft, &localTime);
|
||||||
|
if (success && !get_gmt) {
|
||||||
|
SYSTEMTIME t2 = localTime;
|
||||||
|
if (SystemTimeToTzSpecificLocalTimeExProc)
|
||||||
|
success = SystemTimeToTzSpecificLocalTimeExProc(NULL, &t2, &localTime);
|
||||||
|
else
|
||||||
|
success = SystemTimeToTzSpecificLocalTime(NULL, &t2, &localTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
# ifdef USE_PALMTIME
|
# ifdef USE_PALMTIME
|
||||||
TimSecondsToDateTime(lnow, &localTime) ;
|
TimSecondsToDateTime(lnow, &localTime) ;
|
||||||
|
@ -9495,65 +9598,53 @@ static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
#if defined(USE_MACTIME) || defined(USE_PALMTIME)
|
#ifdef USE_WIN32_TIME
|
||||||
# ifdef USE_MACTIME
|
|
||||||
# define mzDOW(localTime) localTime.dayOfWeek - 1
|
|
||||||
# else
|
|
||||||
# define mzDOW(localTime) localTime.weekDay
|
|
||||||
# endif
|
|
||||||
|
|
||||||
hour = localTime.hour;
|
hour = localTime.wHour;
|
||||||
min = localTime.minute;
|
min = localTime.wMinute;
|
||||||
sec = localTime.second;
|
sec = localTime.wSecond;
|
||||||
|
|
||||||
month = localTime.month;
|
month = localTime.wMonth;
|
||||||
day = localTime.day;
|
day = localTime.wDay;
|
||||||
year = localTime.year;
|
year = localTime.wYear;
|
||||||
|
|
||||||
wday = mzDOW(localTime);
|
wday = localTime.wDayOfWeek;
|
||||||
|
yday = month_offsets[localTime.wMonth-1] + day-1;
|
||||||
|
/* leap-year adjustment: */
|
||||||
|
if ((month > 2)
|
||||||
|
&& ((year % 4) == 0)
|
||||||
|
&& (((year % 100) != 0) || ((year % 400) == 0)))
|
||||||
|
yday++;
|
||||||
|
|
||||||
yday = month_offsets[localTime.month - 1] + localTime.day - 1;
|
dst = 0;
|
||||||
/* If month > 2, is it a leap-year? */
|
if (get_gmt) {
|
||||||
if (localTime.month > 2) {
|
tzoffset = 0;
|
||||||
# ifdef USE_MACTIME
|
tzn = "UTC";
|
||||||
unsigned long ttime;
|
} else {
|
||||||
DateTimeRec tester;
|
TIME_ZONE_INFORMATION tz;
|
||||||
|
if (GetTimeZoneInformationForYearProc)
|
||||||
tester.year = localTime.year;
|
GetTimeZoneInformationForYearProc(localTime.wYear, NULL, &tz);
|
||||||
tester.hour = tester.minute = 0;
|
else
|
||||||
tester.second = 1;
|
(void)GetTimeZoneInformation(&tz);
|
||||||
tester.month = 1;
|
if (tz.StandardDate.wMonth) {
|
||||||
tester.day = 60;
|
if (is_start_day_before(&tz.DaylightDate, &tz.StandardDate)) {
|
||||||
DateToSeconds(&tester, &ttime);
|
/* northern hemisphere */
|
||||||
SecondsToDate(ttime, &tester);
|
dst = (!is_day_before(&localTime, &tz.DaylightDate)
|
||||||
if (tester.month == 2)
|
&& is_day_before(&localTime, &tz.StandardDate));
|
||||||
/* It is a leap-year */
|
} else {
|
||||||
yday++;
|
/* southern hemisphere */
|
||||||
# else
|
dst = (is_day_before(&localTime, &tz.StandardDate)
|
||||||
/* PalmOS: */
|
|| !is_day_before(&localTime, &tz.DaylightDate));
|
||||||
if (DaysInMonth(2, year) > 28)
|
}
|
||||||
yday++;
|
}
|
||||||
# endif
|
if (dst) {
|
||||||
|
tzoffset = (tz.Bias + tz.DaylightBias) * -60;
|
||||||
|
tzn = NARROW_PATH(tz.DaylightName);
|
||||||
|
} else {
|
||||||
|
tzoffset = (tz.Bias + tz.StandardBias) * -60;
|
||||||
|
tzn = NARROW_PATH(tz.StandardName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifdef USE_MACTIME
|
|
||||||
{
|
|
||||||
MachineLocation loc;
|
|
||||||
ReadLocation(&loc);
|
|
||||||
|
|
||||||
dst = (loc.u.dlsDelta != 0);
|
|
||||||
|
|
||||||
tzoffset = loc.u.gmtDelta; /* 3-byte value in a long!! */
|
|
||||||
/* Copied from Inside mac: */
|
|
||||||
tzoffset = tzoffset & 0xFFFFFF;
|
|
||||||
if (tzoffset & (0x1 << 23))
|
|
||||||
tzoffset |= 0xFF000000;
|
|
||||||
}
|
|
||||||
# else
|
|
||||||
/* No timezone on PalmOS: */
|
|
||||||
tzoffset = 0;
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
hour = localTime->tm_hour;
|
hour = localTime->tm_hour;
|
||||||
min = localTime->tm_min;
|
min = localTime->tm_min;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user