AceTime  0.1
Date and time classes for Arduino that supports the TZ DAtabase, and a system clock synchronized 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 
32 class LocalDate {
33  public:
35  static const int16_t kEpochYear = 2000;
36 
41  static const int8_t kInvalidYearTiny = INT8_MIN;
42 
47  static const int8_t kMinYearTiny = INT8_MIN + 1;
48 
50  static const acetime_t kInvalidEpochDays = INT32_MIN;
51 
54 
59  static const acetime_t kSecondsSinceUnixEpoch = 946684800;
60 
65  static const acetime_t kDaysSinceUnixEpoch = 10957;
66 
71  static const acetime_t kDaysSinceJulianEpoch = 2451545;
72 
74  static const uint8_t kMonday = 1;
75 
77  static const uint8_t kTuesday = 2;
78 
80  static const uint8_t kWednesday = 3;
81 
83  static const uint8_t kThursday = 4;
84 
86  static const uint8_t kFriday = 5;
87 
89  static const uint8_t kSaturday = 6;
90 
92  static const uint8_t kSunday = 7;
93 
102  static LocalDate forComponents(int16_t year, uint8_t month, uint8_t day) {
103  return LocalDate(year - kEpochYear, month, day);
104  }
105 
113  static LocalDate forEpochDays(acetime_t epochDays) {
114  int16_t year;
115  uint8_t month;
116  uint8_t day;
117  if (epochDays == kInvalidEpochDays) {
118  year = month = day = 0;
119  } else {
120  extractYearMonthDay(epochDays, year, month, day);
121  }
122  return forComponents(year, month, day);
123  }
124 
126  static LocalDate forUnixDays(acetime_t unixDays) {
127  if (unixDays == kInvalidEpochDays) {
128  return forEpochDays(unixDays);
129  } else {
130  return forEpochDays(unixDays - kDaysSinceUnixEpoch);
131  }
132  }
133 
145  static LocalDate forEpochSeconds(acetime_t epochSeconds) {
146  if (epochSeconds == kInvalidEpochSeconds) {
147  return forEpochDays(kInvalidEpochDays);
148  } else {
149  // integer floor-division towards -infinity
150  acetime_t days = (epochSeconds < 0)
151  ? (epochSeconds + 1) / 86400 - 1
152  : epochSeconds / 86400;
153  return forEpochDays(days);
154  }
155  }
156 
162  static LocalDate forUnixSeconds(acetime_t unixSeconds) {
163  if (unixSeconds == kInvalidEpochSeconds) {
164  return forEpochSeconds(unixSeconds);
165  } else {
166  return forEpochSeconds(unixSeconds - kSecondsSinceUnixEpoch);
167  }
168  }
169 
178  static LocalDate forDateString(const char* dateString);
179 
184  static LocalDate forError() {
185  return LocalDate(0, 0, 0);
186  }
187 
189  static bool isLeapYear(int16_t year) {
190  return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
191  }
192 
194  static uint8_t daysInMonth(int16_t year, uint8_t month) {
195  uint8_t days = sDaysInMonth[month - 1];
196  return (month == 2 && isLeapYear(year)) ? days + 1 : days;
197  }
198 
200  explicit LocalDate() {}
201 
203  int16_t year() const { return mYearTiny + kEpochYear; }
204 
206  void year(int16_t year) { mYearTiny = year - kEpochYear; }
207 
209  int8_t yearTiny() const { return mYearTiny; }
210 
212  void yearTiny(int8_t yearTiny) { mYearTiny = yearTiny; }
213 
215  uint8_t month() const { return mMonth; }
216 
218  void month(uint8_t month) { mMonth = month; }
219 
221  uint8_t day() const { return mDay; }
222 
224  void day(uint8_t day) { mDay = day; }
225 
232  uint8_t dayOfWeek() const {
233  // The "year" starts in March to shift leap year calculation to end.
234  int16_t y = year() - (mMonth < 3);
235  int16_t d = y + y/4 - y/100 + y/400 + sDayOfWeek[mMonth-1] + mDay;
236 
237  // 2000-1-1 was a Saturday=6, so set the offsets accordingly
238  return (d < -1) ? (d + 1) % 7 + 8 : (d + 1) % 7 + 1;
239  }
240 
242  bool isError() const {
243  return mDay < 1 || mDay > 31
244  || mMonth < 1 || mMonth > 12;
245  }
246 
263  acetime_t toEpochDays() const {
264  if (isError()) return kInvalidEpochDays;
265 
266  // From wiki article:
267  //
268  // JDN = (1461 x (Y + 4800 + (M - 14)/12))/4
269  // + (367 x (M - 2 - 12 x ((M - 14)/12)))/12
270  // - (3 x ((Y + 4900 + (M - 14)/12)/100))/4
271  // + D - 32075
272  // JDN2000 = JDN - 2451545
273  //
274  // It looks like the formula needs to be done using signed integers
275  // because it depends on the modulo operation (%) to truncate towards 0
276  // for negative numbers.
277 
278  int8_t mm = (mMonth - 14)/12;
279  int16_t yy = year();
280  int32_t jdn = ((int32_t) 1461 * (yy + 4800 + mm))/4
281  + (367 * (mMonth - 2 - 12 * mm))/12
282  - (3 * ((yy + 4900 + mm)/100))/4
283  + mDay - 32075;
284  return jdn - kDaysSinceJulianEpoch;
285  }
286 
288  acetime_t toUnixDays() const {
289  if (isError()) return kInvalidEpochDays;
290  return toEpochDays() + kDaysSinceUnixEpoch;
291  }
292 
303  acetime_t toEpochSeconds() const {
304  if (isError()) return kInvalidEpochSeconds;
305  return 86400 * toEpochDays();
306  }
307 
311  acetime_t toUnixSeconds() const {
312  if (isError()) return kInvalidEpochSeconds;
313  return 86400 * toUnixDays();
314  }
315 
321  int8_t compareTo(const LocalDate& that) const {
322  if (mYearTiny < that.mYearTiny) return -1;
323  if (mYearTiny > that.mYearTiny) return 1;
324  if (mMonth < that.mMonth) return -1;
325  if (mMonth > that.mMonth) return 1;
326  if (mDay < that.mDay) return -1;
327  if (mDay > that.mDay) return 1;
328  return 0;
329  }
330 
336  void printTo(Print& printer) const;
337 
338  // Use default copy constructor and assignment operator.
339  LocalDate(const LocalDate&) = default;
340  LocalDate& operator=(const LocalDate&) = default;
341 
342  private:
343  friend class LocalDateTime; // constructor, forDateStringChainable()
344  friend class ExtendedZoneSpecifier; // constructor
345  friend bool operator==(const LocalDate& a, const LocalDate& b);
346 
348  static const uint8_t kDateStringLength = 10;
349 
355  static const uint8_t sDayOfWeek[12];
356 
358  static const uint8_t sDaysInMonth[12];
359 
367  static LocalDate forDateStringChainable(const char*& dateString);
368 
370  explicit LocalDate(int8_t yearTiny, uint8_t month, uint8_t day):
371  mYearTiny(yearTiny),
372  mMonth(month),
373  mDay(day) {}
374 
380  static void extractYearMonthDay(acetime_t epochDays, int16_t& year,
381  uint8_t& month, uint8_t& day) {
382  uint32_t J = epochDays + kDaysSinceJulianEpoch;
383  uint32_t f = J + 1401 + (((4 * J + 274277 ) / 146097) * 3) / 4 - 38;
384  uint32_t e = 4 * f + 3;
385  uint32_t g = e % 1461 / 4;
386  uint32_t h = 5 * g + 2;
387  day = (h % 153) / 5 + 1;
388  month = (h / 153 + 2) % 12 + 1;
389  year = (e / 1461) - 4716 + (12 + 2 - month) / 12;
390 
391  // 2000-01-01 is Saturday (7)
392  //dayOfWeek = (epochDays + 6) % 7 + 1;
393  }
394 
399  int8_t mYearTiny; // [-128, 127], year offset from 2000
400 
401  uint8_t mMonth; // [1, 12], 0 indicates error
402  uint8_t mDay; // [1, 31], 0 indicates error
403 };
404 
406 inline bool operator==(const LocalDate& a, const LocalDate& b) {
407  return a.mDay == b.mDay
408  && a.mMonth == b.mMonth
409  && a.mYearTiny == b.mYearTiny;
410 }
411 
413 inline bool operator!=(const LocalDate& a, const LocalDate& b) {
414  return ! (a == b);
415 }
416 
417 }
418 
419 #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:59
static LocalDate forEpochDays(acetime_t epochDays)
Factory method using the number of days since AceTime epoch of 2000-01-01.
Definition: LocalDate.h:113
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:65
static const uint8_t kWednesday
Wednesday ISO 8601 number.
Definition: LocalDate.h:80
static LocalDate forError()
Factory method that returns a LocalDate which represents an error condition.
Definition: LocalDate.h:184
static const uint8_t kThursday
Thursday ISO 8601 number.
Definition: LocalDate.h:83
static const acetime_t kInvalidEpochDays
Sentinel epochDays which indicates an error.
Definition: LocalDate.h:50
static LocalDate forUnixDays(acetime_t unixDays)
Factory method using the number of days since Unix epoch 1970-01-1.
Definition: LocalDate.h:126
LocalDate()
Default constructor does nothing.
Definition: LocalDate.h:200
static const int8_t kMinYearTiny
Sentinel yearTiny which represents the smallest year, effectively -Infinity.
Definition: LocalDate.h:47
static const acetime_t kInvalidEpochSeconds
Sentinel epochSeconds which indicates an error.
Definition: LocalDate.h:53
static const acetime_t kInvalidSeconds
An invalid seconds marker that indicates isError() true.
Definition: LocalTime.h:23
acetime_t toEpochSeconds() const
Return the number of seconds since AceTime epoch (2000-01-01 00:00:00).
Definition: LocalDate.h:303
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:189
uint8_t month() const
Return the month with January=1, December=12.
Definition: LocalDate.h:215
bool isError() const
Return true if any component indicates an error condition.
Definition: LocalDate.h:242
An implementation of ZoneSpecifier that works for all zones defined by the TZ Database (with some zon...
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
int16_t year() const
Return the full year instead of just the last 2 digits.
Definition: LocalDate.h:203
friend bool operator==(const LocalDate &a, const LocalDate &b)
Return true if two LocalDate objects are equal in all components.
Definition: LocalDate.h:406
uint8_t day() const
Return the day of the month.
Definition: LocalDate.h:221
static LocalDate forEpochSeconds(acetime_t epochSeconds)
Factory method using the number of seconds since AceTime epoch of 2000-01-01.
Definition: LocalDate.h:145
static const acetime_t kDaysSinceJulianEpoch
Number of days between the Julian calendar epoch (4713 BC 01-01) and the AceTime epoch (2000-01-01)...
Definition: LocalDate.h:71
void year(int16_t year)
Set the year given the full year.
Definition: LocalDate.h:206
void yearTiny(int8_t yearTiny)
Set the single-byte year offset from year 2000.
Definition: LocalDate.h:212
static LocalDate forUnixSeconds(acetime_t unixSeconds)
Factory method that takes the number of seconds since Unix Epoch of 1970-01-01.
Definition: LocalDate.h:162
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:41
static LocalDate forComponents(int16_t year, uint8_t month, uint8_t day)
Factory method using separated year, month and day fields.
Definition: LocalDate.h:102
static const uint8_t kSunday
Sunday ISO 8601 number.
Definition: LocalDate.h:92
The date (year, month, day) representing the date without regards to time zone.
Definition: LocalDate.h:32
static const uint8_t kFriday
Friday ISO 8601 number.
Definition: LocalDate.h:86
static const uint8_t kSaturday
Saturday ISO 8601 number.
Definition: LocalDate.h:89
static const uint8_t kTuesday
Tuesday ISO 8601 number.
Definition: LocalDate.h:77
void month(uint8_t month)
Set the month.
Definition: LocalDate.h:218
static const int16_t kEpochYear
Base year of epoch.
Definition: LocalDate.h:35
static uint8_t daysInMonth(int16_t year, uint8_t month)
Return the number of days in the current month.
Definition: LocalDate.h:194
uint8_t dayOfWeek() const
Calculate the day of week given the (year, month, day).
Definition: LocalDate.h:232
acetime_t toUnixSeconds() const
Return the number of seconds since Unix epoch (1970-01-01 00:00:00).
Definition: LocalDate.h:311
void day(uint8_t day)
Set the day of the month.
Definition: LocalDate.h:224
int8_t yearTiny() const
Return the single-byte year offset from year 2000.
Definition: LocalDate.h:209
acetime_t toEpochDays() const
Return number of days since AceTime epoch (2000-01-01 00:00:00Z).
Definition: LocalDate.h:263
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:321
acetime_t toUnixDays() const
Return the number of days since Unix epoch (1970-01-01 00:00:00).
Definition: LocalDate.h:288
static const uint8_t kMonday
Monday ISO 8601 number.
Definition: LocalDate.h:74