v / vlib / time / time_windows.c.v
237 lines · 206 sloc · 5.58 KB · a87a4d73b9ab25cfff0822f4e94cf2a2d9e64323
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module time
5
6#include <time.h>
7// #include <sysinfoapi.h>
8
9pub struct C.tm {
10pub mut:
11 tm_year int
12 tm_mon int
13 tm_mday int
14 tm_hour int
15 tm_min int
16 tm_sec int
17}
18
19pub struct C._FILETIME {
20pub mut:
21 dwLowDateTime u32
22 dwHighDateTime u32
23}
24
25struct SystemTime {
26 year u16
27 month u16
28 day_of_week u16
29 day u16
30 hour u16
31 minute u16
32 second u16
33 millisecond u16
34}
35
36fn C.GetSystemTimeAsFileTime(lpSystemTimeAsFileTime &C._FILETIME)
37
38fn C.FileTimeToSystemTime(lpFileTime &C._FILETIME, lpSystemTime &SystemTime)
39
40fn C.SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation &C.TIME_ZONE_INFORMATION, lpUniversalTime &SystemTime,
41 lpLocalTime &SystemTime)
42
43fn C.localtime_s(t &C.time_t, tm &C.tm)
44
45fn C.timespec_get(t &C.timespec, base i32) i32
46
47// start_time and time_coefficients are needed on Windows because of potential overflows
48const start_time = init_win_time_start()
49const time_coefficients = init_win_time_coefficients()
50const start_local_time = local_as_unix_time()
51
52// in most systems, these are __quad_t, which is an i64
53pub struct C.timespec {
54pub:
55 tv_sec i64
56 tv_nsec i64
57}
58
59fn C.QueryPerformanceCounter(&u64) C.BOOL
60
61fn C.QueryPerformanceFrequency(&u64) C.BOOL
62
63fn make_unix_time(t C.tm) i64 {
64 return portable_timegm(&t)
65}
66
67struct WinTimeCoefficients {
68 numer u64
69 denom u64
70}
71
72fn init_win_time_coefficients() WinTimeCoefficients {
73 mut f := u64(0)
74 C.QueryPerformanceFrequency(voidptr(&f))
75 mut nom := u64(1000000000)
76 for f % 10 == 0 {
77 f = f / 10
78 nom = nom / 10
79 }
80 res := WinTimeCoefficients{
81 numer: nom
82 denom: f
83 }
84 return res
85}
86
87fn init_win_time_start() u64 {
88 s := u64(0)
89 C.QueryPerformanceCounter(voidptr(&s))
90 return s
91}
92
93// sys_mono_now returns a *monotonically increasing time*, NOT a time adjusted for daylight savings, location etc.
94pub fn sys_mono_now() u64 {
95 tm := u64(0)
96 C.QueryPerformanceCounter(voidptr(&tm)) // XP or later never fail
97 return (tm - start_time) * time_coefficients.numer / time_coefficients.denom
98}
99
100// Note: vpc_now is used by `v -profile` .
101// It should NOT call *any other v function*, just C functions and casts.
102@[inline]
103fn vpc_now() u64 {
104 tm := u64(0)
105 C.QueryPerformanceCounter(voidptr(&tm))
106 return tm
107}
108
109// local_as_unix_time returns the current local time as unix time
110fn local_as_unix_time() i64 {
111 t := C.time(0)
112 tm := C.localtime(&t)
113 return make_unix_time(*tm)
114}
115
116// local - return the time `t`, converted to the currently active local timezone.
117pub fn (t Time) local() Time {
118 if t.is_local {
119 return t
120 }
121 st_utc := SystemTime{
122 year: u16(t.year)
123 month: u16(t.month)
124 day: u16(t.day)
125 hour: u16(t.hour)
126 minute: u16(t.minute)
127 second: u16(t.second)
128 millisecond: u16(t.nanosecond / 1_000_000)
129 }
130 st_local := SystemTime{}
131 C.SystemTimeToTzSpecificLocalTime(unsafe { nil }, voidptr(&st_utc), voidptr(&st_local))
132 t_local := Time{
133 year: st_local.year
134 month: st_local.month
135 day: st_local.day
136 hour: st_local.hour
137 minute: st_local.minute
138 second: st_local.second // These are the same
139 nanosecond: int(st_local.millisecond) * 1_000_000
140 unix: st_local.unix()
141 }
142 return t_local
143}
144
145// win_now calculates current time using winapi to get higher resolution on windows
146// GetSystemTimeAsFileTime is used and converted to local time. It can resolve time
147// down to millisecond. Other more precise methods can be implemented in the future
148fn win_now() Time {
149 ft_utc := C._FILETIME{}
150 C.GetSystemTimeAsFileTime(&ft_utc)
151 st_utc := SystemTime{}
152 C.FileTimeToSystemTime(&ft_utc, voidptr(&st_utc))
153 st_local := SystemTime{}
154 C.SystemTimeToTzSpecificLocalTime(unsafe { nil }, voidptr(&st_utc), voidptr(&st_local))
155 t := Time{
156 year: st_local.year
157 month: st_local.month
158 day: st_local.day
159 hour: st_local.hour
160 minute: st_local.minute
161 second: st_local.second
162 nanosecond: int(st_local.millisecond) * 1_000_000
163 unix: st_local.unix()
164 is_local: true
165 }
166 return t
167}
168
169// win_utc calculates current time using winapi to get higher resolution on windows
170// GetSystemTimeAsFileTime is used. It can resolve time down to millisecond
171// other more precise methods can be implemented in the future
172fn win_utc() Time {
173 ft_utc := C._FILETIME{}
174 C.GetSystemTimeAsFileTime(&ft_utc)
175 st_utc := SystemTime{}
176 C.FileTimeToSystemTime(&ft_utc, voidptr(&st_utc))
177 t := Time{
178 year: st_utc.year
179 month: st_utc.month
180 day: st_utc.day
181 hour: st_utc.hour
182 minute: st_utc.minute
183 second: st_utc.second
184 nanosecond: int(st_utc.millisecond) * 1_000_000
185 unix: st_utc.unix()
186 is_local: false
187 }
188 return t
189}
190
191// unix returns Unix time.
192fn (st SystemTime) unix() i64 {
193 tt := C.tm{
194 tm_sec: st.second
195 tm_min: st.minute
196 tm_hour: st.hour
197 tm_mday: st.day
198 tm_mon: st.month - 1
199 tm_year: st.year - 1900
200 }
201 return make_unix_time(tt)
202}
203
204// dummy to compile with all compilers
205fn darwin_now() Time {
206 return Time{}
207}
208
209// dummy to compile with all compilers
210fn linux_now() Time {
211 return Time{}
212}
213
214// dummy to compile with all compilers
215fn solaris_now() Time {
216 return Time{}
217}
218
219// dummy to compile with all compilers
220fn darwin_utc() Time {
221 return Time{}
222}
223
224// dummy to compile with all compilers
225fn linux_utc() Time {
226 return Time{}
227}
228
229// dummy to compile with all compilers
230fn solaris_utc() Time {
231 return Time{}
232}
233
234// sleep makes the calling thread sleep for a given duration (in nanoseconds).
235pub fn sleep(duration Duration) {
236 C.Sleep(int(duration / millisecond))
237}
238