v / vlib / time / time.c.v
153 lines · 139 sloc · 3.72 KB · 68a21aeaf8c1d17298efd2655c5ac0805930ec76
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
8// C.timeval represents a C time value.
9pub struct C.timeval {
10pub:
11 tv_sec u64
12 tv_usec u64
13}
14
15type C.time_t = i64
16
17fn C.time(t &C.time_t) C.time_t
18fn C.localtime(t &C.time_t) &C.tm
19fn C.localtime_r(t &C.time_t, tm &C.tm)
20fn C.gmtime(t &C.time_t) &C.tm
21fn C.gmtime_r(t &C.time_t, res &C.tm) &C.tm
22fn C.strftime(buf &char, maxsize usize, const_format &char, const_tm &C.tm) usize
23
24// now returns the current local time.
25pub fn now() Time {
26 $if macos {
27 return darwin_now()
28 }
29 $if windows {
30 return win_now()
31 }
32 $if solaris {
33 return solaris_now()
34 }
35 return linux_now()
36 /*
37 // defaults to most common feature, the microsecond precision is not available
38 // in this API call
39 t := C.time(0)
40 now := C.localtime(&t)
41 return convert_ctime(*now, 0)
42 */
43}
44
45// utc returns the current UTC time.
46pub fn utc() Time {
47 $if macos {
48 return darwin_utc()
49 }
50 $if windows {
51 return win_utc()
52 }
53 $if solaris {
54 return solaris_utc()
55 }
56 return linux_utc()
57}
58
59fn time_with_unix(t Time) Time {
60 if t.unix != 0 {
61 return t
62 }
63 normalized := normalize_zero_date_parts(t)
64 return Time{
65 ...normalized
66 unix: time_fields_to_unix(normalized)
67 }
68}
69
70@[inline]
71fn normalize_zero_date_parts(t Time) Time {
72 if t.month != 0 && t.day != 0 {
73 return t
74 }
75 return Time{
76 ...t
77 month: if t.month == 0 { 1 } else { t.month }
78 day: if t.day == 0 { 1 } else { t.day }
79 }
80}
81
82@[inline]
83fn time_fields_to_unix(t Time) i64 {
84 return i64(t.days_from_unix_epoch()) * i64(seconds_per_day) +
85 i64(t.hour) * i64(seconds_per_hour) + i64(t.minute) * i64(seconds_per_minute) +
86 i64(t.second)
87}
88
89// ticks returns the number of milliseconds since the UNIX epoch.
90// On Windows ticks returns the number of milliseconds elapsed since system start.
91pub fn ticks() i64 {
92 $if windows {
93 return C.GetTickCount()
94 } $else {
95 ts := C.timeval{}
96 C.gettimeofday(&ts, 0)
97 return i64(ts.tv_sec * u64(1000) + (ts.tv_usec / u64(1_000)))
98 }
99 // t := i64(C.mach_absolute_time())
100 // # Nanoseconds elapsedNano = AbsoluteToNanoseconds( *(AbsoluteTime *) &t );
101 // # return (double)(* (uint64_t *) &elapsedNano) / 1000000;
102}
103
104// str returns the time in the same format as `parse` expects ("YYYY-MM-DD HH:mm:ss").
105pub fn (t Time) str() string {
106 // TODO: Define common default format for
107 // `str` and `parse` and use it in both ways
108 return t.format_ss()
109}
110
111// convert_ctime converts a C time to V time.
112fn convert_ctime(t C.tm, nanosecond int) Time {
113 return Time{
114 year: t.tm_year + 1900
115 month: t.tm_mon + 1
116 day: t.tm_mday
117 hour: t.tm_hour
118 minute: t.tm_min
119 second: t.tm_sec
120 nanosecond: nanosecond
121 unix: make_unix_time(t)
122 // for the actual code base when we
123 // call convert_ctime, it is always
124 // when we manage the local time.
125 is_local: true
126 }
127}
128
129// strftime returns the formatted time using `strftime(3)`.
130pub fn (t Time) strftime(fmt string) string {
131 mut tm := &C.tm{}
132 $if windows {
133 tm = C.gmtime(voidptr(&t.unix))
134 } $else {
135 C.gmtime_r(voidptr(&t.unix), tm)
136 }
137 mut buf := [1024]char{}
138 fmt_c := unsafe { &char(fmt.str) }
139 C.strftime(&buf[0], usize(sizeof(buf)), fmt_c, tm)
140 return unsafe { cstring_to_vstring(&buf[0]) }
141}
142
143// some *nix system functions (e.g. `C.poll()`, C.epoll_wait()) accept an `int`
144// value as *timeout in milliseconds* with the special value `-1` meaning "infinite"
145pub fn (d Duration) sys_milliseconds() int {
146 if d > 2147483647 * millisecond { // treat 2147483647000001 .. C.INT64_MAX as "infinite"
147 return -1
148 } else if d <= 0 {
149 return 0 // treat negative timeouts as 0 - consistent with Unix behaviour
150 } else {
151 return int(d / millisecond)
152 }
153}
154