roo_time
API Documentation for roo_time
Loading...
Searching...
No Matches
roo_time.cpp
Go to the documentation of this file.
1#include "roo_time.h"
2
3namespace roo_time {
4namespace {
5
6const int64_t kMaxComponentizedDuration =
7 (1024LL * 1024 * 64) * 24 * 3600 * 1000000LL - 1;
8}
9
12 int64_t v = micros_;
13 c.negative = (v < 0);
14 if (c.negative) v = -v;
15 if (v > kMaxComponentizedDuration) v = kMaxComponentizedDuration;
16 c.micros = v % 1000000L;
17 v /= 1000000L;
18 c.seconds = v % 60;
19 v /= 60;
20 c.minutes = v % 60;
21 v /= 60;
22 c.hours = v % 24;
23 v /= 24;
24 c.days = v;
25 return c;
26}
27
29 int64_t micros =
30 (((c.days * 24 + c.hours) * 60 + c.minutes) * 60 + c.seconds) *
31 1000000LL +
32 c.micros;
33 if (c.negative) micros = -micros;
34 if (micros == kMaxComponentizedDuration) {
35 return Micros(kMaxComponentizedDuration);
36 }
37 return Micros(micros);
38}
39
40namespace {
41
42// Credit:
43// https://stackoverflow.com/questions/7960318/math-to-convert-seconds-since-1970-into-date-and-vice-versa
44
45// Returns number of days since civil 1970-01-01. Negative values indicate
46// days prior to 1970-01-01.
47// Preconditions: y-m-d represents a date in the civil (Gregorian) calendar
48// m is in [1, 12]
49// d is in [1, last_day_of_month(y, m)]
50// y is "approximately" in
51// [numeric_limits<Int>::min()/366,
52// numeric_limits<Int>::max()/366]
53// Exact range of validity is:
54// [civil_from_days(numeric_limits<Int>::min()),
55// civil_from_days(numeric_limits<Int>::max()-719468)]
56int32_t days_from_civil(int32_t y, uint8_t m, uint8_t d) noexcept {
57 y -= m <= 2;
58 const int32_t era = (y >= 0 ? y : y - 399) / 400;
59 const uint32_t yoe = static_cast<uint16_t>(y - era * 400); // [0, 399]
60 const uint32_t doy =
61 (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; // [0, 365]
62 const uint32_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096]
63 return era * 146097 + static_cast<int32_t>(doe) - 719468;
64}
65
66// Returns year/month/day triple in civil calendar
67// Preconditions: z is number of days since 1970-01-01 and is in the range:
68// [numeric_limits<Int>::min(),
69// numeric_limits<Int>::max()-719468].
70void civil_from_days(int32_t z, int16_t* year, uint8_t* month,
71 uint8_t* day) noexcept {
72 z += 719468;
73 const int32_t era = (z >= 0 ? z : z - 146096) / 146097;
74 const uint32_t doe = static_cast<uint32_t>(z - era * 146097); // [0, 146096]
75 const uint32_t yoe =
76 (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; // [0, 399]
77 const int32_t y = static_cast<int32_t>(yoe) + era * 400;
78 const uint16_t doy = doe - (365 * yoe + yoe / 4 - yoe / 100); // [0, 365]
79 const uint8_t mp = (5 * doy + 2) / 153; // [0, 11]
80 const uint8_t d = doy - (153 * mp + 2) / 5 + 1; // [1, 31]
81 const uint8_t m = mp + (mp < 10 ? 3 : -9); // [1, 12]
82 *year = y + (m <= 2);
83 *month = m;
84 *day = d;
85}
86
87// Returns day of week in civil calendar [0, 6] -> [Sun, Sat]
88// Preconditions: z is number of days since 1970-01-01 and is in the range:
89// [numeric_limits<Int>::min(), numeric_limits<Int>::max()-4].
90constexpr DayOfWeek weekday_from_days(int32_t z) noexcept {
91 return static_cast<DayOfWeek>(z >= -4 ? (z + 4) % 7 : (z + 5) % 7 + 6);
92}
93
94// Returns: true if y is a leap year in the civil calendar, else false
95constexpr bool is_leap(int32_t y) noexcept {
96 return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
97}
98
99// Preconditions: y-m-d represents a date in the civil (Gregorian) calendar
100// m is in [1, 12]
101// d is in [1, last_day_of_month(y, m)]
102uint16_t day_of_year(int16_t y, uint8_t m, uint8_t d) {
103 constexpr uint16_t days_to_month[12] = {0, 31, 59, 90, 120, 151,
104 181, 212, 243, 273, 304, 334};
105 uint16_t result = days_to_month[m - 1] + d;
106 if (m > 2 && is_leap(y)) result++;
107 return result;
108}
109
110// Credit:
111// https://stackoverflow.com/questions/1082917/mod-of-negative-number-is-melting-my-brain/1082938#1082938
112// Assumes n > 0.
113template <typename Int>
114constexpr Int floor_mod(Int k, Int n) {
115 return ((k %= n) < 0) ? k + n : k;
116}
117
118} // namespace
119
120DateTime::DateTime(uint16_t year, uint8_t month, uint8_t day, TimeZone tz)
121 : DateTime(year, month, day, 0, 0, 0, 0, tz) {}
122
123DateTime::DateTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour,
124 uint8_t minute, uint8_t second, uint32_t micros, TimeZone tz)
125 : tz_(tz),
126 year_(year),
127 month_(month),
128 day_(day),
129 hour_(hour),
130 minute_(minute),
131 second_(second),
132 micros_(micros) {
133 int64_t t = days_from_civil(year, month, day);
134 day_of_week_ = weekday_from_days(t);
135 t = ((((t * 24) + hour) * 60 + minute) * 60 + second) * 1000000 + micros;
136 day_of_year_ = day_of_year(year, month, day);
137 walltime_ = WallTime(Micros(t) - tz.offset());
138}
139
141 : walltime_(wall_time), tz_(tz) {
142 Duration sinceEpochTz = wall_time.sinceEpoch() + tz.offset();
143 int32_t unix_days = sinceEpochTz.inHours() / 24;
144 civil_from_days(unix_days, &year_, &month_, &day_);
145 day_of_year_ = day_of_year(year_, month_, day_);
146 day_of_week_ = weekday_from_days(unix_days);
147 uint64_t since_midnight = floor_mod<int64_t>(sinceEpochTz.inMicros(),
148 (uint64_t)1000000 * 3600 * 24);
149 micros_ = since_midnight % 1000000L;
150 since_midnight /= 1000000L;
151 second_ = since_midnight % 60;
152 since_midnight /= 60;
153 minute_ = since_midnight % 60;
154 since_midnight /= 60;
155 hour_ = since_midnight;
156}
157
158} // namespace roo_time
Represents wall time decomposed into date/time in a specific time zone.
Definition roo_time.h:735
int16_t year() const
Returns four-digit year.
Definition roo_time.h:770
Month month() const
Returns month in [1, 12].
Definition roo_time.h:773
uint8_t second() const
Returns second in [0, 59].
Definition roo_time.h:785
uint32_t micros() const
Returns microsecond fraction in [0, 999999].
Definition roo_time.h:788
uint8_t minute() const
Returns minute in [0, 59].
Definition roo_time.h:782
uint8_t hour() const
Returns hour in [0, 23].
Definition roo_time.h:779
DateTime()
Constructs DateTime representing current time in UTC.
Definition roo_time.h:738
uint8_t day() const
Returns day of month in valid range.
Definition roo_time.h:776
Represents an amount of time (e.g. 5s, 10min).
Definition roo_time.h:25
constexpr int64_t inHours() const
Returns duration in hours, rounded toward zero.
Definition roo_time.h:62
static Duration FromComponents(const Components &components)
Reconstructs duration from components.
Definition roo_time.cpp:28
Components toComponents()
Breaks duration into components (days, hours, minutes, ...).
Definition roo_time.cpp:10
friend constexpr Duration Micros(long long micros)
Constructs a duration from microseconds.
Definition roo_time.h:216
constexpr int64_t inMicros() const
Returns duration in microseconds.
Definition roo_time.h:44
constexpr Duration offset() const
Returns UTC offset of this time zone.
Definition roo_time.h:695
Represents absolute wall time since Unix epoch.
Definition roo_time.h:581
Duration sinceEpoch() const
Returns elapsed duration since Unix epoch.
Definition roo_time.h:590
Umbrella header for the roo_time module.
Definition roo_time.cpp:3
constexpr Duration Micros(long long micros)
Constructs a duration from microseconds.
Definition roo_time.h:216
Calendar-like decomposition of a duration value.
Definition roo_time.h:28