aboutsummaryrefslogtreecommitdiff
path: root/src/dutil/timeutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dutil/timeutil.cpp')
-rw-r--r--src/dutil/timeutil.cpp370
1 files changed, 370 insertions, 0 deletions
diff --git a/src/dutil/timeutil.cpp b/src/dutil/timeutil.cpp
new file mode 100644
index 00000000..dacb2660
--- /dev/null
+++ b/src/dutil/timeutil.cpp
@@ -0,0 +1,370 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5const LPCWSTR DAY_OF_WEEK[] = { L"Sun", L"Mon", L"Tue", L"Wed", L"Thu", L"Fri", L"Sat" };
6const LPCWSTR MONTH_OF_YEAR[] = { L"None", L"Jan", L"Feb", L"Mar", L"Apr", L"May", L"Jun", L"Jul", L"Aug", L"Sep", L"Oct", L"Nov", L"Dec" };
7enum TIME_PARSER { DayOfWeek, DayOfMonth, MonthOfYear, Year, Hours, Minutes, Seconds, TimeZone };
8enum TIME_PARSERRFC3339 { RFC3339_Year, RFC3339_Month, RFC3339_Day, RFC3339_Hours, RFC3339_Minutes, RFC3339_Seconds, RFC3339_TimeZone };
9
10// prototypes
11static HRESULT DayFromString(
12 __in_z LPCWSTR wzDay,
13 __out WORD* pwDayOfWeek
14 );
15static HRESULT MonthFromString(
16 __in_z LPCWSTR wzMonth,
17 __out WORD* pwMonthOfYear
18 );
19
20
21/********************************************************************
22 TimeFromString - converts string to FILETIME
23
24*******************************************************************/
25extern "C" HRESULT DAPI TimeFromString(
26 __in_z LPCWSTR wzTime,
27 __out FILETIME* pFileTime
28 )
29{
30 Assert(wzTime && pFileTime);
31
32 HRESULT hr = S_OK;
33 LPWSTR pwzTime = NULL;
34
35 SYSTEMTIME sysTime = { };
36 TIME_PARSER timeParser = DayOfWeek;
37
38 LPCWSTR pwzStart = NULL;
39 LPWSTR pwzEnd = NULL;
40
41 hr = StrAllocString(&pwzTime, wzTime, 0);
42 ExitOnFailure(hr, "Failed to copy time.");
43
44 pwzStart = pwzEnd = pwzTime;
45 while (pwzEnd && *pwzEnd)
46 {
47 if (L',' == *pwzEnd || L' ' == *pwzEnd || L':' == *pwzEnd)
48 {
49 *pwzEnd = L'\0'; // null terminate
50 ++pwzEnd;
51
52 while (L' ' == *pwzEnd)
53 {
54 ++pwzEnd; // and skip past the blank space
55 }
56
57 switch (timeParser)
58 {
59 case DayOfWeek:
60 hr = DayFromString(pwzStart, &sysTime.wDayOfWeek);
61 ExitOnFailure(hr, "Failed to convert string to day: %ls", pwzStart);
62 break;
63
64 case DayOfMonth:
65 sysTime.wDay = (WORD)wcstoul(pwzStart, NULL, 10);
66 break;
67
68 case MonthOfYear:
69 hr = MonthFromString(pwzStart, &sysTime.wMonth);
70 ExitOnFailure(hr, "Failed to convert to month: %ls", pwzStart);
71 break;
72
73 case Year:
74 sysTime.wYear = (WORD)wcstoul(pwzStart, NULL, 10);
75 break;
76
77 case Hours:
78 sysTime.wHour = (WORD)wcstoul(pwzStart, NULL, 10);
79 break;
80
81 case Minutes:
82 sysTime.wMinute = (WORD)wcstoul(pwzStart, NULL, 10);
83 break;
84
85 case Seconds:
86 sysTime.wSecond = (WORD)wcstoul(pwzStart, NULL, 10);
87 break;
88
89 case TimeZone:
90 // TODO: do something with this in the future, but this should only hit outside of the while loop.
91 break;
92
93 default:
94 break;
95 }
96
97 pwzStart = pwzEnd;
98 timeParser = (TIME_PARSER)((int)timeParser + 1);
99 }
100
101 ++pwzEnd;
102 }
103
104
105 if (!::SystemTimeToFileTime(&sysTime, pFileTime))
106 {
107 ExitWithLastError(hr, "Failed to convert system time to file time.");
108 }
109
110LExit:
111 ReleaseStr(pwzTime);
112
113 return hr;
114}
115
116/********************************************************************
117 TimeFromString3339 - converts string formated in accorance with RFC3339 to FILETIME
118 http://tools.ietf.org/html/rfc3339
119*******************************************************************/
120extern "C" HRESULT DAPI TimeFromString3339(
121 __in_z LPCWSTR wzTime,
122 __out FILETIME* pFileTime
123 )
124{
125 Assert(wzTime && pFileTime);
126
127 HRESULT hr = S_OK;
128 LPWSTR pwzTime = NULL;
129
130 SYSTEMTIME sysTime = { };
131 TIME_PARSERRFC3339 timeParser = RFC3339_Year;
132
133 LPCWSTR pwzStart = NULL;
134 LPWSTR pwzEnd = NULL;
135
136 hr = StrAllocString(&pwzTime, wzTime, 0);
137 ExitOnFailure(hr, "Failed to copy time.");
138
139 pwzStart = pwzEnd = pwzTime;
140 while (pwzEnd && *pwzEnd)
141 {
142 if (L'T' == *pwzEnd || L':' == *pwzEnd || L'-' == *pwzEnd)
143 {
144 *pwzEnd = L'\0'; // null terminate
145 ++pwzEnd;
146
147 switch (timeParser)
148 {
149 case RFC3339_Year:
150 sysTime.wYear = (WORD)wcstoul(pwzStart, NULL, 10);
151 break;
152
153 case RFC3339_Month:
154 sysTime.wMonth = (WORD)wcstoul(pwzStart, NULL, 10);
155 break;
156
157 case RFC3339_Day:
158 sysTime.wDay = (WORD)wcstoul(pwzStart, NULL, 10);
159 break;
160
161 case RFC3339_Hours:
162 sysTime.wHour = (WORD)wcstoul(pwzStart, NULL, 10);
163 break;
164
165 case RFC3339_Minutes:
166 sysTime.wMinute = (WORD)wcstoul(pwzStart, NULL, 10);
167 break;
168
169 case RFC3339_Seconds:
170 sysTime.wSecond = (WORD)wcstoul(pwzStart, NULL, 10);
171 break;
172
173 case RFC3339_TimeZone:
174 // TODO: do something with this in the future, but this should only hit outside of the while loop.
175 break;
176
177 default:
178 break;
179 }
180
181 pwzStart = pwzEnd;
182 timeParser = (TIME_PARSERRFC3339)((int)timeParser + 1);
183 }
184
185 ++pwzEnd;
186 }
187
188
189 if (!::SystemTimeToFileTime(&sysTime, pFileTime))
190 {
191 ExitWithLastError(hr, "Failed to convert system time to file time.");
192 }
193
194LExit:
195 ReleaseStr(pwzTime);
196
197 return hr;
198}
199/****************************************************************************
200TimeCurrentTime - gets the current time in string format
201
202****************************************************************************/
203extern "C" HRESULT DAPI TimeCurrentTime(
204 __deref_out_z LPWSTR* ppwz,
205 __in BOOL fGMT
206 )
207{
208 SYSTEMTIME st;
209
210 if (fGMT)
211 {
212 ::GetSystemTime(&st);
213 }
214 else
215 {
216 SYSTEMTIME stGMT;
217 TIME_ZONE_INFORMATION tzi;
218
219 ::GetTimeZoneInformation(&tzi);
220 ::GetSystemTime(&stGMT);
221 ::SystemTimeToTzSpecificLocalTime(&tzi, &stGMT, &st);
222 }
223
224 return StrAllocFormatted(ppwz, L"%02d:%02d:%02d", st.wHour, st.wMinute, st.wSecond);
225}
226
227
228/****************************************************************************
229TimeCurrentDateTime - gets the current date and time in string format,
230 per format described in RFC 3339
231****************************************************************************/
232extern "C" HRESULT DAPI TimeCurrentDateTime(
233 __deref_out_z LPWSTR* ppwz,
234 __in BOOL fGMT
235 )
236{
237 SYSTEMTIME st;
238
239 ::GetSystemTime(&st);
240
241 return TimeSystemDateTime(ppwz, &st, fGMT);
242}
243
244
245/****************************************************************************
246TimeSystemDateTime - converts the provided system time struct to string format,
247 per format described in RFC 3339
248****************************************************************************/
249extern "C" HRESULT DAPI TimeSystemDateTime(
250 __deref_out_z LPWSTR* ppwz,
251 __in const SYSTEMTIME *pst,
252 __in BOOL fGMT
253 )
254{
255 DWORD dwAbsBias = 0;
256
257 if (fGMT)
258 {
259 return StrAllocFormatted(ppwz, L"%04hu-%02hu-%02huT%02hu:%02hu:%02huZ", pst->wYear, pst->wMonth, pst->wDay, pst->wHour, pst->wMinute, pst->wSecond);
260 }
261 else
262 {
263 SYSTEMTIME st;
264 TIME_ZONE_INFORMATION tzi;
265
266 ::GetTimeZoneInformation(&tzi);
267 ::SystemTimeToTzSpecificLocalTime(&tzi, pst, &st);
268 dwAbsBias = abs(tzi.Bias);
269
270 return StrAllocFormatted(ppwz, L"%04hu-%02hu-%02huT%02hu:%02hu:%02hu%c%02u:%02u", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, 0 >= tzi.Bias ? L'+' : L'-', dwAbsBias / 60, dwAbsBias % 60);
271 }
272}
273
274
275/****************************************************************************
276TimeSystemToDateTimeString - converts the provided system time struct to
277 string format representing date and time for the specified locale
278****************************************************************************/
279HRESULT DAPI TimeSystemToDateTimeString(
280 __deref_out_z LPWSTR* ppwz,
281 __in const SYSTEMTIME* pst,
282 __in LCID locale
283 )
284{
285 HRESULT hr = S_OK;
286 const WCHAR * DATE_FORMAT = L"MMM dd',' yyyy',' ";
287 const WCHAR * TIME_FORMAT = L"hh':'mm':'ss tt";
288 int iLenDate = 0;
289 int iLenTime = 0;
290
291 iLenDate = ::GetDateFormatW(locale, 0, pst, DATE_FORMAT, NULL, 0);
292 if (0 >= iLenDate)
293 {
294 ExitWithLastError(hr, "Failed to get date format with NULL");
295 }
296
297 iLenTime = ::GetTimeFormatW(locale, 0, pst, TIME_FORMAT, NULL, 0);
298 if (0 >= iLenTime)
299 {
300 ExitWithLastError(hr, "Failed to get time format with NULL");
301 }
302
303 // Between both lengths we account for 2 null terminators, and only need one, so we subtract one
304 hr = StrAlloc(ppwz, iLenDate + iLenTime - 1);
305 ExitOnFailure(hr, "Failed to allocate string");
306
307 if (!::GetDateFormatW(locale, 0, pst, DATE_FORMAT, *ppwz, iLenDate))
308 {
309 ExitWithLastError(hr, "Failed to get date format with buffer");
310 }
311 // Space to separate them
312 (*ppwz)[iLenDate - 1] = ' ';
313
314 if (!::GetTimeFormatW(locale, 0, pst, TIME_FORMAT, (*ppwz) + iLenDate - 1, iLenTime))
315 {
316 ExitWithLastError(hr, "Failed to get time format with buffer");
317 }
318
319LExit:
320 return hr;
321}
322
323/********************************************************************
324 DayFromString - converts string to day
325
326*******************************************************************/
327static HRESULT DayFromString(
328 __in_z LPCWSTR wzDay,
329 __out WORD* pwDayOfWeek
330 )
331{
332 HRESULT hr = E_INVALIDARG; // assume we won't find a matching name
333
334 for (WORD i = 0; i < countof(DAY_OF_WEEK); ++i)
335 {
336 if (0 == lstrcmpW(wzDay, DAY_OF_WEEK[i]))
337 {
338 *pwDayOfWeek = i;
339 hr = S_OK;
340 break;
341 }
342 }
343
344 return hr;
345}
346
347
348/********************************************************************
349 MonthFromString - converts string to month
350
351*******************************************************************/
352static HRESULT MonthFromString(
353 __in_z LPCWSTR wzMonth,
354 __out WORD* pwMonthOfYear
355 )
356{
357 HRESULT hr = E_INVALIDARG; // assume we won't find a matching name
358
359 for (WORD i = 0; i < countof(MONTH_OF_YEAR); ++i)
360 {
361 if (0 == lstrcmpW(wzMonth, MONTH_OF_YEAR[i]))
362 {
363 *pwMonthOfYear = i;
364 hr = S_OK;
365 break;
366 }
367 }
368
369 return hr;
370}