Time Shield Library
C++ library for working with time
Loading...
Searching...
No Matches
fast_date.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2#pragma once
3#ifndef _TIME_SHIELD_DETAIL_FAST_DATE_HPP_INCLUDED
4#define _TIME_SHIELD_DETAIL_FAST_DATE_HPP_INCLUDED
5
8
9#include "mul_hi.hpp"
10
11#include <cstdint>
12
13namespace time_shield {
14namespace detail {
15
16 namespace {
17 constexpr int16_t k_doy_from_march[12] = {
18 0, // Mar
19 31, // Apr
20 61, // May
21 92, // Jun
22 122, // Jul
23 153, // Aug
24 184, // Sep
25 214, // Oct
26 245, // Nov
27 275, // Dec
28 306, // Jan
29 337 // Feb
30 };
31 } // namespace
32
33 struct DaySplit {
34 int64_t days;
35 int64_t sec_of_day;
36 };
37
39 TIME_SHIELD_CONSTEXPR inline DaySplit split_unix_day(ts_t p_ts) noexcept {
40 int64_t days = p_ts / SEC_PER_DAY;
41 int64_t sec_of_day = p_ts % SEC_PER_DAY;
42 if (sec_of_day < 0) {
44 days -= 1;
45 }
46 return {days, sec_of_day};
47 }
48
49 struct FastDate {
50 int64_t year;
51 int month;
52 int day;
53 };
54
59 TIME_SHIELD_CONSTEXPR inline int64_t fast_days_from_date_constexpr(
60 int64_t p_year,
61 int p_month,
62 int p_day) noexcept {
63 const int month_adjust = (p_month <= 2 ? 1 : 0);
64 const int64_t y = p_year - month_adjust;
65 int m = p_month - 3;
66 if (m < 0) {
67 m += 12;
68 }
69
70 if (y >= 0) {
71 const uint64_t y_u = static_cast<uint64_t>(y);
72 const uint64_t era = y_u / 400U;
73 const uint64_t yoe = y_u - era * 400U;
74 const uint64_t doy = static_cast<uint64_t>(k_doy_from_march[m]) + static_cast<uint64_t>(p_day - 1);
75 const uint64_t doe = yoe * 365U + yoe / 4U - yoe / 100U + doy;
76 return static_cast<int64_t>(era * 146097U + doe) - 719468;
77 }
78
79 const int64_t era = (y - 399) / 400;
80 const int64_t yoe = y - era * 400;
81 const int64_t doy = static_cast<int64_t>(k_doy_from_march[m]) + static_cast<int64_t>(p_day - 1);
82 const int64_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
83 return era * 146097 + doe - 719468;
84 }
85
90 inline int64_t fast_days_from_date(int64_t p_year, int p_month, int p_day) noexcept {
91 const int month_adjust = (p_month <= 2 ? 1 : 0);
92 const int64_t y = p_year - month_adjust;
93 int m = p_month - 3;
94 if (m < 0) {
95 m += 12;
96 }
97
98 if (y >= 0) {
99 const uint64_t y_u = static_cast<uint64_t>(y);
100 const uint64_t era = y_u / 400U;
101 const uint64_t yoe = y_u - era * 400U;
102 const uint64_t doy = static_cast<uint64_t>(k_doy_from_march[m]) + static_cast<uint64_t>(p_day - 1);
103 const uint64_t doe = yoe * 365U + yoe / 4U - yoe / 100U + doy;
104 return static_cast<int64_t>(era * 146097U + doe) - 719468;
105 }
106
107 const int64_t era = (y - 399) / 400;
108 const int64_t yoe = y - era * 400;
109 const int64_t doy = static_cast<int64_t>(k_doy_from_march[m]) + static_cast<int64_t>(p_day - 1);
110 const int64_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
111 return era * 146097 + doe - 719468;
112 }
113
118 TIME_SHIELD_CONSTEXPR inline FastDate fast_date_from_days_constexpr(int64_t p_days) noexcept {
119 constexpr uint64_t ERAS = 4726498270ULL;
120 constexpr int64_t D_SHIFT = static_cast<int64_t>(146097ULL * ERAS - 719469ULL);
121 constexpr int64_t Y_SHIFT = static_cast<int64_t>(400ULL * ERAS - 1ULL);
122 constexpr uint64_t C1 = 505054698555331ULL;
123 constexpr uint64_t C2 = 50504432782230121ULL;
124 constexpr uint64_t C3 = 8619973866219416ULL;
125 constexpr uint64_t YPT_SCALE = 782432ULL;
126 constexpr uint64_t YPT_BUMP_THRESHOLD = 126464ULL;
127 constexpr uint64_t SHIFT_JAN_FEB = 191360ULL;
128 constexpr uint64_t SHIFT_OTHER = 977792ULL;
129
130 const uint64_t rev = static_cast<uint64_t>(D_SHIFT - p_days);
131 const uint64_t cen = mul_shift_u64_constexpr(rev, C1);
132 const uint64_t jul = rev + cen - (cen / 4U);
133
134 const uint64_t num_hi = mul_shift_u64_constexpr(jul, C2);
135 const uint64_t num_low = jul * C2;
136 const uint64_t yrs = static_cast<uint64_t>(Y_SHIFT) - num_hi;
137
138 const uint64_t ypt = mul_shift_u64_constexpr(YPT_SCALE, num_low);
139 const bool bump = ypt < YPT_BUMP_THRESHOLD;
140 const uint64_t shift = bump ? SHIFT_JAN_FEB : SHIFT_OTHER;
141
142 const uint64_t N = (yrs & 3ULL) * 512ULL + shift - ypt;
143 const uint64_t d = mul_shift_u64_constexpr((N & 0xFFFFULL), C3);
144
145 return FastDate{
146 static_cast<int64_t>(yrs + (bump ? 1U : 0U)),
147 static_cast<int>(N >> 16),
148 static_cast<int>(d + 1U)
149 };
150 }
151
156 inline FastDate fast_date_from_days(int64_t p_days) noexcept {
157 constexpr uint64_t ERAS = 4726498270ULL;
158 constexpr int64_t D_SHIFT = static_cast<int64_t>(146097ULL * ERAS - 719469ULL);
159 constexpr int64_t Y_SHIFT = static_cast<int64_t>(400ULL * ERAS - 1ULL);
160 constexpr uint64_t C1 = 505054698555331ULL;
161 constexpr uint64_t C2 = 50504432782230121ULL;
162 constexpr uint64_t C3 = 8619973866219416ULL;
163 constexpr uint64_t YPT_SCALE = 782432ULL;
164 constexpr uint64_t YPT_BUMP_THRESHOLD = 126464ULL;
165 constexpr uint64_t SHIFT_JAN_FEB = 191360ULL;
166 constexpr uint64_t SHIFT_OTHER = 977792ULL;
167
168 const uint64_t rev = static_cast<uint64_t>(D_SHIFT - p_days);
169 const uint64_t cen = mul_shift_u64(rev, C1);
170 const uint64_t jul = rev + cen - (cen / 4U);
171
172 const uint64_t num_hi = mul_shift_u64(jul, C2);
173 const uint64_t num_low = jul * C2;
174 const uint64_t yrs = static_cast<uint64_t>(Y_SHIFT) - num_hi;
175
176 const uint64_t ypt = mul_shift_u64(YPT_SCALE, num_low);
177 const bool bump = ypt < YPT_BUMP_THRESHOLD;
178 const uint64_t shift = bump ? SHIFT_JAN_FEB : SHIFT_OTHER;
179
180 const uint64_t N = (yrs & 3ULL) * 512ULL + shift - ypt;
181 const uint64_t d = mul_shift_u64((N & 0xFFFFULL), C3);
182
183 FastDate result{};
184 result.day = static_cast<int>(d + 1U);
185 result.month = static_cast<int>(N >> 16);
186 result.year = static_cast<int64_t>(yrs + (bump ? 1U : 0U));
187 return result;
188 }
189
194 TIME_SHIELD_CONSTEXPR inline int64_t fast_year_from_days_constexpr(int64_t p_days) noexcept {
195 constexpr uint64_t ERAS = 4726498270ULL;
196 constexpr int64_t D_SHIFT = static_cast<int64_t>(146097ULL * ERAS - 719469ULL);
197 constexpr int64_t Y_SHIFT = static_cast<int64_t>(400ULL * ERAS - 1ULL);
198 constexpr uint64_t C1 = 505054698555331ULL;
199 constexpr uint64_t C2 = 50504432782230121ULL;
200 constexpr uint64_t YPT_SCALE = 782432ULL;
201 constexpr uint64_t YPT_BUMP_THRESHOLD = 126464ULL;
202
203 const uint64_t rev = static_cast<uint64_t>(D_SHIFT - p_days);
204 const uint64_t cen = mul_shift_u64_constexpr(rev, C1);
205 const uint64_t jul = rev + cen - (cen / 4U);
206
207 const uint64_t num_hi = mul_shift_u64_constexpr(jul, C2);
208 const uint64_t num_low = jul * C2;
209 const uint64_t yrs = static_cast<uint64_t>(Y_SHIFT) - num_hi;
210
211 const uint64_t ypt = mul_shift_u64_constexpr(YPT_SCALE, num_low);
212 const bool bump = ypt < YPT_BUMP_THRESHOLD;
213 return static_cast<int64_t>(yrs + (bump ? 1U : 0U));
214 }
215
220 inline int64_t fast_year_from_days(int64_t p_days) noexcept {
221 constexpr uint64_t ERAS = 4726498270ULL;
222 constexpr int64_t D_SHIFT = static_cast<int64_t>(146097ULL * ERAS - 719469ULL);
223 constexpr int64_t Y_SHIFT = static_cast<int64_t>(400ULL * ERAS - 1ULL);
224 constexpr uint64_t C1 = 505054698555331ULL;
225 constexpr uint64_t C2 = 50504432782230121ULL;
226 constexpr uint64_t YPT_SCALE = 782432ULL;
227 constexpr uint64_t YPT_BUMP_THRESHOLD = 126464ULL;
228
229 const uint64_t rev = static_cast<uint64_t>(D_SHIFT - p_days);
230 const uint64_t cen = mul_shift_u64(rev, C1);
231 const uint64_t jul = rev + cen - (cen / 4U);
232
233 const uint64_t num_hi = mul_shift_u64(jul, C2);
234 const uint64_t num_low = jul * C2;
235 const uint64_t yrs = static_cast<uint64_t>(Y_SHIFT) - num_hi;
236
237 const uint64_t ypt = mul_shift_u64(YPT_SCALE, num_low);
238 const bool bump = ypt < YPT_BUMP_THRESHOLD;
239 return static_cast<int64_t>(yrs + (bump ? 1U : 0U));
240 }
241
242} // namespace detail
243} // namespace time_shield
244
245#endif // _TIME_SHIELD_DETAIL_FAST_DATE_HPP_INCLUDED
constexpr int64_t SEC_PER_DAY
Seconds per day.
constexpr T days(ts_t start, ts_t stop) noexcept
Alias for days_between function.
bool sec_of_day(const std::string &str, T &sec)
Parse time of day string to seconds of day.
int64_t ts_t
Unix timestamp in seconds since 1970‑01‑01T00:00:00Z.
Definition types.hpp:49
Helpers for 64-bit multiply-high operations.
uint64_t mul_shift_u64(uint64_t p_x, uint64_t p_c) noexcept
Alias for mul_hi_u64 used for shift-by-64 operations.
Definition mul_hi.hpp:47
TIME_SHIELD_CONSTEXPR FastDate fast_date_from_days_constexpr(int64_t p_days) noexcept
Convert days since Unix epoch to date using a fast constexpr algorithm.
TIME_SHIELD_CONSTEXPR DaySplit split_unix_day(ts_t p_ts) noexcept
Split UNIX seconds into whole days and seconds-of-day.
Definition fast_date.hpp:39
TIME_SHIELD_CONSTEXPR uint64_t mul_shift_u64_constexpr(uint64_t p_x, uint64_t p_c) noexcept
Alias for mul_hi_u64_constexpr used for shift-by-64 operations.
Definition mul_hi.hpp:52
int64_t fast_year_from_days(int64_t p_days) noexcept
Convert days since Unix epoch to year using a fast algorithm.
TIME_SHIELD_CONSTEXPR int64_t fast_year_from_days_constexpr(int64_t p_days) noexcept
Convert days since Unix epoch to year using a fast constexpr algorithm.
FastDate fast_date_from_days(int64_t p_days) noexcept
Convert days since Unix epoch to date using a fast algorithm.
TIME_SHIELD_CONSTEXPR int64_t fast_days_from_date_constexpr(int64_t p_year, int p_month, int p_day) noexcept
Convert date to days since Unix epoch using a fast constexpr algorithm.
Definition fast_date.hpp:59
int64_t fast_days_from_date(int64_t p_year, int p_month, int p_day) noexcept
Convert date to days since Unix epoch using a fast algorithm.
Definition fast_date.hpp:90
Main namespace for the Time Shield library.