MSTL 1.4.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
datetime.hpp
1#ifndef MSTL_CORE_TIME_DATETIME_HPP__
2#define MSTL_CORE_TIME_DATETIME_HPP__
3#include "../string/format.hpp"
4#include "../utility/packages.hpp"
6
8MSTL_INLINE17 static constexpr int32_t MONTH_DAYS[12] = {
9 31, 28, 31, 30, 31, 30,
10 31, 31, 30, 31, 30, 31
11};
13
14class MSTL_API date : public iobject<date>, public icommon<date> {
15public:
16 using date_type = int32_t;
17
18private:
19 date_type year_ = 1970;
20 date_type month_ = 1;
21 date_type day_ = 1;
22
23public:
24 constexpr date() noexcept = default;
25
26 constexpr explicit date(
27 const date_type year, const date_type month, const date_type day) noexcept {
28 if (is_valid(year, month, day)) {
29 year_ = year;
30 month_ = month;
31 day_ = day;
32 }
33 }
34
35 constexpr date(const date& d) noexcept : year_(d.year_), month_(d.month_), day_(d.day_) {}
36
37 constexpr date& operator =(const date& d) noexcept {
38 year_ = d.year_;
39 month_ = d.month_;
40 day_ = d.day_;
41 return *this;
42 }
43
44 constexpr date(date&& d) noexcept : year_(d.year_), month_(d.month_), day_(d.day_) {
45 d.clear();
46 }
47 constexpr date& operator =(date&& d) noexcept {
48 year_ = d.year_;
49 month_ = d.month_;
50 day_ = d.day_;
51 d.clear();
52 return *this;
53 }
54
55 MSTL_CONSTEXPR20 ~date() = default;
56
57
58 MSTL_NODISCARD constexpr date_type year() const noexcept { return year_; }
59 MSTL_NODISCARD constexpr date_type month() const noexcept { return month_; }
60 MSTL_NODISCARD constexpr date_type day() const noexcept { return day_; }
61
62 static constexpr bool is_valid(date_type y, date_type m, date_type d) noexcept {
63 if (y < 1900 || y > 9999) return false;
64 if (m < 1 || m > 12) return false;
65 return d > 0 && d <= days_of_month(y, m);
66 }
67
68
69 static constexpr date epoch() noexcept {
70 return date{};
71 }
72
73 static constexpr bool is_leap_year(const date_type year) noexcept {
74 return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
75 }
76
77
78 MSTL_NODISCARD constexpr date_type days_of_week() const noexcept {
79 date_type y = year_;
80 date_type m = month_;
81 const date_type d = day_;
82 if (m < 3) {
83 y--;
84 m += 12;
85 }
86 return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400 + 1) % 7;
87 }
88
89 static constexpr date_type days_of_month(
90 const date_type year, const date_type month) noexcept {
91 date_type day = _CONSTANTS MONTH_DAYS[month - 1];
92 if (month == 2 && is_leap_year(year)) {
93 day += 1;
94 }
95 return day;
96 }
97
98 MSTL_NODISCARD constexpr date_type days_of_year() const noexcept {
99 date_type days = 0;
100 for (date_type i = 1; i < month_; ++i) {
101 days += days_of_month(year_, i);
102 }
103 return days + day_;
104 }
105
106
107 constexpr void clear() noexcept {
108 year_ = 1970;
109 month_ = 1;
110 day_ = 1;
111 }
112
113
114 constexpr bool operator ==(const date& d) const noexcept {
115 return year_ == d.year_ && month_ == d.month_ && day_ == d.day_;
116 }
117
118 constexpr bool operator <(const date& d) const noexcept {
119 if (year_ < d.year_) return true;
120 if (year_ == d.year_ && month_ < d.month_) return true;
121 if (year_ == d.year_ && month_ == d.month_ && day_ < d.day_) return true;
122 return false;
123 }
124
125 constexpr date& operator +=(const date_type day) noexcept {
126 if (day == 0) return *this;
127 if (day < 0) return *this -= -day;
128
129 if (day > 365) {
130 const int64_t jd = to_julian_day(year_, month_, day_) + day;
131 *this = from_julian_day(jd);
132 return *this;
133 }
134
135 date_type remaining = day;
136 while (remaining > 0) {
137 const date_type days_in_month = days_of_month(year_, month_);
138 const date_type available = days_in_month - day_ + 1;
139
140 if (remaining < available) {
141 day_ += remaining;
142 break;
143 }
144
145 remaining -= available;
146 day_ = 1;
147 if (++month_ > 12) {
148 month_ = 1;
149 ++year_;
150 }
151 }
152 return *this;
153 }
154
155 constexpr date& operator -=(const date_type day) noexcept {
156 if (day < 0) return *this += -day;
157
158 day_ -= day;
159 while (day_ <= 0) {
160 if (--month_ == 0) {
161 month_ = 12;
162 year_--;
163 }
164 day_ += days_of_month(year_, month_);
165 }
166 return *this;
167 }
168
169 constexpr date operator +(const date_type day) const noexcept {
170 date ret(*this);
171 ret += day;
172 return ret;
173 }
174
175 constexpr date operator -(const date_type day) const noexcept {
176 date ret(*this);
177 ret -= day;
178 return ret;
179 }
180
181 constexpr date& operator ++() {
182 *this += 1;
183 return *this;
184 }
185 constexpr date operator ++(int) {
186 const date ret(*this);
187 *this += 1;
188 return ret;
189 }
190
191 constexpr date_type operator -(const date& d) const noexcept {
192 return static_cast<date_type>(to_julian_day(year_, month_, day_) - to_julian_day(d.year_, d.month_, d.day_));
193 }
194
195 MSTL_NODISCARD constexpr size_t to_hash() const noexcept {
196 constexpr hash<date_type> hasher;
197 return hasher(day()) ^ hasher(month()) ^ hasher(year());
198 }
199
200 MSTL_NODISCARD MSTL_CONSTEXPR20 string to_string() const {
201 return _MSTL format("{:04d}-{:02d}-{:02d}", year(), month(), day());
202 }
203
204 MSTL_NODISCARD constexpr static date parse(const string_view str) {
205 if (str.size() != 10 || str[4] != '-' || str[7] != '-') {
206 throw_exception(value_exception("Wrong string formation."));
207 }
208 const date_type year = integer32::parse(str.substr(0, 4));
209 const date_type month = integer32::parse(str.substr(5, 2));
210 const date_type day = integer32::parse(str.substr(8, 2));
211 return date(year, month, day);
212 }
213
214 constexpr void swap(date& d) noexcept {
215 _MSTL swap(year_, d.year_);
216 _MSTL swap(month_, d.month_);
217 _MSTL swap(day_, d.day_);
218 }
219
220 static constexpr int64_t to_julian_day(
221 const date_type y, const date_type m, const date_type d) noexcept {
222 const int64_t a = (14 - m) / 12;
223 const int64_t year = y + 4800 - a;
224 const int64_t month = m + 12 * a - 3;
225 return d + (153 * month + 2) / 5 + 365 * year + year / 4 - year / 100 + year / 400 - 32045;
226 }
227
228 static constexpr date from_julian_day(const int64_t jd) noexcept {
229 const int64_t a = jd + 32044;
230 const int64_t b = (4 * a + 3) / 146097;
231 const int64_t c = a - (146097 * b) / 4;
232 const int64_t d = (4 * c + 3) / 1461;
233 const int64_t e = c - (1461 * d) / 4;
234 const int64_t m = (5 * e + 2) / 153;
235
236 const date_type day = static_cast<date_type>(e - (153 * m + 2) / 5 + 1);
237 const date_type month = static_cast<date_type>(m + 3 - 12 * (m / 10));
238 const date_type year = static_cast<date_type>(100 * b + d - 4800 + (m / 10));
239
240 return date(year, month, day);
241 }
242};
243
244
245class MSTL_API time : public iobject<time>, public icommon<time> {
246public:
247 using time_type = int32_t;
248
249private:
250 time_type hours_ = 0;
251 time_type minutes_ = 0;
252 time_type seconds_ = 0;
253
254public:
255 constexpr explicit time(const time_type h = 0,
256 const time_type m = 0, const time_type s = 0) noexcept {
257 if (is_valid(h, m, s)) {
258 hours_ = h;
259 minutes_ = m;
260 seconds_ = s;
261 }
262 }
263
264 constexpr time(const time& t) noexcept : hours_(t.hours_), minutes_(t.minutes_), seconds_(t.seconds_) {}
265 constexpr time& operator =(const time& t) noexcept {
266 hours_ = t.hours_;
267 minutes_ = t.minutes_;
268 seconds_ = t.seconds_;
269 return *this;
270 }
271
272 constexpr time(time&& t) noexcept : hours_(t.hours_), minutes_(t.minutes_), seconds_(t.seconds_) {
273 t.clear();
274 }
275 constexpr time& operator =(time&& t) noexcept {
276 hours_ = t.hours_;
277 minutes_ = t.minutes_;
278 seconds_ = t.seconds_;
279 t.clear();
280 return *this;
281 }
282
283 MSTL_CONSTEXPR20 ~time() = default;
284
285
286 MSTL_NODISCARD constexpr time_type hours() const noexcept { return hours_; }
287 MSTL_NODISCARD constexpr time_type minutes() const noexcept { return minutes_; }
288 MSTL_NODISCARD constexpr time_type seconds() const noexcept { return seconds_; }
289
290 static constexpr bool is_valid(time_type h, time_type m, time_type s) noexcept {
291 return h >= 0 && h < 24 && m >= 0 && m < 60 && s >= 0 && s < 60;
292 }
293
294 constexpr void clear() noexcept {
295 hours_ = 0;
296 minutes_ = 0;
297 seconds_ = 0;
298 }
299
300
301 constexpr bool operator ==(const time& other) const noexcept {
302 return hours_ == other.hours_ && minutes_ == other.minutes_ && seconds_ == other.seconds_;
303 }
304
305 constexpr bool operator <(const time& other) const noexcept {
306 if (hours_ < other.hours_) return true;
307 if (hours_ == other.hours_) {
308 if (minutes_ < other.minutes_) return true;
309 if (minutes_ == other.minutes_ && seconds_ < other.seconds_) return true;
310 }
311 return false;
312 }
313
314
315 constexpr time& operator +=(const time_type seconds) {
316 if (seconds < 0) return *this -= -seconds;
317
318 seconds_ += seconds;
319 const time_type extra_min = seconds_ / 60;
320 seconds_ %= 60;
321
322 minutes_ += extra_min;
323 const time_type extra_hour = minutes_ / 60;
324 minutes_ %= 60;
325
326 hours_ += extra_hour;
327 hours_ %= 24;
328
329 return *this;
330 }
331
332 constexpr time& operator -=(const time_type seconds) noexcept {
333 if (seconds < 0) return *this += -seconds;
334
335 int64_t total_sec = to_seconds() - seconds;
336 total_sec %= 86400;
337 if (total_sec < 0) total_sec += 86400;
338
339 hours_ = static_cast<time_type>(total_sec / 3600);
340 minutes_ = static_cast<time_type>((total_sec % 3600) / 60);
341 seconds_ = static_cast<time_type>(total_sec % 60);
342 return *this;
343 }
344
345 constexpr time operator +(const time_type seconds) const noexcept {
346 time ret(*this);
347 ret += seconds;
348 return ret;
349 }
350
351 constexpr time operator -(const time_type seconds) const noexcept {
352 time ret(*this);
353 ret -= seconds;
354 return ret;
355 }
356
357 constexpr time& operator ++() { return *this += 1; }
358 constexpr time operator ++(int) {
359 const time ret(*this);
360 *this += 1;
361 return ret;
362 }
363 constexpr time& operator --() { return *this -= 1; }
364 constexpr time operator --(int) {
365 const time ret(*this);
366 *this -= 1;
367 return ret;
368 }
369
370 constexpr time_type operator -(const time& other) const noexcept {
371 time_type sec_diff = (hours_ - other.hours_) * 3600;
372 sec_diff += (minutes_ - other.minutes_) * 60;
373 sec_diff += (seconds_ - other.seconds_);
374 return sec_diff;
375 }
376
377
378 MSTL_NODISCARD constexpr time_type to_seconds() const noexcept {
379 return hours_ * 3600 + minutes_ * 60 + seconds_;
380 }
381
382 MSTL_NODISCARD constexpr size_t to_hash() const noexcept {
383 constexpr hash<time_type> hasher;
384 return hasher(hours()) ^ hasher(minutes()) ^ hasher(seconds());
385 }
386
387 MSTL_NODISCARD MSTL_CONSTEXPR20 string to_string() const {
388 return _MSTL format("{:02d}:{:02d}:{:02d}", hours(), minutes(), seconds());
389 }
390
391 MSTL_NODISCARD static constexpr time parse(const string_view str) {
392 if (str.size() != 8 || str[2] != ':' || str[5] != ':') {
393 throw_exception(value_exception("Wrong string formation."));
394 }
395 const time_type h = integer32::parse(str.substr(0, 2));
396 const time_type m = integer32::parse(str.substr(3, 2));
397 const time_type s = integer32::parse(str.substr(6, 2));
398 return time(h, m, s);
399 }
400
401 constexpr void swap(time& other) noexcept {
402 _MSTL swap(hours_, other.hours_);
403 _MSTL swap(minutes_, other.minutes_);
404 _MSTL swap(seconds_, other.seconds_);
405 }
406};
407
408
410
411MSTL_INLINE17 constexpr const char* const WEEKDAYS_STRING[] =
412 {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
413
414MSTL_INLINE17 constexpr const char* const MONTHS_STRING[] =
415 {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
416
418
419constexpr int months_to_int(const string_view sv) {
420 for (int i = 0; i < 12; ++i) {
421 if (sv == _CONSTANTS MONTHS_STRING[i]) return i + 1;
422 }
423 return 0;
424}
425
426
427class MSTL_API datetime : public iobject<datetime>, public icommon<datetime> {
428public:
429 using date_type = _MSTL date::date_type;
430 using time_type = _MSTL time::time_type;
431
432private:
433 _MSTL date date_{};
434 _MSTL time time_{};
435 int64_t offset_seconds_ = 0;
436 bool has_timezone_ = false;
437
438public:
439 constexpr datetime() noexcept = default;
440
441 constexpr datetime(const datetime& dt) noexcept
442 : date_(dt.date_), time_(dt.time_),
443 offset_seconds_(dt.offset_seconds_), has_timezone_(dt.has_timezone_) {}
444
445 constexpr datetime& operator =(const datetime& dt) noexcept {
446 date_ = dt.date_;
447 time_ = dt.time_;
448 offset_seconds_ = dt.offset_seconds_;
449 has_timezone_ = dt.has_timezone_;
450 return *this;
451 }
452
453 constexpr datetime(datetime&& dt) noexcept
454 : date_(dt.date_), time_(dt.time_), offset_seconds_(dt.offset_seconds_),
455 has_timezone_(dt.has_timezone_) {
456 dt.clear();
457 }
458
459 constexpr datetime& operator =(datetime&& dt) noexcept {
460 date_ = dt.date_;
461 time_ = dt.time_;
462 offset_seconds_ = dt.offset_seconds_;
463 has_timezone_ = dt.has_timezone_;
464 dt.clear();
465 return *this;
466 }
467
468 constexpr explicit datetime(const date_type year, const date_type month, const date_type day,
469 const time_type hour, const time_type minute, const time_type second) noexcept
470 : date_(year, month, day), time_(hour, minute, second) {}
471
472 constexpr explicit datetime(const date_type year, const date_type month, const date_type day,
473 const time_type hour, const time_type minute, const time_type second, const int64_t offset) noexcept
474 : date_(year, month, day), time_(hour, minute, second), offset_seconds_(offset), has_timezone_(true) {}
475
476 constexpr explicit datetime(const _MSTL date& d, const _MSTL time& t) noexcept
477 : date_(d), time_(t) {}
478
479 constexpr explicit datetime(const _MSTL date& d, const _MSTL time& t, const int64_t offset) noexcept
480 : date_(d), time_(t), offset_seconds_(offset), has_timezone_(true) {}
481
482 constexpr explicit datetime(_MSTL date&& d, _MSTL time&& t) noexcept
483 : date_(d), time_(t) {
484 d.clear();
485 t.clear();
486 }
487
488 constexpr explicit datetime(_MSTL date&& d, _MSTL time&& t, const int64_t offset) noexcept
489 : date_(d), time_(t), offset_seconds_(offset), has_timezone_(true) {
490 d.clear();
491 t.clear();
492 }
493
494 constexpr explicit datetime(const _MSTL date& d) noexcept : date_(d) {}
495
496 constexpr datetime& operator =(const _MSTL date& d) noexcept {
497 date_ = d;
498 return *this;
499 }
500
501 constexpr explicit datetime(_MSTL date&& d) noexcept : date_(d) {
502 d.clear();
503 }
504
505 constexpr datetime& operator =(_MSTL date&& d) noexcept {
506 date_ = d;
507 d.clear();
508 return *this;
509 }
510
511 constexpr explicit datetime(const _MSTL time& t) noexcept : time_(t) {}
512
513 constexpr datetime& operator =(const _MSTL time& t) noexcept {
514 time_ = t;
515 return *this;
516 }
517
518 constexpr explicit datetime(_MSTL time&& t) noexcept : time_(t) {
519 t.clear();
520 }
521
522 constexpr datetime& operator =(_MSTL time&& t) noexcept {
523 time_ = t;
524 t.clear();
525 return *this;
526 }
527
528 MSTL_CONSTEXPR20 ~datetime() = default;
529
530
531 MSTL_NODISCARD constexpr const _MSTL date& date() const noexcept { return date_; }
532 MSTL_NODISCARD constexpr const _MSTL time& time() const noexcept { return time_; }
533
534 MSTL_NODISCARD constexpr time_type hours() const noexcept { return time_.hours(); }
535 MSTL_NODISCARD constexpr time_type minutes() const noexcept { return time_.minutes(); }
536 MSTL_NODISCARD constexpr time_type seconds() const noexcept { return time_.seconds(); }
537 MSTL_NODISCARD constexpr date_type year() const noexcept { return date_.year(); }
538 MSTL_NODISCARD constexpr date_type month() const noexcept { return date_.month(); }
539 MSTL_NODISCARD constexpr date_type day() const noexcept { return date_.day(); }
540
541 MSTL_NODISCARD constexpr bool has_timezone() const noexcept { return has_timezone_; }
542 MSTL_NODISCARD constexpr int64_t offset_seconds() const noexcept { return offset_seconds_; }
543
544 MSTL_NODISCARD static constexpr datetime epoch() noexcept { return datetime{}; }
545 MSTL_NODISCARD static datetime now() noexcept;
546
547 constexpr void clear() noexcept {
548 date_.clear();
549 time_.clear();
550 offset_seconds_ = 0;
551 has_timezone_ = false;
552 }
553
554
555 constexpr bool operator ==(const datetime& other) const noexcept {
556 return date_ == other.date_ && time_ == other.time_
557 && has_timezone_ == other.has_timezone_
558 && offset_seconds_ == other.offset_seconds_;
559 }
560
561 constexpr bool operator <(const datetime& other) const noexcept {
562 if (date_ < other.date_) {
563 return true;
564 } else if (date_ == other.date_) {
565 if (time_ < other.time_) {
566 return true;
567 } else if (time_ == other.time_) {
568 if (has_timezone_ && other.has_timezone_ &&
569 offset_seconds_ < other.offset_seconds_) {
570 return true;
571 }
572 }
573 }
574 return false;
575 }
576
577
578 constexpr datetime& operator +=(const int64_t seconds) {
579 if (seconds < 0) return *this -= -seconds;
580
581 const int64_t current_total_sec =
582 static_cast<int64_t>(time_.hours()) * 3600 +
583 static_cast<int64_t>(time_.minutes()) * 60 +
584 static_cast<int64_t>(time_.seconds());
585
586 int64_t new_total_sec = current_total_sec + seconds;
587 int64_t days_to_add = new_total_sec / 86400;
588 new_total_sec %= 86400;
589
590 if (new_total_sec < 0) {
591 new_total_sec += 86400;
592 days_to_add--;
593 }
594
595 date_ += static_cast<date_type>(days_to_add);
596 time_ = _MSTL time(
597 static_cast<time_type>(new_total_sec / 3600),
598 static_cast<time_type>((new_total_sec % 3600) / 60),
599 static_cast<time_type>(new_total_sec % 60)
600 );
601 return *this;
602 }
603
604 constexpr datetime& operator -=(const int64_t seconds) noexcept {
605 if (seconds < 0) return *this += -seconds;
606
607 const int64_t current_total_sec =
608 static_cast<int64_t>(time_.hours()) * 3600 +
609 static_cast<int64_t>(time_.minutes()) * 60 +
610 static_cast<int64_t>(time_.seconds());
611
612 int64_t new_total_sec = current_total_sec - seconds;
613 int64_t days_to_subtract = 0;
614
615 if (new_total_sec < 0) {
616 days_to_subtract = (-new_total_sec + 86399) / 86400;
617 new_total_sec += days_to_subtract * 86400;
618 }
619
620 date_ -= static_cast<date_type>(days_to_subtract);
621 time_ = _MSTL time(
622 static_cast<time_type>(new_total_sec / 3600),
623 static_cast<time_type>((new_total_sec % 3600) / 60),
624 static_cast<time_type>(new_total_sec % 60)
625 );
626 return *this;
627 }
628
629 constexpr datetime operator +(const int64_t seconds) const noexcept {
630 datetime ret(*this);
631 ret += seconds;
632 return ret;
633 }
634
635 constexpr datetime operator -(const int64_t seconds) const noexcept {
636 datetime ret(*this);
637 ret -= seconds;
638 return ret;
639 }
640
641 constexpr datetime& operator ++() { return *this += 1; }
642 constexpr datetime operator ++(int) {
643 const datetime ret(*this);
644 *this += 1;
645 return ret;
646 }
647 constexpr datetime& operator --() { return *this -= 1; }
648 constexpr datetime operator --(int) {
649 const datetime ret(*this);
650 *this -= 1;
651 return ret;
652 }
653
654 constexpr time_type operator -(const datetime& other) const noexcept {
655 const time_type day_diff = date_ - other.date_;
656 time_type sec_diff = day_diff * 86400;
657 sec_diff += (time_ - other.time_);
658 return sec_diff;
659 }
660
661
662 MSTL_NODISCARD MSTL_CONSTEXPR20 string to_offset_string() const {
663 if (!has_timezone_) return {};
664 if (offset_seconds_ == 0) return "Z";
665 int64_t total_sec = offset_seconds_;
666 const char sign = total_sec >= 0 ? '+' : '-';
667 total_sec = total_sec >= 0 ? total_sec : -total_sec;
668 const int64_t hours = total_sec / 3600;
669 const int64_t minutes = (total_sec % 3600) / 60;
670 return _MSTL format("{}{:02d}:{:02d}", sign, hours, minutes);
671 }
672
673
674 static constexpr datetime from_UTC(const datetime& utc_dt, const int32_t offset_sec = 0) noexcept {
675 datetime utc_time = utc_dt;
676 if (utc_dt.has_timezone_ && utc_dt.offset_seconds_ != 0) {
677 utc_time = utc_dt.to_UTC();
678 }
679 datetime local = utc_time + offset_sec;
680 local.offset_seconds_ = offset_sec;
681 local.has_timezone_ = true;
682 return local;
683 }
684
685 MSTL_NODISCARD constexpr datetime to_UTC() const noexcept {
686 if (!has_timezone_) {
687 return *this;
688 }
689 datetime utc = *this;
690 utc -= offset_seconds_;
691 utc.offset_seconds_ = 0;
692 utc.has_timezone_ = true;
693 return utc;
694 }
695
696
697 MSTL_NODISCARD MSTL_CONSTEXPR20 string to_string_ISO_UTC() const {
698 if (has_timezone_) {
699 return date_.to_string() + "T" + time_.to_string() + to_offset_string();
700 } else {
701 return date_.to_string() + "T" + time_.to_string();
702 }
703 }
704
705 MSTL_NODISCARD static constexpr datetime parse_ISO_UTC(const string_view str) {
706 if (str.size() < 20 || str[10] != 'T') {
707 throw_exception(value_exception("Invalid ISO UTC datetime format."));
708 }
709
710 const _MSTL date d = date::parse(str.substr(0, 10));
711 const _MSTL time t = time::parse(str.substr(11, 8));
712
713 if (str.size() > 19 && str[19] == 'Z') {
714 return datetime(d, t, 0);
715 } else if (str.size() > 19 && (str[19] == '+' || str[19] == '-')) {
716 const char sign = str[19];
717 int hours = 0, minutes = 0;
718 size_t pos = 20;
719 if (str.size() >= pos + 2) {
720 hours = integer32::parse(str.substr(pos, 2));
721 pos += 2;
722 if (str.size() >= pos + 3 && str[pos] == ':') {
723 pos++;
724 if (str.size() >= pos + 2) {
725 minutes = integer32::parse(str.substr(pos, 2));
726 }
727 }
728 }
729
730 int32_t total_offset = hours * 3600 + minutes * 60;
731 if (sign == '-') total_offset = -total_offset;
732 return datetime(d, t, total_offset);
733 }
734 return datetime(d, t);
735 }
736
737 MSTL_CONSTEXPR20 bool try_parse_ISO_UTC(string_view str) noexcept {
738 try {
739 datetime tmp = datetime::parse_ISO_UTC(str);
740 this->swap(tmp);
741 } catch (...) {
742 return false;
743 }
744 return true;
745 }
746
747
748 MSTL_NODISCARD MSTL_CONSTEXPR20 string to_string_GMT() const noexcept {
749 const _MSTL date utc_date = date();
750 const _MSTL time utc_time = time();
751
752 int wday = utc_date.days_of_week();
753 if (wday < 0 || wday >= 7) wday = 0;
754
755 int mon_idx = utc_date.month() - 1;
756 if (mon_idx < 0 || mon_idx >= 12) mon_idx = 0;
757
758 return _MSTL format("{}, {:02d} {} {} {} GMT",
759 _CONSTANTS WEEKDAYS_STRING[wday],
760 utc_date.day(),
761 _CONSTANTS MONTHS_STRING[mon_idx],
762 utc_date.year(),
763 utc_time.to_string()
764 );
765 }
766
767 MSTL_NODISCARD static constexpr datetime parse_GMT(string_view str) {
768 if (str.size() < 29) {
769 throw_exception(value_exception("Invalid date length."));
770 }
771 if (str.substr(3, 2) != ", ") {
772 throw_exception(value_exception("Invalid date format"));
773 }
774
775 str.remove_prefix(5);
776 const int day = integer32::parse(str.substr(0, 2));
777 str.remove_prefix(3);
778 const int mon = months_to_int(str.substr(0, 3));
779 if (mon == 0) throw_exception(value_exception("Invalid month in date"));
780 str.remove_prefix(4);
781 const int year = integer32::parse(str.substr(0, 4));
782 str.remove_prefix(5);
783 const int hour = integer32::parse(str.substr(0, 2));
784 str.remove_prefix(3);
785 const int minute = integer32::parse(str.substr(0, 2));
786 str.remove_prefix(3);
787 const int second = integer32::parse(str.substr(0, 2));
788 str.remove_prefix(3);
789
790 if (str != "GMT") {
791 throw_exception(value_exception("Invalid timezone in date"));
792 }
793 return datetime(year, mon, day, hour, minute, second);
794 }
795
796 MSTL_CONSTEXPR20 bool try_parse_GMT(const string_view str) noexcept {
797 try {
798 datetime tmp = datetime::parse_GMT(str);
799 this->swap(tmp);
800 } catch (...) {
801 return false;
802 }
803 return true;
804 }
805
806
807 MSTL_NODISCARD MSTL_CONSTEXPR20 string to_string_ISO() const {
808 return date_.to_string() + "T" + time_.to_string();
809 }
810
811 MSTL_NODISCARD static constexpr datetime parse_ISO(const string_view str) {
812 if (str.size() < 19 || str[10] != 'T') {
813 throw_exception(value_exception("Invalid ISO datetime format."));
814 }
815 const _MSTL date d = _MSTL date::parse(str.substr(0, 10));
816 size_t time_len = 8;
817 if (str.size() >= 19) {
818 time_len = 8;
819 }
820 const _MSTL time t = _MSTL time::parse(str.substr(11, time_len));
821 return datetime(d, t);
822 }
823
824 MSTL_CONSTEXPR20 bool try_parse_ISO(const string_view str) noexcept {
825 try {
826 datetime tmp = datetime::parse_ISO(str);
827 this->swap(tmp);
828 } catch (...) {
829 return false;
830 }
831 return true;
832 }
833
834
835 MSTL_NODISCARD MSTL_CONSTEXPR20 string to_string() const {
836 return date_.to_string() + " " + time_.to_string();
837 }
838
839 MSTL_NODISCARD static constexpr datetime parse(const string_view str) {
840 if (str.size() != 19 || str[10] != ' ') {
841 throw_exception(value_exception("Wrong string formation."));
842 }
843 const _MSTL date d = date::parse(str.substr(0, 10));
844 const _MSTL time t = time::parse(str.substr(11, 8));
845 return datetime(d, t);
846 }
847
848 MSTL_NODISCARD constexpr size_t to_hash() const noexcept {
849 return date_.to_hash() ^ time_.to_hash() ^
850 hash<bool>()(has_timezone_) ^ hash<int64_t>()(offset_seconds_);
851 }
852
853 constexpr void swap(datetime& other) noexcept {
854 _MSTL swap(date_, other.date_);
855 _MSTL swap(time_, other.time_);
856 _MSTL swap(offset_seconds_, other.offset_seconds_);
857 _MSTL swap(has_timezone_, other.has_timezone_);
858 }
859};
860
861
862class MSTL_API timestamp : public iobject<timestamp>, public ipackage<timestamp, int64_t> {
863public:
864 using value_type = int64_t;
865
866 constexpr timestamp() noexcept = default;
867
868 constexpr timestamp(const timestamp &timestamp) noexcept
869 : ipackage(timestamp.value_) {}
870
871 constexpr timestamp& operator =(const timestamp &timestamp) noexcept {
872 value_ = timestamp.value_;
873 return *this;
874 }
875
876 constexpr timestamp(timestamp&& timestamp) noexcept
877 : ipackage(timestamp.value_) {
878 timestamp.clear();
879 }
880
881 constexpr timestamp& operator =(timestamp&& timestamp) noexcept {
882 value_ = timestamp.value_;
883 timestamp.clear();
884 return *this;
885 }
886
887 constexpr explicit timestamp(const value_type sec) noexcept
888 : ipackage(sec) {}
889
890 constexpr explicit timestamp(const datetime& dt) noexcept {
891 value_ = dt - datetime::epoch();
892 }
893
894 MSTL_CONSTEXPR20 ~timestamp() = default;
895
896
897 MSTL_NODISCARD static timestamp now() noexcept {
898 return timestamp(datetime::now());
899 }
900
901 MSTL_NODISCARD constexpr datetime to_datetime() const noexcept {
902 return datetime::epoch() + value_;
903 }
904
905 MSTL_NODISCARD MSTL_CONSTEXPR20 string to_string() const {
906 return integer64(value_).to_string();
907 }
908
909 MSTL_NODISCARD static constexpr timestamp parse(const string_view str) {
910 return timestamp{integer64::parse(str)};
911 }
912
913 constexpr void clear() noexcept {
914 value_ = 0;
915 }
916};
917
919#endif // MSTL_CORE_TIME_DATETIME_HPP__
long long int64_t
64位有符号整数类型
int int32_t
32位有符号整数类型
duration< int64_t, ratio< 86400 > > days
天持续时间
duration< int64_t, ratio< 3600 > > hours
小时持续时间
duration< int64_t, ratio< 60 > > minutes
分钟持续时间
duration< int64_t > seconds
秒持续时间
bool operator==(const function< Res(Args...)> &f, nullptr_t null) noexcept
等于空指针比较
MSTL_CONSTEXPR14 int sign(const T &value) noexcept
获取数值的符号
#define _MSTL
全局命名空间MSTL前缀
#define MSTL_END_CONSTANTS__
结束constants命名空间
#define _CONSTANTS
constants命名空间前缀
#define MSTL_BEGIN_CONSTANTS__
开始constants命名空间
#define MSTL_END_NAMESPACE__
结束全局命名空间MSTL
#define MSTL_BEGIN_NAMESPACE__
开始全局命名空间MSTL
MSTL_NODISCARD constexpr normal_iterator< Iterator > operator+(iter_difference_t< normal_iterator< Iterator > > n, const normal_iterator< Iterator > &iter) noexcept
加法运算符
MSTL_NODISCARD constexpr auto operator-(const normal_iterator< LeftIter > &lhs, const normal_iterator< RightIter > &rhs) noexcept -> decltype(lhs.base() - rhs.base())
减法运算符
MSTL_NODISCARD constexpr bool operator<(const normal_iterator< LeftIter > &lhs, const normal_iterator< RightIter > &rhs) noexcept
小于比较运算符
void swap()=delete
删除无参数的swap重载
通用接口,同时具备可比较和可哈希功能
MSTL_NODISCARD constexpr size_t to_hash() const noexcept(noexcept(derived().to_hash()))
获取对象的哈希值