AceTime 3.0.0 Date and time classes for Arduino that support timezones from the TZ Database.

DateTuple.h
1 /*
2 * MIT License
3 * Copyright (c) 2019 Brian T. Park
4 */
5
6 #ifndef ACE_TIME_DATE_TUPLE_H
7 #define ACE_TIME_DATE_TUPLE_H
8
9 #include <stdint.h> // uint8_t
10 #include "common/logging.h"
11 #include "local_date_mutation.h"
12
13 #ifndef ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG
14 #define ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG 0
15 #endif
16
17 namespace ace_time {
18 namespace extended {
19
24 enum class CompareStatus : uint8_t {
25 kFarPast, // 0
26 kPrior, // 1
27 kExactMatch, // 2
28 kWithinMatch, // 3
29 kFarFuture, // 4
30 };
31
36 struct DateTuple {
37 DateTuple() = default;
38
39 DateTuple(int16_t y, uint8_t mon, uint8_t d, int32_t secs, uint8_t mod)
40 : year(y), month(mon), day(d), seconds(secs), suffix(mod)
41 {}
42
43 int16_t year; // [-1,10000]
44 uint8_t month; // [1,12]
45 uint8_t day; // [1,31]
46 int32_t seconds; // negative values allowed
47 uint8_t suffix; // kSuffixS, kSuffixW, kSuffixU
48
50 void log() const {
51 if (ACE_TIME_EXTENDED_ZONE_PROCESSOR_DEBUG) {
52 int16_t minutes = seconds / 60;
53 int8_t second = seconds - int32_t(60) * minutes;
54 int8_t hour = minutes / 60;
55 int8_t minute = minutes - hour * 60;
56 char c = "wsu"[(suffix>>4)];
57 if (second) {
58 logging::printf("%04d-%02u-%02uT%02d:%02d:%02d%c",
59 year, month, day, hour, minute, second, c);
60 } else {
61 logging::printf("%04d-%02u-%02uT%02d:%02d%c",
62 year, month, day, hour, minute, c);
63 }
64 }
65 }
66 };
67
69 inline bool operator<(const DateTuple& a, const DateTuple& b) {
70 if (a.year < b.year) return true;
71 if (a.year > b.year) return false;
72 if (a.month < b.month) return true;
73 if (a.month > b.month) return false;
74 if (a.day < b.day) return true;
75 if (a.day > b.day) return false;
76 if (a.seconds < b.seconds) return true;
77 if (a.seconds > b.seconds) return false;
78 return false;
79 }
80
81 inline bool operator>=(const DateTuple& a, const DateTuple& b) {
82 return ! (a < b);
83 }
84
85 inline bool operator<=(const DateTuple& a, const DateTuple& b) {
86 return ! (b < a);
87 }
88
89 inline bool operator>(const DateTuple& a, const DateTuple& b) {
90 return (b < a);
91 }
92
94 inline bool operator==(const DateTuple& a, const DateTuple& b) {
95 return a.year == b.year
96 && a.month == b.month
97 && a.day == b.day
98 && a.seconds == b.seconds
99 && a.suffix == b.suffix;
100 }
101
112 inline void normalizeDateTuple(DateTuple* dt) {
113 const int32_t kOneDayAsSeconds = int32_t(60) * 60 * 24;
114 if (dt->seconds <= -kOneDayAsSeconds) {
115 LocalDate ld = LocalDate::forComponents(dt->year, dt->month, dt->day);
116 local_date_mutation::decrementOneDay(ld);
117 dt->year = ld.year();
118 dt->month = ld.month();
119 dt->day = ld.day();
120 dt->seconds += kOneDayAsSeconds;
121 } else if (kOneDayAsSeconds <= dt->seconds) {
122 LocalDate ld = LocalDate::forComponents(dt->year, dt->month, dt->day);
123 local_date_mutation::incrementOneDay(ld);
124 dt->year = ld.year();
125 dt->month = ld.month();
126 dt->day = ld.day();
127 dt->seconds -= kOneDayAsSeconds;
128 } else {
129 // do nothing
130 }
131 }
132
138 inline void expandDateTuple(
139 const DateTuple* tt,
140 int32_t offsetSeconds,
141 int32_t deltaSeconds,
142 DateTuple* ttw,
143 DateTuple* tts,
144 DateTuple* ttu) {
145
146 if (tt->suffix == Info::ZoneContext::kSuffixS) {
147 *tts = *tt;
148 *ttu = {tt->year, tt->month, tt->day,
149 tt->seconds - offsetSeconds,
150 Info::ZoneContext::kSuffixU};
151 *ttw = {tt->year, tt->month, tt->day,
152 tt->seconds + deltaSeconds,
153 Info::ZoneContext::kSuffixW};
154 } else if (tt->suffix == Info::ZoneContext::kSuffixU) {
155 *ttu = *tt;
156 *tts = {tt->year, tt->month, tt->day,
157 tt->seconds + offsetSeconds,
158 Info::ZoneContext::kSuffixS};
159 *ttw = {tt->year, tt->month, tt->day,
160 tt->seconds + (offsetSeconds + deltaSeconds),
161 Info::ZoneContext::kSuffixW};
162 } else {
163 // Explicit set the suffix to 'w' in case it was something else.
164 *ttw = *tt;
165 ttw->suffix = Info::ZoneContext::kSuffixW;
166 *tts = {tt->year, tt->month, tt->day,
167 tt->seconds - deltaSeconds,
168 Info::ZoneContext::kSuffixS};
169 *ttu = {tt->year, tt->month, tt->day,
170 tt->seconds - (deltaSeconds + offsetSeconds),
171 Info::ZoneContext::kSuffixU};
172 }
173
174 normalizeDateTuple(ttw);
175 normalizeDateTuple(tts);
176 normalizeDateTuple(ttu);
177 }
178
185 inline acetime_t subtractDateTuple(const DateTuple& a, const DateTuple& b) {
186 int32_t epochDaysA = LocalDate::forComponents(
187 a.year, a.month, a.day).toEpochDays();
188
189 int32_t epochDaysB = LocalDate::forComponents(
190 b.year, b.month, b.day).toEpochDays();
191
192 // Perform the subtraction of the days first, before converting to seconds, to
193 // prevent overflow if a.year or b.year is more than 68 years from the current
194 // epoch year.
195 return (epochDaysA - epochDaysB) * 86400 + a.seconds - b.seconds;
196 }
197
210 inline CompareStatus compareDateTupleFuzzy(
211 const DateTuple& t,
212 const DateTuple& start,
213 const DateTuple& until) {
214 // Use int32_t because a delta year of 2730 or greater will exceed
215 // the range of an int16_t.
216 int32_t tMonths = t.year * (int32_t) 12 + t.month;
217 int32_t startMonths = start.year * (int32_t) 12 + start.month;
218 if (tMonths < startMonths - 1) return CompareStatus::kPrior;
219 int32_t untilMonths = until.year * 12 + until.month;
220 if (untilMonths + 1 < tMonths) return CompareStatus::kFarFuture;
221 return CompareStatus::kWithinMatch;
222 }
223
224 } // namespace extended
225 } // namespace ace_time
226
227 #endif
ace_time::LocalDate::forComponents
static LocalDate forComponents(int16_t year, uint8_t month, uint8_t day)
Factory method using separated year, month and day fields.
Definition: LocalDate.h:153
ace_time::LocalDate::toEpochDays
int32_t toEpochDays() const
Return number of days since the current epoch year sCurrentEpochYear.
Definition: LocalDate.h:352
ace_time::acetime_t
int32_t acetime_t
Type for the number of seconds from epoch.
Definition: common.h:24
ace_time::ZoneInfoLow::ZoneContext::kSuffixW
static const uint8_t kSuffixW
Represents 'w' or wall time.
Definition: ZoneInfoLow.h:88
ace_time::ZoneInfoLow::ZoneContext::kSuffixS
static const uint8_t kSuffixS
Represents 's' or standard time.
Definition: ZoneInfoLow.h:91
ace_time::ZoneInfoLow::ZoneContext::kSuffixU
static const uint8_t kSuffixU
Represents 'u' or UTC time.
Definition: ZoneInfoLow.h:94
ace_time::extended::DateTuple
A tuple that represents a date and time.
Definition: DateTuple.h:36
ace_time::extended::DateTuple::log
void log() const
Used only for debugging.
Definition: DateTuple.h:50