NexusForce 1.0.0
A Modern C++ Library with extended functionality, web components, and utility libraries
载入中...
搜索中...
未找到
datetime.hpp
浏览该文件的文档.
1#ifndef NEFORCE_CORE_TIME_DATETIME_HPP__
2#define NEFORCE_CORE_TIME_DATETIME_HPP__
3
16
18NEFORCE_BEGIN_NAMESPACE__
19
83
91class NEFORCE_API date : public iobject<date>, public icommon<date> {
92public:
94
95private:
96 date_type year_ = 1970;
97 date_type month_ = 1;
98 date_type day_ = 1;
99
100public:
104 static constexpr int32_t month_days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
105
106public:
110 constexpr date() noexcept = default;
111
112 NEFORCE_CONSTEXPR20 ~date() = default;
113
122 constexpr explicit date(date_type year, const date_type month, const date_type day) noexcept {
123 if (is_valid(year, month, day)) {
124 year_ = year;
125 month_ = month;
126 day_ = day;
127 }
128 }
129
130 constexpr date(const date&) noexcept = default;
131 constexpr date& operator=(const date&) noexcept = default;
132 constexpr date(date&&) noexcept = default;
133 constexpr date& operator=(date&&) noexcept = default;
134
139 NEFORCE_NODISCARD constexpr date_type year() const noexcept { return year_; }
140
145 NEFORCE_NODISCARD constexpr date_type month() const noexcept { return month_; }
146
151 NEFORCE_NODISCARD constexpr date_type day() const noexcept { return day_; }
152
160 static constexpr bool is_valid(date_type year, date_type month, date_type day) noexcept {
161 if (year < 1900 || year > 9999) {
162 return false;
163 }
164 if (month < 1 || month > 12) {
165 return false;
166 }
167 return day > 0 && day <= days_of_month(year, month);
168 }
169
174 constexpr bool is_valid() const noexcept { return is_valid(year_, month_, day_); }
175
180 static constexpr date epoch() noexcept { return date{}; }
181
187 static constexpr bool is_leap_year(const date_type year) noexcept {
188 return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
189 }
190
195 NEFORCE_NODISCARD constexpr date_type days_of_week() const noexcept {
196 date_type y = year_;
197 date_type m = month_;
198 const date_type d = day_;
199 if (m < 3) {
200 y--;
201 m += 12;
202 }
203 return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400 + 1) % 7;
204 }
205
212 static constexpr date_type days_of_month(const date_type year, const date_type month) noexcept {
214 if (month == 2 && is_leap_year(year)) {
215 day += 1;
216 }
217 return day;
218 }
219
224 NEFORCE_NODISCARD constexpr date_type days_of_year() const noexcept {
225 date_type days = 0;
226 for (date_type i = 1; i < month_; ++i) {
227 days += days_of_month(year_, i);
228 }
229 return days + day_;
230 }
231
236 constexpr int64_t to_julian_day() const noexcept {
237 const date_type a = (14 - month_) / 12;
238 const date_type year = year_ + 4800 - a;
239 const date_type month = month_ + 12 * a - 3;
240 return day_ + (153 * month + 2) / 5 + 365 * year + year / 4 - year / 100 + year / 400 - 32045;
241 }
242
248 static constexpr date from_julian_day(const int64_t julian_day) noexcept {
249 const int64_t a = julian_day + 32044;
250 const int64_t b = (4 * a + 3) / 146097;
251 const int64_t c = a - (146097 * b) / 4;
252 const int64_t d = (4 * c + 3) / 1461;
253 const int64_t e = c - (1461 * d) / 4;
254 const int64_t m = (5 * e + 2) / 153;
255
256 const date_type day = static_cast<date_type>(e - (153 * m + 2) / 5 + 1);
257 const date_type month = static_cast<date_type>(m + 3 - 12 * (m / 10));
258 const date_type year = static_cast<date_type>(100 * b + d - 4800 + (m / 10));
259
260 return date(year, month, day);
261 }
262
266 constexpr void clear() noexcept {
267 year_ = 1970;
268 month_ = 1;
269 day_ = 1;
270 }
271
275 constexpr bool operator==(const date& rhs) const noexcept {
276 return year_ == rhs.year_ && month_ == rhs.month_ && day_ == rhs.day_;
277 }
278
282 constexpr bool operator<(const date& rhs) const noexcept {
283 if (year_ < rhs.year_) {
284 return true;
285 }
286 if (year_ == rhs.year_ && month_ < rhs.month_) {
287 return true;
288 }
289 if (year_ == rhs.year_ && month_ == rhs.month_ && day_ < rhs.day_) {
290 return true;
291 }
292 return false;
293 }
294
300 constexpr date& operator+=(const date_type day) noexcept {
301 if (day == 0) {
302 return *this;
303 }
304 if (day < 0) {
305 return *this -= -day;
306 }
307
308 if (day > 365) {
309 const int64_t jd = to_julian_day() + day;
310 *this = from_julian_day(jd);
311 return *this;
312 }
313
314 date_type remaining = day;
315 while (remaining > 0) {
316 const date_type days_in_month = days_of_month(year_, month_);
317 const date_type available = days_in_month - day_ + 1;
318
319 if (remaining < available) {
320 day_ += remaining;
321 break;
322 }
323
324 remaining -= available;
325 day_ = 1;
326 if (++month_ > 12) {
327 month_ = 1;
328 ++year_;
329 }
330 }
331 return *this;
332 }
333
339 constexpr date& operator-=(const date_type day) noexcept {
340 if (day < 0) {
341 return *this += -day;
342 }
343
344 day_ -= day;
345 while (day_ <= 0) {
346 if (--month_ == 0) {
347 month_ = 12;
348 year_--;
349 }
350 day_ += days_of_month(year_, month_);
351 }
352 return *this;
353 }
354
360 constexpr date operator+(const date_type day) const noexcept {
361 date ret(*this);
362 ret += day;
363 return ret;
364 }
365
371 constexpr date operator-(const date_type day) const noexcept {
372 date ret(*this);
373 ret -= day;
374 return ret;
375 }
376
380 constexpr date& operator++() {
381 *this += 1;
382 return *this;
383 }
384
388 constexpr date operator++(int) {
389 const date ret(*this);
390 *this += 1;
391 return ret;
392 }
393
399 constexpr date_type operator-(const date& other) const noexcept {
400 return static_cast<date_type>(to_julian_day() - other.to_julian_day());
401 }
402
407 NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept {
408 constexpr hash<date_type> hasher;
409 return hasher(day()) ^ hasher(month()) ^ hasher(year());
410 }
411
416 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const {
417 return _NEFORCE format("{:04d}-{:02d}-{:02d}", year(), month(), day());
418 }
419
426 NEFORCE_NODISCARD constexpr static date parse(const string_view view) {
427 if (view.size() != 10 || view[4] != '-' || view[7] != '-') {
428 NEFORCE_THROW_EXCEPTION(value_exception("Wrong string formation."));
429 }
430 const date_type year = integer32::parse(view.substr(0, 4)).value();
431 const date_type month = integer32::parse(view.substr(5, 2)).value();
432 const date_type day = integer32::parse(view.substr(8, 2)).value();
433 return date(year, month, day);
434 }
435
440 constexpr void swap(date& other) noexcept {
441 _NEFORCE swap(year_, other.year_);
442 _NEFORCE swap(month_, other.month_);
443 _NEFORCE swap(day_, other.day_);
444 }
445};
446
447
454class NEFORCE_API time : public iobject<time>, public icommon<time> {
455public:
457
458private:
459 time_type hours_ = 0;
460 time_type minutes_ = 0;
461 time_type seconds_ = 0;
462
463public:
467 constexpr time() noexcept = default;
468
472 NEFORCE_CONSTEXPR20 ~time() = default;
473
480 constexpr explicit time(const time_type hour, const time_type minute, const time_type second) noexcept {
481 if (is_valid(hour, minute, second)) {
482 hours_ = hour;
483 minutes_ = minute;
484 seconds_ = second;
485 }
486 }
487
488 constexpr time(const time&) noexcept = default;
489 constexpr time& operator=(const time&) noexcept = default;
490 constexpr time(time&&) noexcept = default;
491 constexpr time& operator=(time&&) noexcept = default;
492
497 NEFORCE_NODISCARD constexpr time_type hours() const noexcept { return hours_; }
498
503 NEFORCE_NODISCARD constexpr time_type minutes() const noexcept { return minutes_; }
504
509 NEFORCE_NODISCARD constexpr time_type seconds() const noexcept { return seconds_; }
510
518 static constexpr bool is_valid(time_type hour, time_type minute, time_type second) noexcept {
519 return hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60;
520 }
521
526 constexpr bool is_valid() const noexcept { return is_valid(hours_, minutes_, seconds_); }
527
531 constexpr void clear() noexcept {
532 hours_ = 0;
533 minutes_ = 0;
534 seconds_ = 0;
535 }
536
541 NEFORCE_NODISCARD constexpr time_type to_seconds() const noexcept {
542 return hours_ * 3600 + minutes_ * 60 + seconds_;
543 }
544
548 constexpr bool operator==(const time& other) const noexcept {
549 return hours_ == other.hours_ && minutes_ == other.minutes_ && seconds_ == other.seconds_;
550 }
551
555 constexpr bool operator<(const time& other) const noexcept {
556 if (hours_ < other.hours_) {
557 return true;
558 }
559 if (hours_ == other.hours_) {
560 if (minutes_ < other.minutes_) {
561 return true;
562 }
563 if (minutes_ == other.minutes_ && seconds_ < other.seconds_) {
564 return true;
565 }
566 }
567 return false;
568 }
569
575 constexpr time& operator+=(const time_type seconds) {
576 if (seconds < 0) {
577 return *this -= -seconds;
578 }
579
580 seconds_ += seconds;
581 const time_type extra_min = seconds_ / 60;
582 seconds_ %= 60;
583
584 minutes_ += extra_min;
585 const time_type extra_hour = minutes_ / 60;
586 minutes_ %= 60;
587
588 hours_ += extra_hour;
589 hours_ %= 24;
590
591 return *this;
592 }
593
599 constexpr time& operator-=(const time_type seconds) noexcept {
600 if (seconds < 0) {
601 return *this += -seconds;
602 }
603
604 int64_t total_sec = to_seconds() - seconds;
605 total_sec %= 86400;
606 if (total_sec < 0) {
607 total_sec += 86400;
608 }
609
610 hours_ = static_cast<time_type>(total_sec / 3600);
611 minutes_ = static_cast<time_type>((total_sec % 3600) / 60);
612 seconds_ = static_cast<time_type>(total_sec % 60);
613 return *this;
614 }
615
621 constexpr time operator+(const time_type seconds) const noexcept {
622 time ret(*this);
623 ret += seconds;
624 return ret;
625 }
626
632 constexpr time operator-(const time_type seconds) const noexcept {
633 time ret(*this);
634 ret -= seconds;
635 return ret;
636 }
637
641 constexpr time& operator++() { return *this += 1; }
642
646 constexpr time operator++(int) {
647 const time ret(*this);
648 *this += 1;
649 return ret;
650 }
651
655 constexpr time& operator--() { return *this -= 1; }
656
660 constexpr time operator--(int) {
661 const time ret(*this);
662 *this -= 1;
663 return ret;
664 }
665
671 constexpr time_type operator-(const time& other) const noexcept {
672 time_type sec_diff = (hours_ - other.hours_) * 3600;
673 sec_diff += (minutes_ - other.minutes_) * 60;
674 sec_diff += (seconds_ - other.seconds_);
675 return sec_diff;
676 }
677
682 NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept {
683 constexpr hash<time_type> hasher;
684 return hasher(hours()) ^ hasher(minutes()) ^ hasher(seconds());
685 }
686
691 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const {
692 return _NEFORCE format("{:02d}:{:02d}:{:02d}", hours(), minutes(), seconds());
693 }
694
701 NEFORCE_NODISCARD static constexpr time parse(const string_view view) {
702 if (view.size() != 8 || view[2] != ':' || view[5] != ':') {
703 NEFORCE_THROW_EXCEPTION(value_exception("Wrong string formation."));
704 }
705 const time_type hour = integer32::parse(view.substr(0, 2)).value();
706 const time_type minute = integer32::parse(view.substr(3, 2)).value();
707 const time_type second = integer32::parse(view.substr(6, 2)).value();
708 return time(hour, minute, second);
709 }
710
715 constexpr void swap(time& other) noexcept {
716 _NEFORCE swap(hours_, other.hours_);
717 _NEFORCE swap(minutes_, other.minutes_);
718 _NEFORCE swap(seconds_, other.seconds_);
719 }
720};
721
722
734class NEFORCE_API datetime : public iobject<datetime>, public icommon<datetime> {
735public:
736 using date_type = _NEFORCE date::date_type;
737 using time_type = _NEFORCE time::time_type;
738
739private:
740 _NEFORCE date date_{};
741 _NEFORCE time time_{};
742 int64_t offset_seconds_ = 0;
743 bool has_timezone_ = false;
744
745private:
751 static constexpr int months_to_int(const string_view view) {
752 constexpr string_view months_string[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
753 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
754 for (int i = 0; i < 12; ++i) {
755 if (view == months_string[i]) {
756 return i + 1;
757 }
758 }
759 return 0;
760 }
761
762public:
763 constexpr datetime() noexcept = default;
764
765 NEFORCE_CONSTEXPR20 ~datetime() = default;
766
767 constexpr datetime(const datetime&) noexcept = default;
768 constexpr datetime& operator=(const datetime&) noexcept = default;
769 constexpr datetime(datetime&&) noexcept = default;
770 constexpr datetime& operator=(datetime&&) noexcept = default;
771
781 constexpr explicit datetime(const date_type year, const date_type month, const date_type day, const time_type hour,
782 const time_type minute, const time_type second) noexcept :
783 date_(year, month, day),
784 time_(hour, minute, second) {}
785
796 constexpr explicit datetime(const date_type year, const date_type month, const date_type day, const time_type hour,
797 const time_type minute, const time_type second, const int64_t offset) noexcept :
798 date_(year, month, day),
799 time_(hour, minute, second),
800 offset_seconds_(offset),
801 has_timezone_(true) {}
802
808 constexpr explicit datetime(const _NEFORCE date& date, const _NEFORCE time& time) noexcept :
809 date_(date),
810 time_(time) {}
811
818 constexpr explicit datetime(const _NEFORCE date& date, const _NEFORCE time& time, const int64_t offset) noexcept :
819 date_(date),
820 time_(time),
821 offset_seconds_(offset),
822 has_timezone_(true) {}
823
828 constexpr explicit datetime(const _NEFORCE date& date) noexcept :
829 date_(date) {}
830
835 constexpr explicit datetime(const _NEFORCE time& time) noexcept :
836 time_(time) {}
837
842 constexpr explicit datetime(_NEFORCE date&& date) noexcept :
843 date_(date) {
844 date.clear();
845 }
846
851 constexpr explicit datetime(_NEFORCE time&& time) noexcept :
852 time_(time) {
853 time.clear();
854 }
855
861 constexpr explicit datetime(_NEFORCE date&& date, _NEFORCE time&& time) noexcept :
862 date_(date),
863 time_(time) {
864 date.clear();
865 time.clear();
866 }
867
874 constexpr explicit datetime(_NEFORCE date&& date, _NEFORCE time&& time, const int64_t offset) noexcept :
875 date_(date),
876 time_(time),
877 offset_seconds_(offset),
878 has_timezone_(true) {
879 date.clear();
880 time.clear();
881 }
882
887 constexpr bool is_valid() const noexcept { return date_.is_valid() && time_.is_valid(); }
888
894 constexpr datetime& operator=(const _NEFORCE date& date) noexcept {
895 date_ = date;
896 return *this;
897 }
898
904 constexpr datetime& operator=(_NEFORCE date&& date) noexcept {
905 date_ = date;
906 date.clear();
907 return *this;
908 }
909
915 constexpr datetime& operator=(const _NEFORCE time& time) noexcept {
916 time_ = time;
917 return *this;
918 }
919
925 constexpr datetime& operator=(_NEFORCE time&& time) noexcept {
926 time_ = time;
927 time.clear();
928 return *this;
929 }
930
935 NEFORCE_NODISCARD constexpr const _NEFORCE date& date() const noexcept { return date_; }
936
941 NEFORCE_NODISCARD constexpr const _NEFORCE time& time() const noexcept { return time_; }
942
947 NEFORCE_NODISCARD constexpr time_type hours() const noexcept { return time_.hours(); }
948
953 NEFORCE_NODISCARD constexpr time_type minutes() const noexcept { return time_.minutes(); }
954
959 NEFORCE_NODISCARD constexpr time_type seconds() const noexcept { return time_.seconds(); }
960
965 NEFORCE_NODISCARD constexpr date_type year() const noexcept { return date_.year(); }
966
971 NEFORCE_NODISCARD constexpr date_type month() const noexcept { return date_.month(); }
972
977 NEFORCE_NODISCARD constexpr date_type day() const noexcept { return date_.day(); }
978
983 NEFORCE_NODISCARD constexpr bool has_timezone() const noexcept { return has_timezone_; }
984
989 NEFORCE_NODISCARD constexpr int64_t offset_seconds() const noexcept { return offset_seconds_; }
990
995 NEFORCE_NODISCARD static constexpr datetime epoch() noexcept { return datetime{}; }
996
1001 NEFORCE_NODISCARD static datetime now() noexcept;
1002
1006 constexpr void clear() noexcept {
1007 date_.clear();
1008 time_.clear();
1009 offset_seconds_ = 0;
1010 has_timezone_ = false;
1011 }
1012
1016 constexpr bool operator==(const datetime& other) const noexcept {
1017 return date_ == other.date_ && time_ == other.time_ && has_timezone_ == other.has_timezone_ &&
1018 offset_seconds_ == other.offset_seconds_;
1019 }
1020
1024 constexpr bool operator<(const datetime& other) const noexcept {
1025 if (date_ < other.date_) {
1026 return true;
1027 } else if (date_ == other.date_) {
1028 if (time_ < other.time_) {
1029 return true;
1030 } else if (time_ == other.time_) {
1031 if (has_timezone_ && other.has_timezone_ && offset_seconds_ < other.offset_seconds_) {
1032 return true;
1033 }
1034 }
1035 }
1036 return false;
1037 }
1038
1044 constexpr datetime& operator+=(const int64_t seconds) {
1045 if (seconds < 0) {
1046 return *this -= -seconds;
1047 }
1048
1049 const int64_t current_total_sec = static_cast<int64_t>(time_.hours()) * 3600 +
1050 static_cast<int64_t>(time_.minutes()) * 60 +
1051 static_cast<int64_t>(time_.seconds());
1052
1053 int64_t new_total_sec = current_total_sec + seconds;
1054 int64_t days_to_add = new_total_sec / 86400;
1055 new_total_sec %= 86400;
1056
1057 if (new_total_sec < 0) {
1058 new_total_sec += 86400;
1059 days_to_add--;
1060 }
1061
1062 date_ += static_cast<date_type>(days_to_add);
1063 time_ = _NEFORCE time(static_cast<time_type>(new_total_sec / 3600),
1064 static_cast<time_type>((new_total_sec % 3600) / 60),
1065 static_cast<time_type>(new_total_sec % 60));
1066 return *this;
1067 }
1068
1074 constexpr datetime& operator-=(const int64_t seconds) noexcept {
1075 if (seconds < 0) {
1076 return *this += -seconds;
1077 }
1078
1079 const int64_t current_total_sec = static_cast<int64_t>(time_.hours()) * 3600 +
1080 static_cast<int64_t>(time_.minutes()) * 60 +
1081 static_cast<int64_t>(time_.seconds());
1082
1083 int64_t new_total_sec = current_total_sec - seconds;
1084 int64_t days_to_subtract = 0;
1085
1086 if (new_total_sec < 0) {
1087 days_to_subtract = (-new_total_sec + 86399) / 86400;
1088 new_total_sec += days_to_subtract * 86400;
1089 }
1090
1091 date_ -= static_cast<date_type>(days_to_subtract);
1092 time_ = _NEFORCE time(static_cast<time_type>(new_total_sec / 3600),
1093 static_cast<time_type>((new_total_sec % 3600) / 60),
1094 static_cast<time_type>(new_total_sec % 60));
1095 return *this;
1096 }
1097
1103 constexpr datetime operator+(const int64_t seconds) const noexcept {
1104 datetime ret(*this);
1105 ret += seconds;
1106 return ret;
1107 }
1108
1114 constexpr datetime operator-(const int64_t seconds) const noexcept {
1115 datetime ret(*this);
1116 ret -= seconds;
1117 return ret;
1118 }
1119
1123 constexpr datetime& operator++() { return *this += 1; }
1124
1128 constexpr datetime operator++(int) {
1129 const datetime ret(*this);
1130 *this += 1;
1131 return ret;
1132 }
1133
1137 constexpr datetime& operator--() { return *this -= 1; }
1138
1142 constexpr datetime operator--(int) {
1143 const datetime ret(*this);
1144 *this -= 1;
1145 return ret;
1146 }
1147
1153 constexpr time_type operator-(const datetime& other) const noexcept {
1154 const datetime lhs_utc = this->to_UTC();
1155 const datetime rhs_utc = other.to_UTC();
1156
1157 const time_type day_diff = lhs_utc.date_ - rhs_utc.date_;
1158 time_type sec_diff = day_diff * 86400;
1159 sec_diff += (lhs_utc.time_ - rhs_utc.time_);
1160 return sec_diff;
1161 }
1162
1167 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_offset_string() const {
1168 if (!has_timezone_) {
1169 return {};
1170 }
1171 if (offset_seconds_ == 0) {
1172 return "Z";
1173 }
1174 int64_t total_sec = offset_seconds_;
1175 const char sign = total_sec >= 0 ? '+' : '-';
1176 total_sec = total_sec >= 0 ? total_sec : -total_sec;
1177 const int64_t hours = total_sec / 3600;
1178 const int64_t minutes = (total_sec % 3600) / 60;
1179 return _NEFORCE format("{}{:02d}:{:02d}", sign, hours, minutes);
1180 }
1181
1188 static constexpr datetime from_UTC(const datetime& utc, const int32_t offset = 0) noexcept {
1189 datetime utc_time = utc;
1190 if (utc.has_timezone_ && utc.offset_seconds_ != 0) {
1191 utc_time = utc.to_UTC();
1192 }
1193 datetime local = utc_time + offset;
1194 local.offset_seconds_ = offset;
1195 local.has_timezone_ = true;
1196 return local;
1197 }
1198
1203 NEFORCE_NODISCARD constexpr datetime to_UTC() const noexcept {
1204 if (!has_timezone_) {
1205 return *this;
1206 }
1207 datetime utc = *this;
1208 utc -= offset_seconds_;
1209 utc.offset_seconds_ = 0;
1210 utc.has_timezone_ = true;
1211 return utc;
1212 }
1213
1218 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_ISO_UTC() const {
1219 if (has_timezone_) {
1220 return date_.to_string() + "T" + time_.to_string() + to_offset_string();
1221 } else {
1222 return date_.to_string() + "T" + time_.to_string();
1223 }
1224 }
1225
1232 NEFORCE_NODISCARD static constexpr datetime parse_ISO_UTC(const string_view view) {
1233 if (view.size() < 20 || view[10] != 'T') {
1234 NEFORCE_THROW_EXCEPTION(value_exception("Invalid ISO UTC datetime format."));
1235 }
1236
1237 const _NEFORCE date d = date::parse(view.substr(0, 10));
1238 const _NEFORCE time t = time::parse(view.substr(11, 8));
1239
1240 if (view.size() > 19 && view[19] == 'Z') {
1241 return datetime(d, t, 0);
1242 } else if (view.size() > 19 && (view[19] == '+' || view[19] == '-')) {
1243 const char sign = view[19];
1244 int hours = 0, minutes = 0;
1245 size_t pos = 20;
1246 if (view.size() >= pos + 2) {
1247 hours = integer32::parse(view.substr(pos, 2)).value();
1248 pos += 2;
1249 if (view.size() >= pos + 3 && view[pos] == ':') {
1250 pos++;
1251 if (view.size() >= pos + 2) {
1252 minutes = integer32::parse(view.substr(pos, 2)).value();
1253 }
1254 }
1255 }
1256
1257 int32_t total_offset = hours * 3600 + minutes * 60;
1258 if (sign == '-') {
1259 total_offset = -total_offset;
1260 }
1261 return datetime(d, t, total_offset);
1262 }
1263 return datetime(d, t);
1264 }
1265
1271 NEFORCE_CONSTEXPR20 bool try_parse_ISO_UTC(const string_view view) noexcept {
1272 try {
1273 datetime tmp = datetime::parse_ISO_UTC(view);
1274 this->swap(tmp);
1275 } catch (...) {
1276 return false;
1277 }
1278 return true;
1279 }
1280
1285 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_GMT() const noexcept {
1286 constexpr string_view months_string[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
1287 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
1288
1289 constexpr string_view weekdays_string[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
1290
1291 const _NEFORCE date utc_date = date();
1292 const _NEFORCE time utc_time = time();
1293
1294 int wday = utc_date.days_of_week();
1295 if (wday < 0 || wday >= 7) {
1296 wday = 0;
1297 }
1298
1299 int mon_idx = utc_date.month() - 1;
1300 if (mon_idx < 0 || mon_idx >= 12) {
1301 mon_idx = 0;
1302 }
1303
1304 return _NEFORCE format("{}, {:02d} {} {} {} GMT", weekdays_string[wday], utc_date.day(), months_string[mon_idx],
1305 utc_date.year(), utc_time.to_string());
1306 }
1307
1314 NEFORCE_NODISCARD static constexpr datetime parse_GMT(string_view view) {
1315 if (view.size() < 29) {
1316 NEFORCE_THROW_EXCEPTION(value_exception("Invalid date length."));
1317 }
1318 if (view.substr(3, 2) != ", ") {
1319 NEFORCE_THROW_EXCEPTION(value_exception("Invalid date format"));
1320 }
1321
1322 view.remove_prefix(5);
1323 const int day = integer32::parse(view.substr(0, 2)).value();
1324 view.remove_prefix(3);
1325 const int mon = months_to_int(view.substr(0, 3));
1326 if (mon == 0) {
1327 NEFORCE_THROW_EXCEPTION(value_exception("Invalid month in date"));
1328 }
1329 view.remove_prefix(4);
1330 const int year = integer32::parse(view.substr(0, 4)).value();
1331 view.remove_prefix(5);
1332 const int hour = integer32::parse(view.substr(0, 2)).value();
1333 view.remove_prefix(3);
1334 const int minute = integer32::parse(view.substr(0, 2)).value();
1335 view.remove_prefix(3);
1336 const int second = integer32::parse(view.substr(0, 2)).value();
1337 view.remove_prefix(3);
1338
1339 if (view != "GMT") {
1340 NEFORCE_THROW_EXCEPTION(value_exception("Invalid timezone in date"));
1341 }
1342 return datetime(year, mon, day, hour, minute, second);
1343 }
1344
1350 NEFORCE_CONSTEXPR20 bool try_parse_GMT(const string_view view) noexcept {
1351 try {
1352 datetime tmp = datetime::parse_GMT(view);
1353 this->swap(tmp);
1354 } catch (...) {
1355 return false;
1356 }
1357 return true;
1358 }
1359
1364 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_ISO() const {
1365 return date_.to_string() + "T" + time_.to_string();
1366 }
1367
1374 NEFORCE_NODISCARD static constexpr datetime parse_ISO(const string_view view) {
1375 if (view.size() < 19 || view[10] != 'T') {
1376 NEFORCE_THROW_EXCEPTION(value_exception("Invalid ISO datetime format."));
1377 }
1378 const _NEFORCE date d = _NEFORCE date::parse(view.substr(0, 10));
1379 size_t time_len = 8;
1380 if (view.size() >= 19) {
1381 time_len = 8;
1382 }
1383 const _NEFORCE time t = _NEFORCE time::parse(view.substr(11, time_len));
1384 return datetime(d, t);
1385 }
1386
1392 NEFORCE_CONSTEXPR20 bool try_parse_ISO(const string_view view) noexcept {
1393 try {
1394 datetime tmp = datetime::parse_ISO(view);
1395 this->swap(tmp);
1396 } catch (...) {
1397 return false;
1398 }
1399 return true;
1400 }
1401
1406 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const {
1407 return date_.to_string() + " " + time_.to_string();
1408 }
1409
1416 NEFORCE_NODISCARD static constexpr datetime parse(const string_view view) {
1417 if (view.size() != 19 || view[10] != ' ') {
1418 NEFORCE_THROW_EXCEPTION(value_exception("Wrong string formation."));
1419 }
1420 const _NEFORCE date d = date::parse(view.substr(0, 10));
1421 const _NEFORCE time t = time::parse(view.substr(11, 8));
1422 return datetime(d, t);
1423 }
1424
1429 NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept {
1430 return date_.to_hash() ^ time_.to_hash() ^ hash<bool>()(has_timezone_) ^ hash<int64_t>()(offset_seconds_);
1431 }
1432
1437 constexpr void swap(datetime& other) noexcept {
1438 _NEFORCE swap(date_, other.date_);
1439 _NEFORCE swap(time_, other.time_);
1440 _NEFORCE swap(offset_seconds_, other.offset_seconds_);
1441 _NEFORCE swap(has_timezone_, other.has_timezone_);
1442 }
1443};
1444
1445
1453class NEFORCE_API timestamp : public iobject<timestamp>, public ipackage<timestamp, int64_t> {
1454public:
1456
1457 constexpr timestamp() noexcept = default;
1458
1459 NEFORCE_CONSTEXPR20 ~timestamp() = default;
1460
1461 constexpr timestamp(const timestamp& other) noexcept :
1462 ipackage(other.value_) {}
1463
1464 constexpr timestamp& operator=(const timestamp& other) noexcept {
1465 value_ = other.value_;
1466 return *this;
1467 }
1468
1469 constexpr timestamp(timestamp&& other) noexcept :
1470 ipackage(other.value_) {
1471 other.clear();
1472 }
1473
1474 constexpr timestamp& operator=(timestamp&& other) noexcept {
1475 value_ = other.value_;
1476 other.clear();
1477 return *this;
1478 }
1479
1484 constexpr explicit timestamp(const value_type value) noexcept :
1485 ipackage(value) {}
1486
1491 constexpr explicit timestamp(const datetime& dt) noexcept {
1492 const datetime utc = dt.to_UTC();
1493 value_ = utc - datetime::epoch().to_UTC();
1494 }
1495
1500 NEFORCE_NODISCARD static timestamp now() noexcept { return timestamp(datetime::now()); }
1501
1506 NEFORCE_NODISCARD constexpr datetime to_datetime() const noexcept { return datetime::epoch() + value_; }
1507
1512 NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const { return integer64(value_).to_string(); }
1513
1519 NEFORCE_NODISCARD static constexpr timestamp parse(const string_view view) {
1520 return timestamp{integer64::parse(view).value()};
1521 }
1522
1526 constexpr void clear() noexcept { value_ = 0; }
1527};
1528 // DateTime
1530
1531NEFORCE_END_NAMESPACE__
1532#endif // NEFORCE_CORE_TIME_DATETIME_HPP__
NEFORCE_NODISCARD constexpr size_type size() const noexcept
获取字符串长度
NEFORCE_NODISCARD constexpr basic_string_view substr(const size_type off=0, size_type count=npos) const
获取子视图
constexpr void remove_prefix(const size_type n) noexcept
移除前缀
日期类
constexpr bool operator==(const date &rhs) const noexcept
相等比较
NEFORCE_NODISCARD constexpr date_type day() const noexcept
获取日期
int32_t date_type
日期分量类型
constexpr date & operator++()
前置递增(加1天)
NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept
计算哈希值
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const
转换为字符串
constexpr date() noexcept=default
默认构造函数,创建1970-01-01
constexpr bool operator<(const date &rhs) const noexcept
小于比较
constexpr bool is_valid() const noexcept
检查日期是否有效
constexpr date operator++(int)
后置递增(加1天)
NEFORCE_NODISCARD constexpr date_type days_of_year() const noexcept
获取一年中的第几天
static constexpr date from_julian_day(const int64_t julian_day) noexcept
从儒略日转换
NEFORCE_NODISCARD constexpr date_type year() const noexcept
获取年份
constexpr date operator-(const date_type day) const noexcept
日期减天数
static constexpr int32_t month_days[12]
每月天数表(非闰年)
constexpr void swap(date &other) noexcept
交换两个日期
static constexpr date_type days_of_month(const date_type year, const date_type month) noexcept
获取指定年月的天数
static constexpr bool is_valid(date_type year, date_type month, date_type day) noexcept
检查日期是否有效
static constexpr bool is_leap_year(const date_type year) noexcept
检查是否为闰年
constexpr date & operator+=(const date_type day) noexcept
日期加天数
NEFORCE_NODISCARD constexpr date_type days_of_week() const noexcept
获取星期几
constexpr date_type operator-(const date &other) const noexcept
日期差(天数)
constexpr void clear() noexcept
重置为纪元起始日期
constexpr date operator+(const date_type day) const noexcept
日期加天数
constexpr int64_t to_julian_day() const noexcept
转换为儒略日
static constexpr date epoch() noexcept
获取纪元起始日期(1970-01-01)
NEFORCE_NODISCARD constexpr date_type month() const noexcept
获取月份
NEFORCE_NODISCARD static constexpr date parse(const string_view view)
从字符串解析
constexpr date & operator-=(const date_type day) noexcept
日期减天数
日期时间类
constexpr datetime & operator++()
前置递增(加1秒)
NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept
计算哈希值
constexpr time_type operator-(const datetime &other) const noexcept
时间差(秒数)
static NEFORCE_NODISCARD constexpr datetime parse_ISO(const string_view view)
解析ISO格式(无时区)
NEFORCE_NODISCARD constexpr date_type day() const noexcept
获取日期
NEFORCE_NODISCARD constexpr date_type year() const noexcept
获取年份
static NEFORCE_NODISCARD constexpr datetime parse_GMT(string_view view)
解析GMT格式
constexpr datetime(const _NEFORCE date &date) noexcept
从日期构造(时间部分为00:00:00)
NEFORCE_NODISCARD constexpr date_type month() const noexcept
获取月份
NEFORCE_NODISCARD constexpr const _NEFORCE date & date() const noexcept
获取日期部分
NEFORCE_NODISCARD constexpr int64_t offset_seconds() const noexcept
获取时区偏移
constexpr datetime(const _NEFORCE date &date, const _NEFORCE time &time, const int64_t offset) noexcept
从日期、时间对象和时区构造
constexpr void clear() noexcept
重置为纪元起始时间
constexpr bool is_valid() const noexcept
检查时间是否有效
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_ISO() const
转换为ISO格式(无时区)
NEFORCE_NODISCARD constexpr bool has_timezone() const noexcept
检查是否有时区信息
constexpr datetime & operator=(_NEFORCE time &&time) noexcept
从时间移动赋值
static constexpr datetime from_UTC(const datetime &utc, const int32_t offset=0) noexcept
从UTC时间转换为本地时间
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_ISO_UTC() const
转换为ISO格式带时区
NEFORCE_CONSTEXPR20 bool try_parse_GMT(const string_view view) noexcept
尝试解析GMT格式
constexpr datetime(_NEFORCE date &&date, _NEFORCE time &&time) noexcept
从日期和时间对象移动构造
constexpr bool operator==(const datetime &other) const noexcept
相等比较
static NEFORCE_NODISCARD constexpr datetime parse(const string_view view)
解析简单格式
constexpr datetime(_NEFORCE date &&date) noexcept
从日期构造(时间部分为00:00:00)
NEFORCE_NODISCARD constexpr time_type minutes() const noexcept
获取分钟
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const
转换为简单格式
constexpr datetime & operator=(const _NEFORCE time &time) noexcept
从时间赋值
constexpr datetime(_NEFORCE time &&time) noexcept
从时间构造(日期部分为1970-01-01)
_NEFORCE date::date_type date_type
日期分量类型
NEFORCE_NODISCARD constexpr const _NEFORCE time & time() const noexcept
获取时间部分
NEFORCE_NODISCARD constexpr datetime to_UTC() const noexcept
转换为UTC时间
constexpr datetime operator+(const int64_t seconds) const noexcept
加秒数
constexpr datetime(_NEFORCE date &&date, _NEFORCE time &&time, const int64_t offset) noexcept
从日期、时间对象和时区移动构造
constexpr datetime & operator=(const _NEFORCE date &date) noexcept
从日期赋值
constexpr datetime(const _NEFORCE date &date, const _NEFORCE time &time) noexcept
从日期和时间对象构造
NEFORCE_NODISCARD constexpr time_type hours() const noexcept
获取小时
_NEFORCE time::time_type time_type
时间分量类型
constexpr datetime & operator+=(const int64_t seconds)
加秒数
NEFORCE_NODISCARD constexpr time_type seconds() const noexcept
获取秒
static NEFORCE_NODISCARD constexpr datetime epoch() noexcept
获取纪元起始时间(1970-01-01 00:00:00 UTC)
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_offset_string() const
转换为时区偏移字符串
NEFORCE_CONSTEXPR20 bool try_parse_ISO_UTC(const string_view view) noexcept
尝试解析ISO格式带时区
constexpr datetime operator++(int)
后置递增(加1秒)
static NEFORCE_NODISCARD constexpr datetime parse_ISO_UTC(const string_view view)
解析ISO格式带时区
constexpr datetime operator--(int)
后置递减(减1秒)
constexpr datetime & operator=(_NEFORCE date &&date) noexcept
从日期移动赋值
constexpr datetime(const _NEFORCE time &time) noexcept
从时间构造(日期部分为1970-01-01)
constexpr datetime operator-(const int64_t seconds) const noexcept
减秒数
static NEFORCE_NODISCARD datetime now() noexcept
获取当前本地时间
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_GMT() const noexcept
转换为GMT格式(RFC 1123)
constexpr datetime & operator-=(const int64_t seconds) noexcept
减秒数
constexpr datetime(const date_type year, const date_type month, const date_type day, const time_type hour, const time_type minute, const time_type second, const int64_t offset) noexcept
从日期、时间和时区构造
NEFORCE_CONSTEXPR20 bool try_parse_ISO(const string_view view) noexcept
尝试解析ISO格式(无时区)
constexpr void swap(datetime &other) noexcept
交换两个日期时间
constexpr datetime & operator--()
前置递减(减1秒)
constexpr bool operator<(const datetime &other) const noexcept
小于比较
时间类
constexpr bool operator==(const time &other) const noexcept
相等比较
constexpr time_type operator-(const time &other) const noexcept
时间差(秒数)
NEFORCE_NODISCARD constexpr time_type minutes() const noexcept
获取分钟
constexpr time operator--(int)
后置递减(减1秒)
static NEFORCE_NODISCARD constexpr time parse(const string_view view)
从字符串解析
NEFORCE_NODISCARD constexpr time_type hours() const noexcept
获取小时
constexpr void clear() noexcept
重置为00:00:00
constexpr time() noexcept=default
默认构造函数,创建00:00:00
int32_t time_type
时间分量类型
constexpr bool is_valid() const noexcept
检查时间是否有效
constexpr time operator-(const time_type seconds) const noexcept
时间减秒数
NEFORCE_NODISCARD constexpr time_type to_seconds() const noexcept
转换为总秒数
NEFORCE_NODISCARD constexpr time_type seconds() const noexcept
获取秒
constexpr time & operator--()
前置递减(减1秒)
NEFORCE_NODISCARD constexpr size_t to_hash() const noexcept
计算哈希值
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const
转换为字符串
constexpr time & operator-=(const time_type seconds) noexcept
时间减秒数
constexpr time & operator+=(const time_type seconds)
时间加秒数
constexpr time & operator++()
前置递增(加1秒)
constexpr time operator++(int)
后置递增(加1秒)
static constexpr bool is_valid(time_type hour, time_type minute, time_type second) noexcept
检查时间是否有效
constexpr void swap(time &other) noexcept
交换两个时间
constexpr bool operator<(const time &other) const noexcept
小于比较
constexpr time operator+(const time_type seconds) const noexcept
时间加秒数
时间戳类
static NEFORCE_NODISCARD timestamp now() noexcept
获取当前时间戳
NEFORCE_NODISCARD constexpr datetime to_datetime() const noexcept
转换为日期时间
int64_t value_type
值类型
static NEFORCE_NODISCARD constexpr timestamp parse(const string_view view)
从字符串解析
constexpr timestamp(const value_type value) noexcept
从秒数构造
constexpr timestamp(const datetime &dt) noexcept
从日期时间构造
constexpr void clear() noexcept
重置为0
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string() const
转换为字符串
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
秒持续时间
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string format(const string_view fmt, Args &&... args)
格式化字符串
NEFORCE_CONSTEXPR14 int sign(const T &value) noexcept
获取数值的符号
basic_string_view< char > string_view
字符字符串视图
void swap()=delete
删除无参数的swap重载
数值类型包装类
哈希函数的主模板
通用接口,同时具备可比较和可哈希功能
64位整数包装类
可解析对象接口
NEFORCE_NODISCARD constexpr package_type value() const noexcept
变量处理异常