forked from svaarala/duktape
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathduk_bi_date_windows.c
130 lines (108 loc) · 4.45 KB
/
duk_bi_date_windows.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
* Windows Date providers
*
* Platform specific links:
*
* - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
*/
#include "duk_internal.h"
/* The necessary #includes are in place in duk_config.h. */
#if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS)
/* Shared Windows helpers. */
DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEGER *res) {
FILETIME ft;
if (SystemTimeToFileTime(st, &ft) == 0) {
DUK_D(DUK_DPRINT("SystemTimeToFileTime() failed, returning 0"));
res->QuadPart = 0;
} else {
res->LowPart = ft.dwLowDateTime;
res->HighPart = ft.dwHighDateTime;
}
}
DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
DUK_MEMZERO((void *) st, sizeof(*st));
st->wYear = 1970;
st->wMonth = 1;
st->wDayOfWeek = 4; /* not sure whether or not needed; Thursday */
st->wDay = 1;
DUK_ASSERT(st->wHour == 0);
DUK_ASSERT(st->wMinute == 0);
DUK_ASSERT(st->wSecond == 0);
DUK_ASSERT(st->wMilliseconds == 0);
}
#endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */
#if defined(DUK_USE_DATE_NOW_WINDOWS)
DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx) {
/* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
*/
SYSTEMTIME st1, st2;
ULARGE_INTEGER tmp1, tmp2;
DUK_UNREF(ctx);
GetSystemTime(&st1);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
duk__set_systime_jan1970(&st2);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
/* Difference is in 100ns units, convert to milliseconds w/o fractions */
return (duk_double_t) (((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / DUK_I64_CONSTANT(10000));
}
#endif /* DUK_USE_DATE_NOW_WINDOWS */
#if defined(DUK_USE_DATE_TZO_WINDOWS)
DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
SYSTEMTIME st1;
SYSTEMTIME st2;
SYSTEMTIME st3;
ULARGE_INTEGER tmp1;
ULARGE_INTEGER tmp2;
ULARGE_INTEGER tmp3;
FILETIME ft1;
/* XXX: handling of timestamps outside Windows supported range.
* How does Windows deal with dates before 1600? Does windows
* support all Ecmascript years (like -200000 and +200000)?
* Should equivalent year mapping be used here too? If so, use
* a shared helper (currently integrated into timeval-to-parts).
*/
/* Use the approach described in "Remarks" of FileTimeToLocalFileTime:
* http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx
*/
duk__set_systime_jan1970(&st1);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
tmp2.QuadPart = (ULONGLONG) (d * 10000.0); /* millisec -> 100ns units since jan 1, 1970 */
tmp2.QuadPart += tmp1.QuadPart; /* input 'd' in Windows UTC, 100ns units */
ft1.dwLowDateTime = tmp2.LowPart;
ft1.dwHighDateTime = tmp2.HighPart;
FileTimeToSystemTime((const FILETIME *) &ft1, &st2);
if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) {
DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0"));
return 0;
}
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
/* Positive if local time ahead of UTC. */
return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
}
#endif /* DUK_USE_DATE_TZO_WINDOWS */
#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d) {
SYSTEMTIME st1;
SYSTEMTIME st2;
FILETIME ft1;
FILETIME ft2;
ULARGE_INTEGER tmp1;
ULARGE_INTEGER tmp2;
/* Do a similar computation to duk_bi_date_get_local_tzoffset_windows
* but without accounting for daylight savings time. Use this on
* Windows platforms (like Durango) that don't support the
* SystemTimeToTzSpecificLocalTime() call.
*/
/* current time not needed for this computation */
DUK_UNREF(d);
duk__set_systime_jan1970(&st1);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
ft1.dwLowDateTime = tmp1.LowPart;
ft1.dwHighDateTime = tmp1.HighPart;
FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2);
FileTimeToSystemTime((const FILETIME *) &ft2, &st2);
duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / 10000000LL); /* seconds */
}
#endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */