AceTime  0.3
Date and time classes for Arduino that support timezones from the TZ Database, and a system clock that can synchronize from an NTP server or an RTC chip.
LocalDate.h
1 #ifndef ACE_TIME_LOCAL_DATE_H
2 #define ACE_TIME_LOCAL_DATE_H
3 
4 #include <stdint.h>
5 #include "common/common.h"
6 #include "LocalTime.h"
7 
8 class Print;
9 
10 namespace ace_time {
11 
30 class LocalDate {
31  public:
33  static const int16_t kEpochYear = 2000;
34 
39  static const int8_t kInvalidYearTiny = INT8_MIN;
40 
42  static const acetime_t kInvalidEpochDays = INT32_MIN;
43 
46 
51  static const acetime_t kSecondsSinceUnixEpoch = 946684800;
52 
57  static const acetime_t kDaysSinceUnixEpoch = 10957;
58 
60  static const uint8_t kMonday = 1;
61 
63  static const uint8_t kTuesday = 2;
64 
66  static const uint8_t kWednesday = 3;
67 
69  static const uint8_t kThursday = 4;
70 
72  static const uint8_t kFriday = 5;
73 
75  static const uint8_t kSaturday = 6;
76 
78  static const uint8_t kSunday = 7;
79 
88  static LocalDate forComponents(int16_t year, uint8_t month, uint8_t day) {
89  int8_t yearTiny = isYearValid(year)
90  ? year - kEpochYear : kInvalidYearTiny;
91  return LocalDate(yearTiny, month, day);
92  }
93 
95  static LocalDate forTinyComponents(int8_t yearTiny, uint8_t month,
96  uint8_t day) {
97  return LocalDate(yearTiny, month, day);
98  }
99 
107  static LocalDate forEpochDays(acetime_t epochDays) {
108  int16_t year;
109  uint8_t month;
110  uint8_t day;
111  if (epochDays == kInvalidEpochDays) {
112  year = month = day = 0;
113  } else {
114  extractYearMonthDay(epochDays, year, month, day);
115  }
116  return forComponents(year, month, day);
117  }
118 
120  static LocalDate forUnixDays(acetime_t unixDays) {
121  if (unixDays == kInvalidEpochDays) {
122  return forEpochDays(unixDays);
123  } else {
124  return forEpochDays(unixDays - kDaysSinceUnixEpoch);
125  }
126  }
127 
139  static LocalDate forEpochSeconds(acetime_t epochSeconds) {
140  if (epochSeconds == kInvalidEpochSeconds) {
141  return forEpochDays(kInvalidEpochDays);
142  } else {
143  // integer floor-division towards -infinity
144  acetime_t days = (epochSeconds < 0)
145  ? (epochSeconds + 1) / 86400 - 1
146  : epochSeconds / 86400;
147  return forEpochDays(days);
148  }
149  }
150 
156  static LocalDate forUnixSeconds(acetime_t unixSeconds) {
157  if (unixSeconds == kInvalidEpochSeconds) {
158  return forEpochSeconds(unixSeconds);
159  } else {
160  return forEpochSeconds(unixSeconds - kSecondsSinceUnixEpoch);
161  }
162  }
163 
173  static LocalDate forDateString(const char* dateString);
174 
182  static LocalDate forDateStringChainable(const char*& dateString);
183 
188  static LocalDate forError() {
189  return LocalDate(kInvalidYearTiny, 0, 0);
190  }
191 
193  static bool isLeapYear(int16_t year) {
194  return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
195  }
196 
198  static bool isYearValid(int16_t year) {
199  return year >= kEpochYear + kMinYearTiny
200  && year <= kEpochYear + kMaxYearTiny;
201  }
202 
204  static uint8_t daysInMonth(int16_t year, uint8_t month) {
205  uint8_t days = sDaysInMonth[month - 1];
206  return (month == 2 && isLeapYear(year)) ? days + 1 : days;
207  }
208 
210  explicit LocalDate() {}
211 
213  int16_t year() const { return mYearTiny + kEpochYear; }
214 
216  void year(int16_t year) { mYearTiny = year - kEpochYear; }
217 
219  int8_t yearTiny() const { return mYearTiny; }
220 
222  void yearTiny(int8_t yearTiny) { mYearTiny = yearTiny; }
223 
225  uint8_t month() const { return mMonth; }
226 
228  void month(uint8_t month) { mMonth = month; }
229 
231  uint8_t day() const { return mDay; }
232 
234  void day(uint8_t day) { mDay = day; }
235 
242  uint8_t dayOfWeek() const {
243  // The "year" starts in March to shift leap year calculation to end.
244  int16_t y = year() - (mMonth < 3);
245  int16_t d = y + y/4 - y/100 + y/400 + sDayOfWeek[mMonth-1] + mDay;
246 
247  // 2000-1-1 was a Saturday=6, so set the offsets accordingly
248  return (d < -1) ? (d + 1) % 7 + 8 : (d + 1) % 7 + 1;
249  }
250 
252  bool isError() const {
253  return mYearTiny == kInvalidYearTiny
254  || mDay < 1 || mDay > 31
255  || mMonth < 1 || mMonth > 12;
256  }
257 
274  acetime_t toEpochDays() const {
275  if (isError()) return kInvalidEpochDays;
276 
277  // From wiki article:
278  //
279  // JDN = (1461 x (Y + 4800 + (M - 14)/12))/4
280  // + (367 x (M - 2 - 12 x ((M - 14)/12)))/12
281  // - (3 x ((Y + 4900 + (M - 14)/12)/100))/4
282  // + D - 32075
283  // JDN2000 = JDN - 2451545
284  //
285  // It looks like the formula needs to be done using signed integers
286  // because it depends on the modulo operation (%) to truncate towards 0
287  // for negative numbers.
288 
289  int8_t mm = (mMonth - 14)/12;
290  int16_t yy = year();
291  int32_t jdn = ((int32_t) 1461 * (yy + 4800 + mm))/4
292  + (367 * (mMonth - 2 - 12 * mm))/12
293  - (3 * ((yy + 4900 + mm)/100))/4
294  + mDay - 32075;
295  return jdn - kDaysSinceJulianEpoch;
296  }
297 
299  acetime_t toUnixDays() const {
300  if (isError()) return kInvalidEpochDays;
301  return toEpochDays() + kDaysSinceUnixEpoch;
302  }
303 
314  acetime_t toEpochSeconds() const {
315  if (isError()) return kInvalidEpochSeconds;
316  return 86400 * toEpochDays();
317  }
318 
322  acetime_t toUnixSeconds() const {
323  if (isError()) return kInvalidEpochSeconds;
324  return 86400 * toUnixDays();
325  }
326 
332  int8_t compareTo(const LocalDate& that) const {
333  if (mYearTiny < that.mYearTiny) return -1;
334  if (mYearTiny > that.mYearTiny) return 1;
335  if (mMonth < that.mMonth) return -1;
336  if (mMonth > that.mMonth) return 1;
337  if (mDay < that.mDay) return -1;
338  if (mDay > that.mDay) return 1;
339  return 0;
340  }
341 
348  void printTo(Print& printer) const;
349 
350  // Use default copy constructor and assignment operator.
351  LocalDate(const LocalDate&) = default;
352  LocalDate& operator=(const LocalDate&) = default;
353 
354  private:
355  friend bool operator==(const LocalDate& a, const LocalDate& b);
356 
361  static const int8_t kMinYearTiny = INT8_MIN + 1;
362 
367  static const int8_t kMaxYearTiny = INT8_MAX;
368 
373  static const acetime_t kDaysSinceJulianEpoch = 2451545;
374 
376  static const uint8_t kDateStringLength = 10;
377 
383  static const uint8_t sDayOfWeek[12];
384 
386  static const uint8_t sDaysInMonth[12];
387 
389  explicit LocalDate(int8_t yearTiny, uint8_t month, uint8_t day):
390  mYearTiny(yearTiny),
391  mMonth(month),
392  mDay(day) {}
393 
399  static void extractYearMonthDay(acetime_t epochDays, int16_t& year,
400  uint8_t& month, uint8_t& day) {
401  uint32_t J = epochDays + kDaysSinceJulianEpoch;
402  uint32_t f = J + 1401 + (((4 * J + 274277 ) / 146097) * 3) / 4 - 38;
403  uint32_t e = 4 * f + 3;
404  uint32_t g = e % 1461 / 4;
405  uint32_t h = 5 * g + 2;
406  day = (h % 153) / 5 + 1;
407  month = (h / 153 + 2) % 12 + 1;
408  year = (e / 1461) - 4716 + (12 + 2 - month) / 12;
409 
410  // 2000-01-01 is Saturday (7)
411  //dayOfWeek = (epochDays + 6) % 7 + 1;
412  }
413 
418  int8_t mYearTiny; // [-127, 127], -128 indicates error
419 
420  uint8_t mMonth; // [1, 12], 0 indicates error
421  uint8_t mDay; // [1, 31], 0 indicates error
422 };
423 
425 inline bool operator==(const LocalDate& a, const LocalDate& b) {
426  return a.mDay == b.mDay
427  && a.mMonth == b.mMonth
428  && a.mYearTiny == b.mYearTiny;
429 }
430 
432 inline bool operator!=(const LocalDate& a, const LocalDate& b) {
433  return ! (a == b);
434 }
435 
436 }
437 
438 #endif
static const acetime_t kSecondsSinceUnixEpoch
Number of seconds from Unix epoch (1970-01-01 00:00:00Z) to the AceTime epoch (2000-01-01 00:00:00Z)...
Definition: LocalDate.h:51
static LocalDate forEpochDays(acetime_t epochDays)
Factory method using the number of days since AceTime epoch of 2000-01-01.
Definition: LocalDate.h:107
static const acetime_t kDaysSinceUnixEpoch
Number of days from Unix epoch (1970-01-01 00:00:00Z) to the AceTime epoch (2000-01-01 00:00:00Z)...
Definition: LocalDate.h:57
static const uint8_t kWednesday
Wednesday ISO 8601 number.
Definition: LocalDate.h:66
static LocalDate forError()
Factory method that returns a LocalDate which represents an error condition.
Definition: LocalDate.h:188
static const uint8_t kThursday
Thursday ISO 8601 number.
Definition: LocalDate.h:69
static const acetime_t kInvalidEpochDays
Sentinel epochDays which indicates an error.
Definition: LocalDate.h:42
static LocalDate forUnixDays(acetime_t unixDays)
Factory method using the number of days since Unix epoch 1970-01-1.
Definition: LocalDate.h:120
LocalDate()
Default constructor does nothing.
Definition: LocalDate.h:210
int8_t yearTiny() const
Return the single-byte year offset from year 2000.
Definition: LocalDate.h:219
static const acetime_t kInvalidEpochSeconds
Sentinel epochSeconds which indicates an error.
Definition: LocalDate.h:45
static const acetime_t kInvalidSeconds
An invalid seconds marker that indicates isError() true.
Definition: LocalTime.h:23
static LocalDate forDateString(const char *dateString)
Factory method.
Definition: LocalDate.cpp:62
static bool isLeapYear(int16_t year)
True if year is a leap year.
Definition: LocalDate.h:193
void printTo(Print &printer) const
Print LocalDate to &#39;printer&#39; in ISO 8601 format, along with the day of week.
Definition: LocalDate.cpp:43
acetime_t toEpochDays() const
Return number of days since AceTime epoch (2000-01-01 00:00:00Z).
Definition: LocalDate.h:274
static LocalDate forTinyComponents(int8_t yearTiny, uint8_t month, uint8_t day)
Factory method using components with an int8_t yearTiny.
Definition: LocalDate.h:95
static LocalDate forDateStringChainable(const char *&dateString)
Variant of forDateString() that updates the pointer to the next unprocessed character.
Definition: LocalDate.cpp:69
bool isError() const
Return true if any component indicates an error condition.
Definition: LocalDate.h:252
uint8_t day() const
Return the day of the month.
Definition: LocalDate.h:231
acetime_t toEpochSeconds() const
Return the number of seconds since AceTime epoch (2000-01-01 00:00:00).
Definition: LocalDate.h:314
acetime_t toUnixDays() const
Return the number of days since Unix epoch (1970-01-01 00:00:00).
Definition: LocalDate.h:299
friend bool operator==(const LocalDate &a, const LocalDate &b)
Return true if two LocalDate objects are equal in all components.
Definition: LocalDate.h:425
static LocalDate forEpochSeconds(acetime_t epochSeconds)
Factory method using the number of seconds since AceTime epoch of 2000-01-01.
Definition: LocalDate.h:139
void year(int16_t year)
Set the year given the full year.
Definition: LocalDate.h:216
acetime_t toUnixSeconds() const
Return the number of seconds since Unix epoch (1970-01-01 00:00:00).
Definition: LocalDate.h:322
void yearTiny(int8_t yearTiny)
Set the single-byte year offset from year 2000.
Definition: LocalDate.h:222
static LocalDate forUnixSeconds(acetime_t unixSeconds)
Factory method that takes the number of seconds since Unix Epoch of 1970-01-01.
Definition: LocalDate.h:156
static const int8_t kInvalidYearTiny
Sentinel yearTiny which indicates an error condition or sometimes a year that &#39;does not exist&#39;...
Definition: LocalDate.h:39
static LocalDate forComponents(int16_t year, uint8_t month, uint8_t day)
Factory method using separated year, month and day fields.
Definition: LocalDate.h:88
static const uint8_t kSunday
Sunday ISO 8601 number.
Definition: LocalDate.h:78
The date (year, month, day) representing the date without regards to time zone.
Definition: LocalDate.h:30
static const uint8_t kFriday
Friday ISO 8601 number.
Definition: LocalDate.h:72
static const uint8_t kSaturday
Saturday ISO 8601 number.
Definition: LocalDate.h:75
static const uint8_t kTuesday
Tuesday ISO 8601 number.
Definition: LocalDate.h:63
void month(uint8_t month)
Set the month.
Definition: LocalDate.h:228
static const int16_t kEpochYear
Base year of epoch.
Definition: LocalDate.h:33
static uint8_t daysInMonth(int16_t year, uint8_t month)
Return the number of days in the current month.
Definition: LocalDate.h:204
uint8_t month() const
Return the month with January=1, December=12.
Definition: LocalDate.h:225
static bool isYearValid(int16_t year)
Return true if year is within valid range of [1873, 2127].
Definition: LocalDate.h:198
int16_t year() const
Return the full year instead of just the last 2 digits.
Definition: LocalDate.h:213
void day(uint8_t day)
Set the day of the month.
Definition: LocalDate.h:234
int8_t compareTo(const LocalDate &that) const
Compare this LocalDate to that LocalDate, returning (<0, 0, >0) according to whether the epochSeconds...
Definition: LocalDate.h:332
static const uint8_t kMonday
Monday ISO 8601 number.
Definition: LocalDate.h:60
uint8_t dayOfWeek() const
Calculate the day of week given the (year, month, day).
Definition: LocalDate.h:242