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
|
||||
|
||||
# define TIME_SYNTAX
|
||||
# define USE_FTIME
|
||||
# define USE_TIMEZONE_VAR_W_DLS
|
||||
# define USE_TZNAME_VAR
|
||||
# define USE_WIN32_TIME
|
||||
# define WINDOWS_GET_PROCESS_TIMES
|
||||
# define GETENV_FUNCTION
|
||||
# define DIR_FUNCTION
|
||||
|
@ -991,6 +989,8 @@
|
|||
|
||||
/* 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. */
|
||||
|
||||
/* USER_TIME_IS_CLOCK uses the user time for system milliseconds. */
|
||||
|
|
|
@ -36,9 +36,8 @@
|
|||
/* The implementations of the time primitives, such as
|
||||
`current-seconds', vary a lot from platform to platform. */
|
||||
#ifdef TIME_SYNTAX
|
||||
# ifdef USE_MACTIME
|
||||
# include <OSUtils.h>
|
||||
# include <Timer.h>
|
||||
# ifdef USE_WIN32_TIME
|
||||
# include <Windows.h>
|
||||
# else
|
||||
# ifndef USE_PALMTIME
|
||||
# if defined(OSKIT) && !defined(OSKIT_TEST)
|
||||
|
@ -217,6 +216,15 @@ typedef void (*DW_PrePost_Proc)(void *);
|
|||
static void register_traversers(void);
|
||||
#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: */
|
||||
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->so.type = scheme_prompt_type;
|
||||
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
|
||||
|
@ -9222,6 +9244,11 @@ static Scheme_Object *jump_to_alt_continuation()
|
|||
#define CLOCKS_PER_SEC 1000000
|
||||
#endif
|
||||
|
||||
#ifdef USE_WIN32_TIME
|
||||
/* Number of milliseconds from 1601 to 1970: */
|
||||
# define MSEC_OFFSET 11644473600000
|
||||
#endif
|
||||
|
||||
intptr_t scheme_get_milliseconds(void)
|
||||
XFORM_SKIP_PROC
|
||||
/* this function can be called from any OS thread */
|
||||
|
@ -9234,9 +9261,13 @@ intptr_t scheme_get_milliseconds(void)
|
|||
MSC_IZE(ftime)(&now);
|
||||
return (intptr_t)(now.time * 1000 + now.millitm);
|
||||
# else
|
||||
# ifdef PALMOS_STUFF
|
||||
/* FIXME */
|
||||
return 0;
|
||||
# ifdef USE_WIN32_TIME
|
||||
FILETIME ft;
|
||||
mzlonglong v;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
v = ((mzlonglong)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
|
||||
v = (v / 10000) - MSEC_OFFSET;
|
||||
return (intptr_t)v;
|
||||
# else
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
|
@ -9265,9 +9296,13 @@ double scheme_get_inexact_milliseconds(void)
|
|||
MSC_IZE(ftime)(&now);
|
||||
return (double)now.time * 1000.0 + (double)now.millitm;
|
||||
# else
|
||||
# ifdef PALMOS_STUFF
|
||||
/* FIXME */
|
||||
return 0;
|
||||
# ifdef USE_WIN32_TIME
|
||||
FILETIME ft;
|
||||
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
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
|
@ -9312,10 +9347,12 @@ intptr_t scheme_get_process_milliseconds(void)
|
|||
v = ((((mzlonglong)kr.dwHighDateTime << 32) + kr.dwLowDateTime)
|
||||
+ (((mzlonglong)us.dwHighDateTime << 32) + us.dwLowDateTime));
|
||||
return (uintptr_t)(v / 10000);
|
||||
}
|
||||
} else
|
||||
return 0; /* anything better to do? */
|
||||
}
|
||||
# endif
|
||||
# else
|
||||
return clock() * 1000 / CLOCKS_PER_SEC;
|
||||
# endif
|
||||
|
||||
# endif
|
||||
# endif
|
||||
|
@ -9338,11 +9375,8 @@ intptr_t scheme_get_thread_milliseconds(Scheme_Object *thrd)
|
|||
|
||||
intptr_t scheme_get_seconds(void)
|
||||
{
|
||||
#ifdef USE_MACTIME
|
||||
/* This is wrong, since it's not since January 1, 1970 */
|
||||
unsigned long secs;
|
||||
GetDateTime(&secs);
|
||||
return secs;
|
||||
#ifdef USE_WIN32_TIME
|
||||
return scheme_get_milliseconds() / 1000;
|
||||
#else
|
||||
# ifdef USE_PALMTIME
|
||||
return TimGetSeconds();
|
||||
|
@ -9366,10 +9400,66 @@ intptr_t scheme_get_seconds(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
#if defined(USE_MACTIME) || defined(USE_PALMTIME)
|
||||
static int month_offsets[12] = { 0, 31, 59, 90,
|
||||
120, 151, 181, 212,
|
||||
243, 273, 304, 334 };
|
||||
#if defined(USE_WIN32_TIME)
|
||||
/* Assuming not a leap year (and adjusted elsewhere): */
|
||||
static int month_offsets[13] = { 0, 31, 59, 90,
|
||||
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
|
||||
|
||||
#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 hour, min, sec, month, day, year, wday, yday, dst;
|
||||
long tzoffset;
|
||||
#ifdef USE_MACTIME
|
||||
# define CHECK_TIME_T unsigned long
|
||||
DateTimeRec localTime;
|
||||
#ifdef USE_WIN32_TIME
|
||||
# define CHECK_TIME_T uintptr_t
|
||||
SYSTEMTIME localTime;
|
||||
#else
|
||||
# ifdef USE_PALMTIME
|
||||
# define CHECK_TIME_T UInt32
|
||||
|
@ -9479,9 +9569,22 @@ static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv)
|
|||
&& VALID_TIME_RANGE(lnow)) {
|
||||
int success;
|
||||
|
||||
#ifdef USE_MACTIME
|
||||
SecondsToDate(lnow, &localTime);
|
||||
success = 1;
|
||||
#ifdef USE_WIN32_TIME
|
||||
{
|
||||
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
|
||||
# ifdef USE_PALMTIME
|
||||
TimSecondsToDateTime(lnow, &localTime) ;
|
||||
|
@ -9495,65 +9598,53 @@ static Scheme_Object *seconds_to_date(int argc, Scheme_Object **argv)
|
|||
#endif
|
||||
|
||||
if (success) {
|
||||
#if defined(USE_MACTIME) || defined(USE_PALMTIME)
|
||||
# ifdef USE_MACTIME
|
||||
# define mzDOW(localTime) localTime.dayOfWeek - 1
|
||||
# else
|
||||
# define mzDOW(localTime) localTime.weekDay
|
||||
# endif
|
||||
#ifdef USE_WIN32_TIME
|
||||
|
||||
hour = localTime.hour;
|
||||
min = localTime.minute;
|
||||
sec = localTime.second;
|
||||
hour = localTime.wHour;
|
||||
min = localTime.wMinute;
|
||||
sec = localTime.wSecond;
|
||||
|
||||
month = localTime.month;
|
||||
day = localTime.day;
|
||||
year = localTime.year;
|
||||
month = localTime.wMonth;
|
||||
day = localTime.wDay;
|
||||
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;
|
||||
/* If month > 2, is it a leap-year? */
|
||||
if (localTime.month > 2) {
|
||||
# ifdef USE_MACTIME
|
||||
unsigned long ttime;
|
||||
DateTimeRec tester;
|
||||
|
||||
tester.year = localTime.year;
|
||||
tester.hour = tester.minute = 0;
|
||||
tester.second = 1;
|
||||
tester.month = 1;
|
||||
tester.day = 60;
|
||||
DateToSeconds(&tester, &ttime);
|
||||
SecondsToDate(ttime, &tester);
|
||||
if (tester.month == 2)
|
||||
/* It is a leap-year */
|
||||
yday++;
|
||||
# else
|
||||
/* PalmOS: */
|
||||
if (DaysInMonth(2, year) > 28)
|
||||
yday++;
|
||||
# endif
|
||||
dst = 0;
|
||||
if (get_gmt) {
|
||||
tzoffset = 0;
|
||||
tzn = "UTC";
|
||||
} else {
|
||||
TIME_ZONE_INFORMATION tz;
|
||||
if (GetTimeZoneInformationForYearProc)
|
||||
GetTimeZoneInformationForYearProc(localTime.wYear, NULL, &tz);
|
||||
else
|
||||
(void)GetTimeZoneInformation(&tz);
|
||||
if (tz.StandardDate.wMonth) {
|
||||
if (is_start_day_before(&tz.DaylightDate, &tz.StandardDate)) {
|
||||
/* northern hemisphere */
|
||||
dst = (!is_day_before(&localTime, &tz.DaylightDate)
|
||||
&& is_day_before(&localTime, &tz.StandardDate));
|
||||
} else {
|
||||
/* southern hemisphere */
|
||||
dst = (is_day_before(&localTime, &tz.StandardDate)
|
||||
|| !is_day_before(&localTime, &tz.DaylightDate));
|
||||
}
|
||||
}
|
||||
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
|
||||
hour = localTime->tm_hour;
|
||||
min = localTime->tm_min;
|
||||
|
|
Loading…
Reference in New Issue
Block a user