xref: /reactos/sdk/lib/ucrt/time/time.cpp (revision 04e0dc4a)
1 //
2 // time.cpp
3 //
4 //      Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // The timespec_get() and time() families of functions, which get the current
7 // system time as a timespec and a time_t, respectively.
8 //
9 #include <corecrt_internal_time.h>
10 
11 
12 using get_system_time_function_type = void(WINAPI *)(LPFILETIME);
13 
14 template <get_system_time_function_type GetSystemTimeFunction, typename TimeSpecType>
15 _Success_(return != 0)
common_timespec_get(TimeSpecType * const ts,int const base)16 static int __cdecl common_timespec_get(TimeSpecType* const ts, int const base) throw()
17 {
18     typedef decltype(ts->tv_sec)                time_type;
19     typedef __crt_time_time_t_traits<time_type> time_traits;
20 
21     _VALIDATE_RETURN(ts != nullptr, EINVAL, 0);
22 
23     if (base != TIME_UTC)
24     {
25         return 0;
26     }
27 
28     __crt_filetime_union system_time{};
29     GetSystemTimeFunction(&system_time._filetime);
30 
31     __time64_t const filetime_scale{10 * 1000 * 1000}; // 100ns units
32 
33     __time64_t const epoch_time{static_cast<__time64_t>(system_time._scalar) - _EPOCH_BIAS};
34 
35     __time64_t const seconds    {epoch_time / filetime_scale};
36     __time64_t const nanoseconds{epoch_time % filetime_scale * 100};
37 
38     if (seconds > static_cast<__time64_t>(time_traits::max_time_t))
39     {
40         return 0;
41     }
42 
43     ts->tv_sec  = static_cast<time_type>(seconds);
44     ts->tv_nsec = static_cast<long>(nanoseconds);
45     return base;
46 }
47 
_timespec32_get(_timespec32 * const ts,int const base)48 extern "C" int __cdecl _timespec32_get(_timespec32* const ts, int const base)
49 {
50     return common_timespec_get<__acrt_GetSystemTimePreciseAsFileTime>(ts, base);
51 }
52 
_timespec64_get(_timespec64 * const ts,int const base)53 extern "C" int __cdecl _timespec64_get(_timespec64* const ts, int const base)
54 {
55     return common_timespec_get<__acrt_GetSystemTimePreciseAsFileTime>(ts, base);
56 }
57 
58 
59 
60 // Gets the current system time and converts it to a time_t value. If 'result'
61 // is non-null, the time is stored in '*result'.  The time is also returned
62 // (even if 'result' is null).
63 template <typename TimeType>
common_time(TimeType * const result)64 static TimeType __cdecl common_time(TimeType* const result) throw()
65 {
66     typedef __crt_time_time_t_traits<TimeType> time_traits;
67 
68     typename time_traits::timespec_type ts{};
69 
70     // The resolution of time() is in seconds, so we can afford to use
71     // a less precise, but faster method of getting the time.
72     // GetSystemTimePreciseAsFileTime uses QueryPerformanceCounter which
73     // needs to be virtualized on some systems in order to be accurate, which can
74     // be significantly slower than calling GetSystemTimeAsFileTime.
75     // For example, hypervisors will virtualize QPC calls in order to take into
76     // account virtual machine live migration.
77     // Note that calling the less precise API is still observable because the tick
78     // count may update +/- 15ms, but this should not affect common use of time().
79     // See https://docs.microsoft.com/en-us/windows/desktop/sysinfo/acquiring-high-resolution-time-stamps
80     // for more details.
81     if (common_timespec_get<GetSystemTimeAsFileTime>(&ts, TIME_UTC) != TIME_UTC)
82     {
83         ts.tv_sec = static_cast<TimeType>(-1);
84     }
85 
86     if (result)
87     {
88         *result = ts.tv_sec;
89     }
90 
91     return ts.tv_sec;
92 }
93 
_time32(__time32_t * const result)94 extern "C" __time32_t __cdecl _time32(__time32_t* const result)
95 {
96     return common_time(result);
97 }
98 
_time64(__time64_t * const result)99 extern "C" __time64_t __cdecl _time64(__time64_t* const result)
100 {
101     return common_time(result);
102 }
103