v
Зеркало из https://github.com/vlang/v
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:
11tm_year int
12tm_mon int
13tm_mday int
14tm_hour int
15tm_min int
16tm_sec int
17}
18
19pub struct C._FILETIME {
20pub mut:
21dwLowDateTime u32
22dwHighDateTime u32
23}
24
25struct SystemTime {
26year u16
27month u16
28day_of_week u16
29day u16
30hour u16
31minute u16
32second u16
33millisecond 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,
41lpLocalTime &SystemTime)
42
43fn C.localtime_s(t &C.time_t, tm &C.tm)
44
45fn C.timespec_get(t &C.timespec, base int) int
46
47// start_time is needed on Darwin and Windows because of potential overflows
48const start_time = init_win_time_start()
49const freq_time = init_win_time_freq()
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:
55tv_sec i64
56tv_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 {
64return portable_timegm(&t)
65}
66
67fn init_win_time_freq() u64 {
68f := u64(0)
69C.QueryPerformanceFrequency(voidptr(&f))
70return f
71}
72
73fn init_win_time_start() u64 {
74s := u64(0)
75C.QueryPerformanceCounter(voidptr(&s))
76return s
77}
78
79// sys_mono_now returns a *monotonically increasing time*, NOT a time adjusted for daylight savings, location etc.
80pub fn sys_mono_now() u64 {
81tm := u64(0)
82C.QueryPerformanceCounter(voidptr(&tm)) // XP or later never fail
83return (tm - start_time) * 1000000000 / freq_time
84}
85
86// Note: vpc_now is used by `v -profile` .
87// It should NOT call *any other v function*, just C functions and casts.
88@[inline]
89fn vpc_now() u64 {
90tm := u64(0)
91C.QueryPerformanceCounter(voidptr(&tm))
92return tm
93}
94
95// local_as_unix_time returns the current local time as unix time
96fn local_as_unix_time() i64 {
97t := C.time(0)
98tm := C.localtime(&t)
99return make_unix_time(tm)
100}
101
102// local - return the time `t`, converted to the currently active local timezone
103pub fn (t Time) local() Time {
104if t.is_local {
105return t
106}
107st_utc := SystemTime{
108year: u16(t.year)
109month: u16(t.month)
110day: u16(t.day)
111hour: u16(t.hour)
112minute: u16(t.minute)
113second: u16(t.second)
114millisecond: u16(t.nanosecond / 1_000_000)
115}
116st_local := SystemTime{}
117C.SystemTimeToTzSpecificLocalTime(unsafe { nil }, voidptr(&st_utc), voidptr(&st_local))
118t_local := Time{
119year: st_local.year
120month: st_local.month
121day: st_local.day
122hour: st_local.hour
123minute: st_local.minute
124second: st_local.second // These are the same
125nanosecond: int(st_local.millisecond) * 1_000_000
126unix: st_local.unix()
127}
128return t_local
129}
130
131// win_now calculates current time using winapi to get higher resolution on windows
132// GetSystemTimeAsFileTime is used and converted to local time. It can resolve time
133// down to millisecond. Other more precise methods can be implemented in the future
134fn win_now() Time {
135ft_utc := C._FILETIME{}
136C.GetSystemTimeAsFileTime(&ft_utc)
137st_utc := SystemTime{}
138C.FileTimeToSystemTime(&ft_utc, voidptr(&st_utc))
139st_local := SystemTime{}
140C.SystemTimeToTzSpecificLocalTime(unsafe { nil }, voidptr(&st_utc), voidptr(&st_local))
141t := Time{
142year: st_local.year
143month: st_local.month
144day: st_local.day
145hour: st_local.hour
146minute: st_local.minute
147second: st_local.second
148nanosecond: int(st_local.millisecond) * 1_000_000
149unix: st_local.unix()
150is_local: true
151}
152return t
153}
154
155// win_utc calculates current time using winapi to get higher resolution on windows
156// GetSystemTimeAsFileTime is used. It can resolve time down to millisecond
157// other more precise methods can be implemented in the future
158fn win_utc() Time {
159ft_utc := C._FILETIME{}
160C.GetSystemTimeAsFileTime(&ft_utc)
161st_utc := SystemTime{}
162C.FileTimeToSystemTime(&ft_utc, voidptr(&st_utc))
163t := Time{
164year: st_utc.year
165month: st_utc.month
166day: st_utc.day
167hour: st_utc.hour
168minute: st_utc.minute
169second: st_utc.second
170nanosecond: int(st_utc.millisecond) * 1_000_000
171unix: st_utc.unix()
172is_local: false
173}
174return t
175}
176
177// unix_time returns Unix time.
178@[deprecated: 'use `st.unix()` instead']
179fn (st SystemTime) unix_time() i64 {
180return st.unix()
181}
182
183// unix returns Unix time.
184fn (st SystemTime) unix() i64 {
185tt := C.tm{
186tm_sec: st.second
187tm_min: st.minute
188tm_hour: st.hour
189tm_mday: st.day
190tm_mon: st.month - 1
191tm_year: st.year - 1900
192}
193return make_unix_time(tt)
194}
195
196// dummy to compile with all compilers
197fn darwin_now() Time {
198return Time{}
199}
200
201// dummy to compile with all compilers
202fn linux_now() Time {
203return Time{}
204}
205
206// dummy to compile with all compilers
207fn solaris_now() Time {
208return Time{}
209}
210
211// dummy to compile with all compilers
212fn darwin_utc() Time {
213return Time{}
214}
215
216// dummy to compile with all compilers
217fn linux_utc() Time {
218return Time{}
219}
220
221// dummy to compile with all compilers
222fn solaris_utc() Time {
223return Time{}
224}
225
226// sleep makes the calling thread sleep for a given duration (in nanoseconds).
227pub fn sleep(duration Duration) {
228C.Sleep(int(duration / millisecond))
229}
230