14 std::chrono::duration<double>
parseNumberAndUnit(std::stringstream& aStream,
int* aMonths,
int* aYears) {
15 class unitDescriptor {
19 kWithEnlargingPrefix = 1 << 0,
20 kWithDiminishingPrefix = 1 << 1,
21 kWithPrefix = kWithEnlargingPrefix | kWithDiminishingPrefix,
23 kYear = (1 << 3) | kWithEnlargingPrefix ,
24 kSecond = kWithDiminishingPrefix
26 const char *lUnitName;
29 unitDescriptor(decltype(lUnitName) aUnitName,
30 decltype(lFactor) aFactor,
31 decltype(lType) aType):
32 lUnitName(aUnitName), lFactor(aFactor), lType(aType) {
36 static std::vector<unitDescriptor> unitDescriptors({
37 {
"year", 31557500, unitDescriptor::kYear},
38 {
"yr", 31557500, unitDescriptor::kYear},
39 {
"a", 31557500, unitDescriptor::kYear},
40 {
"month", 2629800, unitDescriptor::kMonth},
41 {
"week", 3600 * 24 * 7, unitDescriptor::kUnspecific},
42 {
"day", 3600 * 24, unitDescriptor::kUnspecific},
43 {
"hour", 3600, unitDescriptor::kUnspecific},
44 {
"minute", 60, unitDescriptor::kUnspecific},
45 {
"min", 60, unitDescriptor::kUnspecific},
46 {
"second", 1, unitDescriptor::kSecond},
47 {
"sec", 1, unitDescriptor::kSecond},
48 {
"s", 1, unitDescriptor::kSecond}
52 class prefixDescriptor {
56 std::string::size_type lNameLength;
57 prefixDescriptor(decltype(lName) aName, decltype(lFactor) aFactor) :
58 lName(aName), lFactor(aFactor) {
59 lNameLength = strlen(aName);
62 static std::vector<prefixDescriptor> diminishingPrefixDescriptors ({
71 static std::vector<prefixDescriptor> enlargingPrefixDescriptors ({
84 return std::chrono::duration<double>::zero();
88 std::transform(unit.begin(), unit.end(), unit.begin(), ::tolower);
89 for (
auto& unitDesc : unitDescriptors) {
90 auto location = unit.find(unitDesc.lUnitName);
91 if (location != std::string::npos) {
92 auto unitNameLength = strlen(unitDesc.lUnitName);
93 auto nExtraChars = unit.size() - location - unitNameLength;
94 if (nExtraChars > 0 &&
95 !(nExtraChars == 1 && unitNameLength > 2 && unit.back() ==
's')) {
100 if (!(unitDesc.lType & unitDescriptor::kWithPrefix)) {
104 bool prefixFound =
false;
105 if (unitDesc.lType & unitDescriptor::kWithDiminishingPrefix) {
106 for (
auto& prefix : diminishingPrefixDescriptors) {
107 if (unit.compare(0, location, prefix.lName) == 0) {
108 number /= prefix.lFactor;
114 if (unitDesc.lType & unitDescriptor::kWithEnlargingPrefix) {
115 for (
auto& prefix : enlargingPrefixDescriptors) {
116 if (unit.compare(0, location, prefix.lName) == 0) {
117 number *= prefix.lFactor;
128 if ((unitDesc.lType == unitDescriptor::kYear && aYears) ||
129 (unitDesc.lType == unitDescriptor::kMonth && aMonths)) {
130 if (unitDesc.lType == unitDescriptor::kYear) {
135 return std::chrono::duration<double>::zero();
137 return std::chrono::duration<double>(unitDesc.lFactor * number);
143 return std::chrono::duration<double>::zero();
147 aStream >> aBrokenDownTime->tm_year;
148 if (aStream.fail() || aStream.get() !=
'/') {
151 aStream >> aBrokenDownTime->tm_mon;
152 if (aStream.fail() || aStream.get() !=
'/') {
155 aStream >> aBrokenDownTime->tm_mday;
156 if (aStream.fail()) {
159 aStream >> aBrokenDownTime->tm_hour;
160 if (!aStream.fail()) {
161 if (aStream.get() !=
':') {
164 aStream >> aBrokenDownTime->tm_min;
165 if (aStream.fail()) {
168 if (aStream.peek() ==
':') {
170 aStream >> aFractional;
171 aBrokenDownTime->tm_sec = aFractional;
172 aFractional -= aBrokenDownTime->tm_sec;
173 if (aStream.fail()) {
184 std::string::size_type pointStringStart = 0;
185 std::string::size_type pointStringLength = std::string::npos;
186 std::string::size_type offsetStringStart = std::string::npos;
187 std::string::size_type offsetStringLength = std::string::npos;
188 bool offsetIsNegative =
false;
190 auto after = aString.find(
"after");
192 offsetStringStart = 6;
193 pointStringStart = std::string::npos;
194 }
else if (after != std::string::npos) {
195 offsetStringStart = 0;
196 offsetStringLength = after - 1;
197 pointStringStart = after + 6;
201 auto before = aString.find(
"before");
203 offsetStringStart = 6;
204 pointStringStart = std::string::npos;
205 offsetIsNegative =
true;
206 }
else if (before != std::string::npos) {
207 offsetStringStart = 0;
208 offsetStringLength = before - 1;
209 pointStringStart = before + 7;
210 offsetIsNegative =
true;
214 std::chrono::system_clock::time_point
timePoint;
221 kDay = kToday | kTomorrow | kYesterday | kWeekday,
227 if (pointStringStart < aString.size()) {
228 auto pointString = aString.substr(pointStringStart, pointStringLength);
229 std::transform(pointString.begin(), pointString.end(), pointString.begin(), ::tolower);
231 typename std::underlying_type<dateBitType>::type dateBits = 0;
233 if (pointString.find(
"now") != std::string::npos) {
235 }
else if (pointString.find(
"today") != std::string::npos) {
237 }
else if (pointString.find(
"yesterday") != std::string::npos) {
238 dateBits |= kYesterday;
239 }
else if (pointString.find(
"tomorrow") != std::string::npos) {
240 dateBits |= kTomorrow;
241 }
else if (pointString.find(
"sun") != std::string::npos) {
242 dateBits |= kWeekday;
244 }
else if (pointString.find(
"mon") != std::string::npos) {
245 dateBits |= kWeekday;
247 }
else if (pointString.find(
"tue") != std::string::npos) {
248 dateBits |= kWeekday;
250 }
else if (pointString.find(
"wed") != std::string::npos) {
251 dateBits |= kWeekday;
253 }
else if (pointString.find(
"thu") != std::string::npos) {
254 dateBits |= kWeekday;
256 }
else if (pointString.find(
"fri") != std::string::npos) {
257 dateBits |= kWeekday;
259 }
else if (pointString.find(
"sat") != std::string::npos) {
260 dateBits |= kWeekday;
263 if (pointString.find(
"noon") != std::string::npos) {
266 if (pointString.find(
"last") != std::string::npos) {
269 if (pointString.find(
"this") != std::string::npos) {
274 timePoint = std::chrono::system_clock::now();
275 if (dateBits & kDay) {
276 auto coarse_time = std::chrono::system_clock::to_time_t(
timePoint);
277 auto broken_down_time = std::localtime(&coarse_time);
279 broken_down_time->tm_sec = 0;
280 broken_down_time->tm_min = 0;
281 broken_down_time->tm_hour = (dateBits & kNoon) ? 12 : 0;
282 if (dateBits & kYesterday) {
283 broken_down_time->tm_mday--;
284 }
else if (dateBits & kTomorrow) {
285 broken_down_time->tm_mday++;
286 }
else if (dateBits & kWeekday) {
287 auto dayOffset = weekDay - broken_down_time->tm_wday;
288 if (dateBits & kLast) {
289 if (dayOffset >= 0) {
292 }
else if (dateBits & kThis) {
295 if (dayOffset <= 0) {
299 broken_down_time->tm_mday += dayOffset;
302 timePoint = std::chrono::system_clock::from_time_t(std::mktime(broken_down_time));
305 if (pointString[0] ==
'@') {
306 auto seconds = std::stod(pointString.substr(1));
307 timePoint = std::chrono::system_clock::from_time_t(0) +
308 std::chrono::duration_cast<std::chrono::system_clock::duration>(std::chrono::duration<double>(seconds));
310 std::tm broken_down_time;
311 memset(&broken_down_time, 0,
sizeof(broken_down_time));
312 double fractionalPart;
313 std::stringstream buf(aString.substr(pointStringStart, pointStringLength));
314 std::string timezone;
316 broken_down_time.tm_year -= 1900;
317 broken_down_time.tm_mon--;
318 broken_down_time.tm_isdst = -1;
320 auto oldTZ = getenv(
"TZ");
321 std::string oldTZstring;
325 if (timezone.length() > 2) {
326 std::string tzfilename(TZFILE_PATH);
327 tzfilename += timezone;
329 if (stat(tzfilename.c_str(), &s) < 0) {
333 timezone =
":" + timezone;
334 setenv(
"TZ", timezone.c_str(),
true);
338 timePoint = std::chrono::system_clock::from_time_t(std::mktime(&broken_down_time));
339 timePoint += std::chrono::duration_cast<std::chrono::system_clock::duration>(std::chrono::duration<double>(fractionalPart));
341 if (timezone.length() > 2) {
343 setenv(
"TZ", oldTZstring.c_str(),
true);
356 timePoint = std::chrono::system_clock::now();
359 if (offsetStringStart < aString.size()) {
360 std::chrono::system_clock::duration offset;
361 auto offsetString = aString.substr(offsetStringStart, offsetStringLength);
362 std::transform(offsetString.begin(), offsetString.end(), offsetString.begin(), ::tolower);
368 if (offsetIsNegative) {
373 if (months != 0 || years != 0) {
374 auto coarse_time = std::chrono::system_clock::to_time_t(
timePoint);
375 auto fractionalPart =
timePoint - std::chrono::system_clock::from_time_t(coarse_time);
376 auto broken_down_time = std::localtime(&coarse_time);
377 if (offsetIsNegative) {
378 broken_down_time->tm_mon -= months;
379 broken_down_time->tm_year -= years;
381 broken_down_time->tm_mon += months;
382 broken_down_time->tm_year += years;
384 timePoint = std::chrono::system_clock::from_time_t(std::mktime(broken_down_time));
394 auto flags(aStream.flags());
395 aStream << std::fixed;
396 aStream << std::chrono::duration<double>(aValue.time_since_epoch()).count();
397 aStream.flags(flags);
400 internal::typed_base<std::chrono::system_clock::time_point>(aShortName, aLongName, aExplanation, 1),
402 *
static_cast<valueType*
>(
this) = aDefault;
403 if (!aRange.empty()) {
408 internal::typed_base<std::chrono::system_clock::time_point>(aShortName, aLongName, aExplanation, 1),
412 }
catch (
const std::runtime_error& e) {
415 lOriginalString = aDefault;
416 if (!aRange.empty()) {
422 std::getline(aStream, lOriginalString);
425 }
catch (
const std::runtime_error& e) {
432 aStream <<
"# allowed range is";
435 lValuePrinter(aStream,
lRange[0]);
437 lValuePrinter(aStream,
lRange[1]);
440 for (
auto& rangeElement :
lRange) {
441 lValuePrinter(aStream, rangeElement);
450 lValuePrinter(aStream, *
this);
453 using escapedIO::operator>>;
454 aStream >> lOriginalString;
457 }
catch (
const std::runtime_error& e) {
464 namespace escapedIO {
465 std::ostream&
operator<<(std::ostream& aStream,
const std::chrono::system_clock::time_point& aTime) {
469 std::istream&
operator>>(std::istream& aStream, std::chrono::system_clock::time_point& aTime) {
472 if (!aStream.fail()) {