Time Shield Library
C++ library for working with time
Loading...
Searching...
No Matches
date_time_conversions.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2#pragma once
3#ifndef _TIME_SHIELD_DATE_TIME_CONVERSIONS_HPP_INCLUDED
4#define _TIME_SHIELD_DATE_TIME_CONVERSIONS_HPP_INCLUDED
5
8
9#include "config.hpp"
10#include "constants.hpp"
11#include "date_conversions.hpp"
12#include "date_struct.hpp"
13#include "date_time_struct.hpp"
14#include "enums.hpp"
16#include "time_utils.hpp"
18#include "validation.hpp"
19
20#include <cmath>
21#include <ctime>
22#include <stdexcept>
23#include <type_traits>
24
25namespace time_shield {
26
29
40 template<class T1 = DateTimeStruct, class T2 = ts_t>
42 // 9223372029693630000 - значение на момент 292277024400 от 2000 года
43 // Такое значение приводит к неправильному вычислению умножения n_400_years * SEC_PER_400_YEARS
44 // Поэтому пришлось снизить до 9223371890843040000
45 constexpr int64_t BIAS_292277022000 = 9223371890843040000LL;
46 constexpr int64_t BIAS_2000 = 946684800LL;
47
48 int64_t y = MAX_YEAR;
49 int64_t secs = -((static_cast<int64_t>(ts) - BIAS_2000) - BIAS_292277022000);
50
51 const int64_t n_400_years = secs / SEC_PER_400_YEARS;
52 secs -= n_400_years * SEC_PER_400_YEARS;
53 y -= n_400_years * 400LL;
54
55 const int64_t n_100_years = secs / SEC_PER_100_YEARS;
56 secs -= n_100_years * SEC_PER_100_YEARS;
57 y -= n_100_years * 100LL;
58
59 const int64_t n_4_years = secs / SEC_PER_4_YEARS;
60 secs -= n_4_years * SEC_PER_4_YEARS;
61 y -= n_4_years * 4LL;
62
63 const int64_t n_1_years = secs / SEC_PER_YEAR;
64 secs -= n_1_years * SEC_PER_YEAR;
65 y -= n_1_years;
66
67 T1 date_time;
68
69 if (secs == 0) {
70 date_time.year = y;
71 date_time.mon = 1;
72 date_time.day = 1;
73 return date_time;
74 }
75
76 date_time.year = y - 1;
77 const bool is_leap_year = is_leap_year_date(date_time.year);
78 secs = is_leap_year ? SEC_PER_LEAP_YEAR - secs : SEC_PER_YEAR - secs;
79 const int days = static_cast<int>(secs / SEC_PER_DAY);
80
81 constexpr int JAN_AND_FEB_DAY_LEAP_YEAR = 60 - 1;
82 constexpr int TABLE_MONTH_OF_YEAR[] = {
83 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 31 январь
84 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 28 февраль
85 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 31 март
86 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 30 апрель
87 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
88 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
89 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
90 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
91 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
92 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
93 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
94 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
95 };
96 constexpr int TABLE_DAY_OF_YEAR[] = {
97 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 31 январь
98 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28, // 28 февраль
99 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 31 март
100 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, // 30 апрель
101 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
102 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
103 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
104 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
105 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
106 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
107 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
108 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
109 };
110
111 if (is_leap_year) {
112 const int prev_days = days - 1;
113 date_time.day = days == JAN_AND_FEB_DAY_LEAP_YEAR ? (TABLE_DAY_OF_YEAR[prev_days] + 1) :
114 (days > JAN_AND_FEB_DAY_LEAP_YEAR ? TABLE_DAY_OF_YEAR[prev_days] : TABLE_DAY_OF_YEAR[days]);
115 date_time.mon = days >= JAN_AND_FEB_DAY_LEAP_YEAR ? TABLE_MONTH_OF_YEAR[prev_days] : TABLE_MONTH_OF_YEAR[days];
116 } else {
117 date_time.day = TABLE_DAY_OF_YEAR[days];
118 date_time.mon = TABLE_MONTH_OF_YEAR[days];
119 }
120
121 ts_t day_secs = static_cast<ts_t>(secs % SEC_PER_DAY);
122 date_time.hour = static_cast<decltype(date_time.hour)>(day_secs / SEC_PER_HOUR);
123 ts_t min_secs = static_cast<ts_t>(day_secs - date_time.hour * SEC_PER_HOUR);
124 date_time.min = static_cast<decltype(date_time.min)>(min_secs / SEC_PER_MIN);
125 date_time.sec = static_cast<decltype(date_time.sec)>(min_secs - date_time.min * SEC_PER_MIN);
126# ifdef TIME_SHIELD_CPP17
127 if TIME_SHIELD_IF_CONSTEXPR (std::is_floating_point<T2>::value) {
128 date_time.ms = static_cast<int>(std::round(std::fmod(static_cast<double>(ts), static_cast<double>(MS_PER_SEC))));
129 } else date_time.ms = 0;
130# else
131 if (std::is_floating_point<T2>::value) {
132 date_time.ms = static_cast<int>(std::round(std::fmod(static_cast<double>(ts), static_cast<double>(MS_PER_SEC))));
133 } else date_time.ms = 0;
134# endif
135 return date_time;
136 }
137
143 template<class T>
145 const ts_t sec = ms_to_sec<ts_t, ts_ms_t>(ts);
146 T date_time = to_date_time<T, ts_t>(sec);
147 date_time.ms = ms_of_ts(ts); // Extract and set the ms component
148 return date_time;
149 }
150
181 template<class T1 = year_t, class T2 = int>
182 TIME_SHIELD_CONSTEXPR inline ts_t to_timestamp(
183 T1 year,
184 T2 month,
185 T2 day,
186 T2 hour = 0,
187 T2 min = 0,
188 T2 sec = 0) {
189
190 if (day >= UNIX_EPOCH && year <= 31) {
191 return to_timestamp((T1)day, month, (T2)year, hour, min, sec);
192 }
193 if (!is_valid_date_time(year, month, day, hour, min, sec)) {
194 throw std::invalid_argument("Invalid date-time combination");
195 }
196
197 int64_t secs = 0;
198 int64_t years = (static_cast<int64_t>(MAX_YEAR) - year);
199
200 const int64_t n_400_years = years / 400LL;
201 secs += n_400_years * SEC_PER_400_YEARS;
202 years -= n_400_years * 400LL;
203
204 const int64_t n_100_years = years / 100LL;
205 secs += n_100_years * SEC_PER_100_YEARS;
206 years -= n_100_years * 100LL;
207
208 const int64_t n_4_years = years / 4LL;
209 secs += n_4_years * SEC_PER_4_YEARS;
210 years -= n_4_years * 4LL;
211
212 secs += years * SEC_PER_YEAR;
213
214 // 9223372029693630000 - значение на момент 292277024400 от 2000 года
215 // Такое значение приводит к неправильному вычислению умножения n_400_years * SEC_PER_400_YEARS
216 // Поэтому пришлось снизить до 9223371890843040000
217 constexpr int64_t BIAS_292277022000 = 9223371890843040000LL;
218 constexpr int64_t BIAS_2000 = 946684800LL;
219
220 secs = BIAS_292277022000 - secs;
221 secs += BIAS_2000;
222
223 if (month == 1 && day == 1 &&
224 hour == 0 && min == 0 &&
225 sec == 0) {
226 return secs;
227 }
228
229 constexpr int lmos[] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
230 constexpr int mos[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
231
232 secs += (is_leap_year_date(year) ? (lmos[month - 1] + day - 1) : (mos[month - 1] + day - 1)) * SEC_PER_DAY;
233 secs += SEC_PER_HOUR * hour + SEC_PER_MIN * min + sec;
234 return secs;
235 }
236
247 template<class T>
248 TIME_SHIELD_CONSTEXPR inline ts_t dt_to_timestamp(
249 const T& date_time) {
250 return to_timestamp(
251 date_time.year,
252 date_time.mon,
253 date_time.day,
254 date_time.hour,
255 date_time.min,
256 date_time.sec
257 );
258 }
259
268 TIME_SHIELD_CONSTEXPR inline ts_t tm_to_timestamp(
269 const std::tm *timeinfo) {
270 return to_timestamp(
271 static_cast<year_t>(timeinfo->tm_year + 1900),
272 static_cast<int>(timeinfo->tm_mon + 1),
273 static_cast<int>(timeinfo->tm_mday),
274 static_cast<int>(timeinfo->tm_hour),
275 static_cast<int>(timeinfo->tm_min),
276 static_cast<int>(timeinfo->tm_sec)
277 );
278 }
279
297 template<class T1 = year_t, class T2 = int>
298 TIME_SHIELD_CONSTEXPR inline ts_ms_t to_timestamp_ms(
299 T1 year,
300 T2 month,
301 T2 day,
302 T2 hour = 0,
303 T2 min = 0,
304 T2 sec = 0,
305 T2 ms = 0) {
306 return sec_to_ms(to_timestamp<T1, T2>(year, month, day, hour, min, sec)) + ms;
307 }
308
319 template<class T>
320 TIME_SHIELD_CONSTEXPR inline ts_t dt_to_timestamp_ms(
321 const T& date_time) {
322 return sec_to_ms(dt_to_timestamp(date_time)) + date_time.ms;
323 }
324
333 TIME_SHIELD_CONSTEXPR inline ts_t tm_to_timestamp_ms(
334 const std::tm *timeinfo) {
335 return sec_to_ms(tm_to_timestamp(timeinfo));
336 }
337
356 template<class T1 = year_t, class T2 = int, class T3 = int>
357 TIME_SHIELD_CONSTEXPR inline fts_t to_ftimestamp(
358 T1 year,
359 T2 month,
360 T2 day,
361 T2 hour = 0,
362 T2 min = 0,
363 T2 sec = 0,
364 T3 ms = 0) {
365 return static_cast<fts_t>(to_timestamp(year, month, day, hour, min, sec)) +
366 static_cast<fts_t>(ms)/static_cast<fts_t>(MS_PER_SEC);
367 }
368
380 template<class T>
381 TIME_SHIELD_CONSTEXPR inline fts_t dt_to_ftimestamp(
382 const T& date_time) {
383 return static_cast<fts_t>(to_timestamp(date_time)) +
384 static_cast<fts_t>(date_time.ms)/static_cast<fts_t>(MS_PER_SEC);
385 }
386
396 TIME_SHIELD_CONSTEXPR inline fts_t tm_to_ftimestamp(
397 const std::tm* timeinfo) {
398 return static_cast<fts_t>(tm_to_timestamp(timeinfo));
399 }
400
408 constexpr ts_t start_of_day(ts_t ts = time_shield::ts()) noexcept {
409 return ts - (ts % SEC_PER_DAY);
410 }
411
419 template<class T = int>
420 constexpr ts_t start_of_prev_day(ts_t ts = time_shield::ts(), T days = 1) noexcept {
421 return ts - (ts % SEC_PER_DAY) - SEC_PER_DAY * days;
422 }
423
434
443 return ts_ms - (ts_ms % MS_PER_DAY);
444 }
445
454 template<class T = int>
455 constexpr ts_t start_of_next_day(ts_t ts, T days = 1) noexcept {
456 return start_of_day(ts) + days * SEC_PER_DAY;
457 }
458
467 template<class T = int>
468 constexpr ts_ms_t start_of_next_day_ms(ts_ms_t ts_ms, T days = 1) noexcept {
470 }
471
479 template<class T = int>
480 constexpr ts_t next_day(ts_t ts, T days = 1) noexcept {
481 return ts + days * SEC_PER_DAY;
482 }
483
491 template<class T = int>
492 constexpr ts_ms_t next_day_ms(ts_ms_t ts_ms, T days = 1) noexcept {
493 return ts_ms + days * MS_PER_DAY;
494 }
495
502 constexpr ts_t end_of_day(ts_t ts = time_shield::ts()) noexcept {
503 return ts - (ts % SEC_PER_DAY) + SEC_PER_DAY - 1;
504 }
505
514 }
515
523 return ts_ms - (ts_ms % MS_PER_DAY) + MS_PER_DAY - 1;
524 }
525
529 template<class T = year_t>
530 TIME_SHIELD_CONSTEXPR inline ts_t start_of_year_date(T year) {
531 const ts_t year_ts = to_timestamp(year, 1, 1);
532
533 return start_of_day(year_ts);
534 }
535
543 template<class T = year_t>
544 TIME_SHIELD_CONSTEXPR inline ts_ms_t start_of_year_date_ms(T year) {
546 }
547
555 TIME_SHIELD_CONSTEXPR inline ts_t start_of_year(ts_t ts) noexcept {
556 constexpr ts_t BIAS_2100 = 4102444800;
557 if (ts < BIAS_2100) {
558 constexpr ts_t SEC_PER_YEAR_X2 = SEC_PER_YEAR * 2;
559 ts_t year_start_ts = ts % SEC_PER_4_YEARS;
560 if (year_start_ts < SEC_PER_YEAR) {
561 return ts - year_start_ts;
562 } else
563 if (year_start_ts < SEC_PER_YEAR_X2) {
564 return ts + SEC_PER_YEAR - year_start_ts;
565 } else
566 if (year_start_ts < (SEC_PER_YEAR_X2 + SEC_PER_LEAP_YEAR)) {
567 return ts + SEC_PER_YEAR_X2 - year_start_ts;
568 }
569 return ts + (SEC_PER_YEAR_X2 + SEC_PER_LEAP_YEAR) - year_start_ts;
570 }
571
572 constexpr ts_t BIAS_2000 = 946684800;
573 ts_t secs = ts - BIAS_2000;
574
575 ts_t offset_y400 = secs % SEC_PER_400_YEARS;
576 ts_t start_ts = secs - offset_y400 + BIAS_2000;
577 secs = offset_y400;
578
579 if (secs >= SEC_PER_FIRST_100_YEARS) {
581 start_ts += SEC_PER_FIRST_100_YEARS;
582 while (secs >= SEC_PER_100_YEARS) {
583 secs -= SEC_PER_100_YEARS;
584 start_ts += SEC_PER_100_YEARS;
585 }
586
587 constexpr ts_t SEC_PER_4_YEARS_V2 = 4 * SEC_PER_YEAR;
588 if (secs >= SEC_PER_4_YEARS_V2) {
589 secs -= SEC_PER_4_YEARS_V2;
590 start_ts += SEC_PER_4_YEARS_V2;
591 } else {
592 start_ts += secs - secs % SEC_PER_YEAR;
593 return start_ts;
594 }
595 }
596
597 ts_t offset_4y = secs % SEC_PER_4_YEARS;
598 start_ts += secs - offset_4y;
599 secs = offset_4y;
600
601 if (secs >= SEC_PER_LEAP_YEAR) {
602 secs -= SEC_PER_LEAP_YEAR;
603 start_ts += SEC_PER_LEAP_YEAR;
604 start_ts += secs - secs % SEC_PER_YEAR;
605 }
606 else {
607 start_ts += secs - secs % SEC_PER_YEAR;
608 return start_ts;
609 }
610
611 ts_t offset_y = secs % SEC_PER_YEAR;
612 ts_t year_start_ts = start_ts + secs - offset_y;
613 if (offset_y < SEC_PER_YEAR * 2) {
614 return year_start_ts;
615 }
616 else
617 if (offset_y < (SEC_PER_YEAR * 3)) {
618 return year_start_ts + SEC_PER_YEAR;
619 }
620
621 return start_ts + SEC_PER_LEAP_YEAR;
622 }
623
627 TIME_SHIELD_CONSTEXPR inline ts_ms_t start_of_year_ms(ts_ms_t ts_ms = time_shield::ts_ms()) {
629 }
630
637 TIME_SHIELD_CONSTEXPR inline ts_t end_of_year(ts_t ts = time_shield::ts()) {
638 constexpr ts_t BIAS_2100 = 4102444800;
639 if (ts < BIAS_2100) {
640 constexpr ts_t SEC_PER_YEAR_X2 = SEC_PER_YEAR * 2;
641 constexpr ts_t SEC_PER_YEAR_X3 = SEC_PER_YEAR * 3;
642 constexpr ts_t SEC_PER_YEAR_X3_V2 = SEC_PER_YEAR_X2 + SEC_PER_LEAP_YEAR;
643 ts_t year_end_ts = ts % SEC_PER_4_YEARS;
644 if (year_end_ts < SEC_PER_YEAR) {
645 return ts + SEC_PER_YEAR - year_end_ts - 1;
646 } else
647 if (year_end_ts < SEC_PER_YEAR_X2) {
648 return ts + SEC_PER_YEAR_X2 - year_end_ts - 1;
649 } else
650 if (year_end_ts < SEC_PER_YEAR_X3_V2) {
651 return ts + SEC_PER_YEAR_X3_V2 - year_end_ts - 1;
652 }
653 return ts + (SEC_PER_YEAR_X3 + SEC_PER_LEAP_YEAR) - year_end_ts - 1;
654 }
655
656 constexpr ts_t BIAS_2000 = 946684800;
657 ts_t secs = ts - BIAS_2000;
658
659 ts_t offset_y400 = secs % SEC_PER_400_YEARS;
660 ts_t end_ts = secs - offset_y400 + BIAS_2000;
661 secs = offset_y400;
662
663 if (secs >= SEC_PER_FIRST_100_YEARS) {
665 end_ts += SEC_PER_FIRST_100_YEARS;
666 while (secs >= SEC_PER_100_YEARS) {
667 secs -= SEC_PER_100_YEARS;
668 end_ts += SEC_PER_100_YEARS;
669 }
670
671 constexpr ts_t SEC_PER_4_YEARS_V2 = 4 * SEC_PER_YEAR;
672 if (secs >= SEC_PER_4_YEARS_V2) {
673 secs -= SEC_PER_4_YEARS_V2;
674 end_ts += SEC_PER_4_YEARS_V2;
675 } else {
676 end_ts += secs - secs % SEC_PER_YEAR;
677 return end_ts + SEC_PER_YEAR - 1;
678 }
679 }
680
681 ts_t offset_4y = secs % SEC_PER_4_YEARS;
682 end_ts += secs - offset_4y;
683 secs = offset_4y;
684
685 if (secs >= SEC_PER_LEAP_YEAR) {
686 secs -= SEC_PER_LEAP_YEAR;
687 end_ts += SEC_PER_LEAP_YEAR;
688 end_ts += secs - secs % SEC_PER_YEAR;
689 end_ts += SEC_PER_YEAR;
690 } else {
691 end_ts += SEC_PER_LEAP_YEAR;
692 }
693 return end_ts - 1;
694 }
695
702 template<class T = year_t>
703 TIME_SHIELD_CONSTEXPR inline ts_ms_t end_of_year_ms(ts_ms_t ts_ms = time_shield::ts_ms()) {
705 }
706
713 template<class T = int>
715 return static_cast<T>(((ts - start_of_year(ts)) / SEC_PER_DAY) + 1);
716 }
717
724 template<class T = Month>
725 TIME_SHIELD_CONSTEXPR inline T month_of_year(ts_t ts) noexcept {
726 constexpr int JAN_AND_FEB_DAY_LEAP_YEAR = 60;
727 constexpr int TABLE_MONTH_OF_YEAR[] = {
728 0,
729 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 31 январь
730 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 28 февраль
731 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 31 март
732 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 30 апрель
733 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
734 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
735 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
736 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
737 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
738 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
739 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
740 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
741 };
742 const size_t dy = day_of_year<size_t>(ts);
743 return static_cast<T>((is_leap_year(ts) && dy >= JAN_AND_FEB_DAY_LEAP_YEAR) ? TABLE_MONTH_OF_YEAR[dy - 1] : TABLE_MONTH_OF_YEAR[dy]);
744 }
745
752 template<class T = int>
753 TIME_SHIELD_CONSTEXPR inline T day_of_month(ts_t ts = time_shield::ts()) {
754 constexpr int JAN_AND_FEB_DAY_LEAP_YEAR = 60;
755 // таблица для обычного года, не високосного
756 constexpr int TABLE_DAY_OF_YEAR[] = {
757 0,
758 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 31 январь
759 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28, // 28 февраль
760 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 31 март
761 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, // 30 апрель
762 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
763 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
764 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
765 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
766 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
767 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
768 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
769 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
770 };
771 const size_t dy = day_of_year<size_t>(ts);
772 if(is_leap_year(ts)) {
773 if(dy == JAN_AND_FEB_DAY_LEAP_YEAR) return TABLE_DAY_OF_YEAR[dy - 1] + 1;
774 if(dy > JAN_AND_FEB_DAY_LEAP_YEAR) return TABLE_DAY_OF_YEAR[dy - 1];
775 }
776 return TABLE_DAY_OF_YEAR[dy];
777 }
778
786 template<class T1 = int, class T2 = year_t, class T3 = int>
787 constexpr T1 num_days_in_month(T2 year, T3 month) noexcept {
788 if (month > MONTHS_PER_YEAR || month < 0) return 0;
789 constexpr T1 num_days[13] = {0,31,30,31,30,31,30,31,31,30,31,30,31};
790 if (month == FEB) {
791 if (is_leap_year_date(year)) return 29;
792 return 28;
793 }
794 return num_days[month];
795 }
796
803 template<class T1 = int>
804 TIME_SHIELD_CONSTEXPR T1 num_days_in_month_ts(ts_t ts = time_shield::ts()) noexcept {
805 constexpr T1 num_days[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
806 const int month = month_of_year<int>(ts);
807 if (month == FEB) {
808 return is_leap_year(ts) ? 29 : 28;
809 }
810 return num_days[month];
811 }
812
816 template<class T = Weekday>
817 constexpr T weekday_of_ts(ts_t ts) noexcept {
818 return static_cast<T>((ts / SEC_PER_DAY + THU) % DAYS_PER_WEEK);
819 }
820
824 template<class T = Weekday>
828
831 template<class T = Weekday>
832 constexpr T get_weekday_from_ts(ts_t ts) noexcept {
833 return weekday_of_ts<T>(ts);
834 }
835
838 template<class T = Weekday>
842
850 TIME_SHIELD_CONSTEXPR inline ts_t start_of_month(ts_t ts = time_shield::ts()) {
851 return start_of_day(ts) - (day_of_month(ts) - 1) * SEC_PER_DAY;
852 }
853
861 TIME_SHIELD_CONSTEXPR inline ts_t end_of_month(ts_t ts = time_shield::ts()) {
863 }
864
872 TIME_SHIELD_CONSTEXPR inline ts_t last_sunday_of_month(ts_t ts = time_shield::ts()) {
874 }
875
883 template<class T1 = int, class T2 = year_t, class T3 = int>
884 TIME_SHIELD_CONSTEXPR inline T1 last_sunday_month_day(T2 year, T3 month) {
885 const T1 days = num_days_in_month(year, month);
886 return days - day_of_week_date(year, month, days);
887 }
888
899
910
921
922
929 constexpr ts_t start_of_hour(ts_t ts = time_shield::ts()) noexcept {
930 return ts - (ts % SEC_PER_HOUR);
931 }
932
942
948 return ts_ms - (ts_ms % MS_PER_HOUR);
949 }
950
954 constexpr ts_t end_of_hour(ts_t ts = time_shield::ts()) noexcept {
955 return ts - (ts % SEC_PER_HOUR) + SEC_PER_HOUR - 1;
956 }
957
964
969 return ts_ms - (ts_ms % MS_PER_HOUR) + MS_PER_HOUR - 1;
970 }
971
975 constexpr ts_t start_of_min(ts_t ts = time_shield::ts()) noexcept {
976 return ts - (ts % SEC_PER_MIN);
977 }
978
982 constexpr ts_t end_of_min(ts_t ts = time_shield::ts()) noexcept {
983 return ts - (ts % SEC_PER_MIN) + SEC_PER_MIN - 1;
984 }
985
990 template<class T = int>
991 constexpr T min_of_day(ts_t ts = time_shield::ts()) noexcept {
992 return ((ts / SEC_PER_MIN) % MIN_PER_DAY);
993 }
994
999 template<class T = int>
1000 constexpr T hour_of_day(ts_t ts = time_shield::ts()) noexcept {
1001 return ((ts / SEC_PER_HOUR) % HOURS_PER_DAY);
1002 }
1003
1008 template<class T = int>
1009 constexpr T min_of_hour(ts_t ts = time_shield::ts()) noexcept {
1010 return ((ts / SEC_PER_MIN) % MIN_PER_HOUR);
1011 }
1012
1017 template<class T = int>
1019 return ts - (ts % p);
1020 }
1021
1026 template<class T = int>
1028 return ts - (ts % p) + p - 1;
1029 }
1030
1032
1033}; // namespace time_shield
1034
1035#endif // _TIME_SHIELD_DATE_TIME_CONVERSIONS_HPP_INCLUDED
Configuration macros for the library.
Header file with time-related constants.
Conversions related to calendar dates and DateStruct helpers.
Header for date structure and related functions.
Header for date and time structure and related functions.
Header file with enumerations for weekdays, months, and other time-related categories.
constexpr int64_t MIN_PER_HOUR
Minutes per hour.
constexpr int64_t DAYS_PER_WEEK
Days per week.
constexpr int64_t SEC_PER_YEAR
Seconds per year (365 days)
constexpr int64_t SEC_PER_FIRST_100_YEARS
Seconds per first 100 years.
const int64_t MONTHS_PER_YEAR
Months per year.
constexpr int64_t HOURS_PER_DAY
Hours per day.
constexpr int64_t SEC_PER_100_YEARS
Seconds per 100 years.
constexpr int64_t MAX_YEAR
Maximum representable year.
constexpr int64_t SEC_PER_LEAP_YEAR
Seconds per leap year (366 days)
constexpr int64_t MIN_PER_DAY
Minutes per day.
constexpr int64_t SEC_PER_HOUR
Seconds per hour.
constexpr int64_t UNIX_EPOCH
Start year of UNIX time.
constexpr int64_t MS_PER_DAY
Milliseconds per day.
Definition constants.hpp:97
constexpr int64_t MS_PER_SEC
Milliseconds per second.
Definition constants.hpp:77
constexpr int64_t SEC_PER_400_YEARS
Seconds per 400 years.
constexpr int64_t SEC_PER_DAY
Seconds per day.
constexpr int64_t SEC_PER_MIN
Seconds per minute.
constexpr int64_t MS_PER_HOUR
Milliseconds per hour.
Definition constants.hpp:90
constexpr int64_t SEC_PER_4_YEARS
Seconds per 4 years.
TIME_SHIELD_CONSTEXPR ts_t ts(year_t year, int month, int day)
Alias for to_timestamp.
constexpr T ms_of_ts(ts_ms_t ts) noexcept
Get the millisecond part of the timestamp.
TIME_SHIELD_CONSTEXPR T1 day_of_week_date(T2 year, T3 month, T4 day)
Get the day of the week.
TIME_SHIELD_CONSTEXPR ts_ms_t ts_ms(year_t year, int month, int day)
Alias for to_timestamp_ms.
constexpr T1 ms_to_sec(T2 ts_ms) noexcept
Converts a timestamp from milliseconds to seconds.
constexpr T days(ts_t start, ts_t stop) noexcept
Alias for days_between function.
constexpr T1 sec_to_ms(T2 ts) noexcept
Converts a timestamp from seconds to milliseconds.
TIME_SHIELD_CONSTEXPR T year(ts_t ts=time_shield::ts())
Alias for year_of function.
@ FEB
February.
Definition enums.hpp:95
@ SAT
Saturday.
Definition enums.hpp:34
@ THU
Thursday.
Definition enums.hpp:32
TIME_SHIELD_CONSTEXPR ts_t tm_to_timestamp(const std::tm *timeinfo)
Converts a std::tm structure to a timestamp.
TIME_SHIELD_CONSTEXPR T day_of_month(ts_t ts=time_shield::ts())
Get the day of the month.
constexpr ts_t end_of_hour(ts_t ts=time_shield::ts()) noexcept
Get the timestamp at the end of the hour.
TIME_SHIELD_CONSTEXPR fts_t dt_to_ftimestamp(const T &date_time)
Converts a date-time structure to a floating-point timestamp.
TIME_SHIELD_CONSTEXPR fts_t tm_to_ftimestamp(const std::tm *timeinfo)
Converts a std::tm structure to a floating-point timestamp.
constexpr ts_t start_of_saturday(ts_t ts=time_shield::ts())
Get the timestamp of the start of Saturday.
constexpr ts_t end_of_week(ts_t ts=time_shield::ts())
Get the timestamp of the end of the week.
constexpr ts_t start_of_period(T p, ts_t ts=time_shield::ts())
Get the timestamp of the start of the period.
TIME_SHIELD_CONSTEXPR ts_ms_t end_of_year_ms(ts_ms_t ts_ms=time_shield::ts_ms())
Get the timestamp in milliseconds of the end of the year.
T to_date_time_ms(ts_ms_t ts)
Converts a timestamp in milliseconds to a date-time structure with milliseconds.
constexpr ts_t start_of_min(ts_t ts=time_shield::ts()) noexcept
Get the timestamp of the beginning of the minute.
TIME_SHIELD_CONSTEXPR T month_of_year(ts_t ts) noexcept
Get the month of the year.
TIME_SHIELD_CONSTEXPR T1 last_sunday_month_day(T2 year, T3 month)
Get the day of the last Sunday of the given month and year.
constexpr T weekday_of_ts_ms(ts_ms_t ts_ms)
Get the weekday from a timestamp in milliseconds.
constexpr ts_ms_t end_of_hour_ms(ts_ms_t ts_ms=time_shield::ts_ms()) noexcept
Get the timestamp at the end of the hour in milliseconds.
constexpr ts_ms_t end_of_day_ms(ts_ms_t ts_ms=time_shield::ts_ms()) noexcept
Get the timestamp at the end of the day in milliseconds.
TIME_SHIELD_CONSTEXPR ts_t end_of_year(ts_t ts=time_shield::ts())
Get the end-of-year timestamp.
constexpr ts_ms_t start_of_day_ms(ts_ms_t ts_ms=time_shield::ts_ms()) noexcept
Get the start of the day timestamp in milliseconds.
constexpr T min_of_hour(ts_t ts=time_shield::ts()) noexcept
Get minute of hour. This function returns a value between 0 to 59.
constexpr ts_t start_of_hour(ts_t ts=time_shield::ts()) noexcept
Get the timestamp at the start of the hour.
constexpr T hour_of_day(ts_t ts=time_shield::ts()) noexcept
Get hour of day. This function returns a value between 0 to 23.
TIME_SHIELD_CONSTEXPR ts_t start_of_year(ts_t ts) noexcept
Get the start of the year timestamp.
constexpr ts_t end_of_day(ts_t ts=time_shield::ts()) noexcept
Get the timestamp at the end of the day.
T day_of_year(ts_t ts=time_shield::ts())
Get the day of the year.
TIME_SHIELD_CONSTEXPR ts_t tm_to_timestamp_ms(const std::tm *timeinfo)
Converts a std::tm structure to a timestamp in milliseconds.
TIME_SHIELD_CONSTEXPR ts_t start_of_month(ts_t ts=time_shield::ts())
Get the timestamp at the start of the current month.
constexpr T get_weekday_from_ts_ms(ts_ms_t ts_ms)
Alias for weekday_of_ts_ms.
TIME_SHIELD_CONSTEXPR ts_t dt_to_timestamp(const T &date_time)
Converts a date-time structure to a timestamp.
constexpr ts_ms_t start_of_hour_ms(ts_ms_t ts_ms=time_shield::ts_ms()) noexcept
Get the timestamp at the start of the hour. This function sets the minute and second to zero.
TIME_SHIELD_CONSTEXPR T1 num_days_in_month_ts(ts_t ts=time_shield::ts()) noexcept
Get the number of days in the month of the given timestamp.
TIME_SHIELD_CONSTEXPR fts_t to_ftimestamp(T1 year, T2 month, T2 day, T2 hour=0, T2 min=0, T2 sec=0, T3 ms=0)
Converts a date and time to a floating-point timestamp.
TIME_SHIELD_CONSTEXPR ts_t end_of_month(ts_t ts=time_shield::ts())
Get the last timestamp of the current month.
constexpr ts_t start_of_day(ts_t ts=time_shield::ts()) noexcept
Get the start of the day timestamp.
TIME_SHIELD_CONSTEXPR ts_ms_t start_of_year_ms(ts_ms_t ts_ms=time_shield::ts_ms())
Get the timestamp at the start of the year in milliseconds.
constexpr ts_t end_of_hour_sec(ts_ms_t ts_ms=time_shield::ts_ms()) noexcept
Get the timestamp at the end of the hour in seconds.
TIME_SHIELD_CONSTEXPR ts_t to_timestamp(T1 year, T2 month, T2 day, T2 hour=0, T2 min=0, T2 sec=0)
Converts a date and time to a timestamp.
constexpr ts_t end_of_min(ts_t ts=time_shield::ts()) noexcept
Get the timestamp of the end of the minute.
constexpr ts_ms_t start_of_next_day_ms(ts_ms_t ts_ms, T days=1) noexcept
Get the timestamp of the start of the day after a specified number of days.
TIME_SHIELD_CONSTEXPR ts_t last_sunday_of_month(ts_t ts=time_shield::ts())
Get the timestamp of the last Sunday of the current month.
TIME_SHIELD_CONSTEXPR ts_t start_of_year_date(T year)
Get the timestamp of the start of the year.
constexpr ts_ms_t next_day_ms(ts_ms_t ts_ms, T days=1) noexcept
Calculate the timestamp for a specified number of days in the future (milliseconds).
constexpr ts_t end_of_period(T p, ts_t ts=time_shield::ts())
Get the timestamp of the end of the period.
constexpr ts_t start_of_next_day(ts_t ts, T days=1) noexcept
Get the timestamp of the start of the day after a specified number of days.
constexpr ts_t next_day(ts_t ts, T days=1) noexcept
Calculate the timestamp for a specified number of days in the future.
T1 to_date_time(T2 ts)
Converts a timestamp to a date-time structure.
TIME_SHIELD_CONSTEXPR ts_t dt_to_timestamp_ms(const T &date_time)
Converts a date-time structure to a timestamp in milliseconds.
constexpr ts_t start_of_week(ts_t ts=time_shield::ts())
Get the timestamp of the beginning of the week.
constexpr ts_t start_of_day_sec(ts_ms_t ts_ms=time_shield::ts_ms()) noexcept
Get the start of the day timestamp in seconds.
constexpr T weekday_of_ts(ts_t ts) noexcept
Get the second of the week day from a timestamp.
constexpr T min_of_day(ts_t ts=time_shield::ts()) noexcept
Get minute of day. This function returns a value between 0 to 1439 (minute of day).
constexpr ts_t start_of_prev_day(ts_t ts=time_shield::ts(), T days=1) noexcept
Get timestamp of the start of the previous day.
constexpr T1 num_days_in_month(T2 year, T3 month) noexcept
Get the number of days in a month.
constexpr T get_weekday_from_ts(ts_t ts) noexcept
Alias for weekday_of_ts.
TIME_SHIELD_CONSTEXPR ts_ms_t start_of_year_date_ms(T year)
Get the timestamp in milliseconds of the start of the year.
constexpr ts_t start_of_hour_sec(ts_ms_t ts_ms=time_shield::ts_ms()) noexcept
Get the timestamp at the start of the hour.
constexpr ts_t end_of_day_sec(ts_ms_t ts_ms=time_shield::ts_ms()) noexcept
Get the timestamp at the end of the day in seconds.
TIME_SHIELD_CONSTEXPR ts_ms_t to_timestamp_ms(T1 year, T2 month, T2 day, T2 hour=0, T2 min=0, T2 sec=0, T2 ms=0)
Converts a date-time structure to a timestamp in milliseconds.
int64_t ts_t
Unix timestamp in seconds since 1970‑01‑01T00:00:00Z.
Definition types.hpp:48
int64_t ts_ms_t
Unix timestamp in milliseconds since epoch.
Definition types.hpp:49
double fts_t
Floating-point timestamp (fractional seconds since epoch).
Definition types.hpp:51
int64_t year_t
Year as an integer (e.g., 2024).
Definition types.hpp:41
TIME_SHIELD_CONSTEXPR bool is_leap_year(ts_t ts)
Alias for is_leap_year_ts function.
TIME_SHIELD_CONSTEXPR bool is_valid_date_time(T1 year, T2 month, T2 day, T2 hour=0, T2 min=0, T2 sec=0, T3 ms=0) noexcept
Checks the correctness of a date and time.
constexpr bool is_leap_year_date(T year) noexcept
Checks if the given year is a leap year.
Main namespace for the Time Shield library.
Helper functions for unit conversions between seconds, minutes, hours, and milliseconds.
Header file with time-related utility functions.
Conversions related to UNIX-based time units and epochs.
Header file with time-related validation functions.