annotate foosdk/sdk/pfc/filetimetools.cpp @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
1 #include "pfc-lite.h"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
2
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
3 #include "filetimetools.h"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
4
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
5 #include "timers.h"
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
6
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
7 #include <math.h>
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
8
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
9 namespace {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
10 class exception_time_error {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
11 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
12
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
13 using namespace pfc;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
14
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
15 #ifndef _WIN32
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
16 namespace {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
17 typedef uint16_t WORD;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
18
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
19 typedef struct _SYSTEMTIME {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
20 WORD wYear;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
21 WORD wMonth;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
22 WORD wDayOfWeek;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
23 WORD wDay;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
24 WORD wHour;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
25 WORD wMinute;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
26 WORD wSecond;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
27 WORD wMilliseconds;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
28 } SYSTEMTIME, * PSYSTEMTIME, * LPSYSTEMTIME;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
29
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
30 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
31 static void SystemTimeToNix(const SYSTEMTIME& st, struct tm& Time) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
32 memset(&Time, 0, sizeof(Time));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
33 Time.tm_sec = st.wSecond;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
34 Time.tm_min = st.wMinute;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
35 Time.tm_hour = st.wHour;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
36 Time.tm_mday = st.wDay;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
37 Time.tm_mon = st.wMonth - 1;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
38 Time.tm_year = st.wYear - 1900;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
39 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
40
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
41 static t_filetimestamp ExportSystemTime(const SYSTEMTIME& st) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
42 struct tm Time;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
43 SystemTimeToNix(st, Time);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
44 return pfc::fileTimeUtoW(mktime(&Time));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
45 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
46
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
47 static t_filetimestamp ExportSystemTimeLocal(const SYSTEMTIME& st) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
48 struct tm Time, Local;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
49 SystemTimeToNix(st, Time);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
50 time_t t = mktime(&Time);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
51 localtime_r(&t, &Local);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
52 return pfc::fileTimeUtoW(mktime(&Local));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
53 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
54 static void SystemTimeFromNix(SYSTEMTIME& st, struct tm const& Time, t_filetimestamp origTS) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
55 memset(&st, 0, sizeof(st));
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
56 st.wSecond = Time.tm_sec;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
57 st.wMinute = Time.tm_min;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
58 st.wHour = Time.tm_hour;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
59 st.wDay = Time.tm_mday;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
60 st.wDayOfWeek = Time.tm_wday;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
61 st.wMonth = Time.tm_mon + 1;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
62 st.wYear = Time.tm_year + 1900;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
63 st.wMilliseconds = (origTS % filetimestamp_1second_increment) / (filetimestamp_1second_increment/1000);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
64 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
65
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
66 static bool MakeSystemTime(SYSTEMTIME& st, t_filetimestamp ts) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
67 time_t t = (time_t)pfc::fileTimeWtoU(ts);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
68 struct tm Time;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
69 if (gmtime_r(&t, &Time) == NULL) return false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
70 SystemTimeFromNix(st, Time, ts);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
71 return true;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
72 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
73
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
74 static bool MakeSystemTimeLocal(SYSTEMTIME& st, t_filetimestamp ts) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
75 time_t t = (time_t)pfc::fileTimeWtoU(ts);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
76 struct tm Time;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
77 if (localtime_r(&t, &Time) == NULL) return false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
78 SystemTimeFromNix(st, Time, ts);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
79 return true;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
80 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
81
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
82 #else
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
83 static t_filetimestamp ExportSystemTime(const SYSTEMTIME& st) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
84 t_filetimestamp base;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
85 if (!SystemTimeToFileTime(&st, (FILETIME*)&base)) throw exception_time_error();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
86 return base;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
87 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
88 static t_filetimestamp ExportSystemTimeLocal(const SYSTEMTIME& st) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
89 #ifdef FOOBAR2000_DESKTOP_WINDOWS
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
90 t_filetimestamp base, out;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
91 if (!SystemTimeToFileTime(&st, (FILETIME*)&base)) throw exception_time_error();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
92 if (!LocalFileTimeToFileTime((const FILETIME*)&base, (FILETIME*)&out)) throw exception_time_error();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
93 return out;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
94 #else
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
95 SYSTEMTIME UTC;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
96 if (!TzSpecificLocalTimeToSystemTime(NULL, &st, &UTC)) throw exception_time_error();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
97 return ExportSystemTime(UTC);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
98 #endif
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
99 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
100 static bool MakeSystemTime(SYSTEMTIME& st, t_filetimestamp ts) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
101 if (ts == filetimestamp_invalid) return false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
102 return !!FileTimeToSystemTime((const FILETIME*)&ts, &st);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
103
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
104 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
105 static bool MakeSystemTimeLocal(SYSTEMTIME& st, t_filetimestamp ts) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
106 if (ts == filetimestamp_invalid) return false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
107 #ifdef FOOBAR2000_DESKTOP_WINDOWS
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
108 FILETIME ft;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
109 if (FileTimeToLocalFileTime((FILETIME*)&ts, &ft)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
110 if (FileTimeToSystemTime(&ft, &st)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
111 return true;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
112 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
113 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
114 return false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
115 #else
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
116 SYSTEMTIME UTC;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
117 if (FileTimeToSystemTime((FILETIME*)&ts, &UTC)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
118 if (SystemTimeToTzSpecificLocalTime(NULL, &UTC, &st)) return true;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
119 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
120 return false;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
121 #endif
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
122 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
123 #endif // _WIN32
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
124
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
125 static bool is_spacing(char c) { return c == ' ' || c == 10 || c == 13 || c == '\t'; }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
126
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
127 static unsigned ParseDateElem(const char* ptr, t_size len) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
128 unsigned ret = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
129 for (t_size walk = 0; walk < len; ++walk) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
130 const char c = ptr[walk];
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
131 if (c < '0' || c > '9') throw exception_time_error();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
132 ret = ret * 10 + (unsigned)(c - '0');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
133 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
134 return ret;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
135 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
136
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
137 static bool st_sanity(SYSTEMTIME const& st) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
138 return st.wYear >= 1601 && st.wMonth >= 1 && st.wMonth <= 12 && st.wDay >= 1 && st.wDay <= 31 && st.wHour < 24 && st.wMinute < 60 && st.wSecond < 60 && st.wMilliseconds < 1000;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
139 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
140 static t_filetimestamp filetimestamp_from_string_internal(const char* date, bool local) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
141 // Accepted format
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
142 // YYYY-MM-DD HH:MM:SS
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
143 try {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
144 SYSTEMTIME st = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
145 st.wDay = 1; st.wMonth = 1;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
146
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
147 unsigned walk = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
148 auto worker = [&](unsigned n) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
149 auto ret = ParseDateElem(date + walk, n);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
150 walk += n;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
151 if (ret > UINT16_MAX) throw exception_time_error();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
152 return (WORD)ret;;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
153 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
154
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
155 auto skip = [&](char c) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
156 if (date[walk] == c) ++walk;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
157 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
158
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
159 auto skipSpacing = [&] {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
160 while (is_spacing(date[walk])) ++walk;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
161 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
162 skipSpacing();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
163 st.wYear = worker(4);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
164 skip('-');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
165 st.wMonth = worker(2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
166 skip('-');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
167 st.wDay = worker(2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
168 skipSpacing();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
169 st.wHour = worker(2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
170 skip(':');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
171 st.wMinute = worker(2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
172 skip(':');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
173 st.wSecond = worker(2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
174 if (date[walk] == '.') {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
175 double v = pfc::string_to_float(date + walk);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
176 st.wMilliseconds = (WORD)floor(v * 1000.f); // don't ever round up, don't want to handle ms of 1000
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
177 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
178
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
179 if (!st_sanity(st)) throw exception_time_error();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
180
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
181 if (local) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
182 return ExportSystemTimeLocal(st);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
183 } else {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
184 return ExportSystemTime(st);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
185 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
186 } catch (exception_time_error const &) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
187 return filetimestamp_invalid;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
188 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
189 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
190
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
191 namespace pfc {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
192 t_filetimestamp filetimestamp_from_string(const char* date) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
193 return filetimestamp_from_string_internal(date, true);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
194 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
195
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
196 t_filetimestamp filetimestamp_from_string_utc(const char* date) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
197 return filetimestamp_from_string_internal(date, false);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
198 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
199
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
200 static constexpr char g_invalidMsg[] = "<invalid timestamp>";
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
201
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
202 pfc::string_formatter format_filetimestamp(t_filetimestamp p_timestamp) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
203 try {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
204 SYSTEMTIME st;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
205 if (MakeSystemTimeLocal(st, p_timestamp)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
206 pfc::string_formatter buffer;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
207 buffer
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
208 << pfc::format_uint(st.wYear, 4) << "-" << pfc::format_uint(st.wMonth, 2) << "-" << pfc::format_uint(st.wDay, 2) << " "
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
209 << pfc::format_uint(st.wHour, 2) << ":" << pfc::format_uint(st.wMinute, 2) << ":" << pfc::format_uint(st.wSecond, 2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
210 return buffer;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
211 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
212 } catch (...) {}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
213 return g_invalidMsg;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
214 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
215
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
216 pfc::string_formatter format_filetimestamp_ms(t_filetimestamp p_timestamp) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
217 try {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
218 SYSTEMTIME st;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
219 if (MakeSystemTimeLocal(st, p_timestamp)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
220 pfc::string_formatter buffer;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
221 buffer
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
222 << pfc::format_uint(st.wYear, 4) << "-" << pfc::format_uint(st.wMonth, 2) << "-" << pfc::format_uint(st.wDay, 2) << " "
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
223 << pfc::format_uint(st.wHour, 2) << ":" << pfc::format_uint(st.wMinute, 2) << ":" << pfc::format_uint(st.wSecond, 2) << "." << pfc::format_uint(st.wMilliseconds, 3);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
224 return buffer;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
225 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
226 } catch (...) {}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
227 return g_invalidMsg;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
228 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
229
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
230 pfc::string_formatter format_filetimestamp_utc(t_filetimestamp p_timestamp) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
231 try {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
232 SYSTEMTIME st;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
233 if (MakeSystemTime(st, p_timestamp)) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
234 pfc::string_formatter buffer;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
235 buffer
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
236 << pfc::format_uint(st.wYear, 4) << "-" << pfc::format_uint(st.wMonth, 2) << "-" << pfc::format_uint(st.wDay, 2) << " "
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
237 << pfc::format_uint(st.wHour, 2) << ":" << pfc::format_uint(st.wMinute, 2) << ":" << pfc::format_uint(st.wSecond, 2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
238 return buffer;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
239 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
240 } catch (...) {}
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
241 return g_invalidMsg;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
242 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
243
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
244 } // namespace foobar2000_io
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
245
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
246 namespace {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
247 struct dateISO_t {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
248 unsigned Y, M, D;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
249 unsigned h, m, s;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
250 double sfrac;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
251 int tzdelta;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
252 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
253
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
254 dateISO_t read_ISO_8601(const char* dateISO) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
255 dateISO_t ret = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
256 // 2022-01-26T13:44:51.200000Z
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
257 // 2010-02-19T14:54:23.031+08:00
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
258 // 2022-01-27T11:01:49+00:00
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
259 // 2022-01-27T11:01:49Z
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
260 // 20220127T110149Z
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
261
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
262 unsigned walk = 0;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
263 auto worker = [&](unsigned n) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
264 auto ret = ParseDateElem(dateISO + walk, n);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
265 walk += n;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
266 return ret;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
267 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
268 auto skip = [&](char c) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
269 if (dateISO[walk] == c) ++walk;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
270 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
271 auto expect = [&](char c) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
272 if (dateISO[walk] != c) throw exception_time_error();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
273 ++walk;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
274 };
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
275 ret.Y = worker(4);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
276 skip('-');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
277 ret.M = worker(2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
278 skip('-');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
279 ret.D = worker(2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
280 expect('T');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
281 ret.h = worker(2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
282 skip(':');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
283 ret.m = worker(2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
284 skip(':');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
285 ret.s = worker(2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
286 if (dateISO[walk] == '.') {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
287 unsigned base = walk;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
288 ++walk;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
289 while (pfc::char_is_numeric(dateISO[walk])) ++walk;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
290 ret.sfrac = pfc::string_to_float(dateISO + base, walk - base);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
291 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
292 if (dateISO[walk] == '+' || dateISO[walk] == '-') {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
293 bool neg = dateISO[walk] == '-';
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
294 ++walk;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
295 unsigned tz_h = worker(2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
296 if (tz_h >= 24) throw exception_time_error();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
297 skip(':');
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
298 unsigned tz_m = worker(2);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
299 if (tz_m >= 60) throw exception_time_error();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
300 tz_m += tz_h * 60;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
301 ret.tzdelta = neg ? (int)tz_m : -(int)tz_m; // reversed! it's a timezone offset, have to *add* it if timezone has a minus
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
302 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
303 return ret;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
304 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
305 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
306
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
307 t_filetimestamp pfc::filetimestamp_from_string_ISO_8601(const char* dateISO) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
308 try {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
309 auto elems = read_ISO_8601(dateISO);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
310
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
311 SYSTEMTIME st = {};
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
312 st.wDay = 1; st.wMonth = 1;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
313 st.wYear = (WORD)elems.Y;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
314 st.wMonth = (WORD)elems.M;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
315 st.wDay = (WORD)elems.D;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
316 st.wHour = (WORD)elems.h;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
317 st.wMinute = (WORD)elems.m;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
318 st.wSecond = (WORD)elems.s;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
319 st.wMilliseconds = (WORD)floor(elems.sfrac * 1000.f);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
320
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
321 if (!st_sanity(st)) throw exception_time_error();
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
322
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
323 auto ret = ExportSystemTime(st);
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
324
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
325 ret += filetimestamp_1second_increment * elems.tzdelta * 60;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
326
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
327 return ret;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
328 } catch (...) {
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
329 return filetimestamp_invalid;
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
330 }
20d02a178406 *: check in everything else
Paper <paper@tflc.us>
parents:
diff changeset
331 }