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,
151  *ttw = {tt->year, tt->month, tt->day,
152  tt->seconds + deltaSeconds,
154  } else if (tt->suffix == Info::ZoneContext::kSuffixU) {
155  *ttu = *tt;
156  *tts = {tt->year, tt->month, tt->day,
157  tt->seconds + offsetSeconds,
159  *ttw = {tt->year, tt->month, tt->day,
160  tt->seconds + (offsetSeconds + deltaSeconds),
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,
169  *ttu = {tt->year, tt->month, tt->day,
170  tt->seconds - (deltaSeconds + offsetSeconds),
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
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
int32_t toEpochDays() const
Return number of days since the current epoch year sCurrentEpochYear.
Definition: LocalDate.h:352
int32_t acetime_t
Type for the number of seconds from epoch.
Definition: common.h:24
static const uint8_t kSuffixW
Represents 'w' or wall time.
Definition: ZoneInfoLow.h:88
static const uint8_t kSuffixS
Represents 's' or standard time.
Definition: ZoneInfoLow.h:91
static const uint8_t kSuffixU
Represents 'u' or UTC time.
Definition: ZoneInfoLow.h:94
A tuple that represents a date and time.
Definition: DateTuple.h:36
void log() const
Used only for debugging.
Definition: DateTuple.h:50