AceTime  3.0.0
Date and time classes for Arduino that support timezones from the TZ Database.
LocalDate.h
1 /*
2  * MIT License
3  * Copyright (c) 2018 Brian T. Park
4  */
5 
6 #ifndef ACE_TIME_LOCAL_DATE_H
7 #define ACE_TIME_LOCAL_DATE_H
8 
9 #include <stdint.h>
10 #include <string.h> // strlen()
11 #include "Epoch.h"
12 #include "common/common.h"
13 
14 class Print;
15 
16 namespace ace_time {
17 
46 class LocalDate {
47  public:
58  static const int16_t kInvalidYear = INT16_MIN;
59 
69  static const int16_t kMinYear = 0;
70 
78  static const int16_t kMaxYear = 10000;
79 
81  static const int32_t kInvalidEpochDays = INT32_MIN;
82 
84  static const int32_t kInvalidEpochSeconds = INT32_MIN;
85 
87  static const int64_t kInvalidUnixSeconds64 = INT64_MIN;
88 
95  static const acetime_t kMinEpochSeconds = INT32_MIN + 1;
96 
102  static const acetime_t kMaxEpochSeconds = INT32_MAX;
103 
105  static const uint8_t kMonday = 1;
106 
108  static const uint8_t kTuesday = 2;
109 
111  static const uint8_t kWednesday = 3;
112 
114  static const uint8_t kThursday = 4;
115 
117  static const uint8_t kFriday = 5;
118 
120  static const uint8_t kSaturday = 6;
121 
123  static const uint8_t kSunday = 7;
124 
125  // Utility functions
126  public:
128  static bool isLeapYear(int16_t year) {
129  return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
130  }
131 
133  static uint8_t daysInMonth(int16_t year, uint8_t month) {
134  uint8_t days = sDaysInMonth[month - 1];
135  return (month == 2 && isLeapYear(year)) ? days + 1 : days;
136  }
137 
139  static bool isYearValid(int16_t year) {
140  return kMinYear <= year && year <= kMaxYear;
141  }
142 
143  // Factory methods.
144  public:
154  int16_t year, uint8_t month, uint8_t day) {
156  return LocalDate(year, month, day);
157  }
158 
166  static LocalDate forEpochDays(int32_t epochDays) {
167  int16_t year;
168  uint8_t month;
169  uint8_t day;
170  if (epochDays == kInvalidEpochDays) {
171  year = kInvalidYear;
172  month = 0;
173  day = 0;
174  } else {
175  // shift relative to Epoch::kInternalEpochYear
177  ACE_TIME_EPOCH_CONVERTER::fromEpochDays(epochDays, year, month, day);
178  }
179  return forComponents(year, month, day);
180  }
181 
183  static LocalDate forUnixDays(int32_t unixDays) {
184  if (unixDays == kInvalidEpochDays) {
185  return forError();
186  }
187 
188  int32_t days = unixDays - Epoch::daysToCurrentEpochFromUnixEpoch();
189  return forEpochDays(days);
190  }
191 
205  static LocalDate forEpochSeconds(acetime_t epochSeconds) {
206  if (epochSeconds == kInvalidEpochSeconds) {
207  return forError();
208  }
209 
210  // integer floor-division towards -infinity
211  int32_t days = (epochSeconds < 0)
212  ? (epochSeconds + 1) / 86400 - 1
213  : epochSeconds / 86400;
214  return forEpochDays(days);
215  }
216 
224  static LocalDate forUnixSeconds64(int64_t unixSeconds) {
225  if (unixSeconds == kInvalidUnixSeconds64) {
226  return forError();
227  } else {
228  int64_t epochSeconds64 = unixSeconds
230  int32_t days = (epochSeconds64 < 0)
231  ? (epochSeconds64 + 1) / 86400 - 1
232  : epochSeconds64 / 86400;
233  return forEpochDays(days);
234  }
235  }
236 
246  static LocalDate forDateString(const char* dateString) {
247  if (strlen(dateString) < kDateStringLength) {
248  return forError();
249  }
250  return forDateStringChainable(dateString);
251  }
252 
260  static LocalDate forDateStringChainable(const char*& dateString) {
261  const char* s = dateString;
262 
263  // year (assumes 4 digit year)
264  int16_t year = (*s++ - '0');
265  year = 10 * year + (*s++ - '0');
266  year = 10 * year + (*s++ - '0');
267  year = 10 * year + (*s++ - '0');
268 
269  // '-'
270  s++;
271 
272  // month
273  uint8_t month = (*s++ - '0');
274  month = 10 * month + (*s++ - '0');
275 
276  // '-'
277  s++;
278 
279  // day
280  uint8_t day = (*s++ - '0');
281  day = 10 * day + (*s++ - '0');
282 
283  dateString = s;
284  return forComponents(year, month, day);
285  }
286 
291  static LocalDate forError() {
292  return LocalDate(kInvalidYear, 0, 0);
293  }
294 
295  // Instance methods.
296  public:
298  explicit LocalDate() = default;
299 
301  int16_t year() const { return mYear; }
302 
304  void year(int16_t year) { mYear = year; }
305 
307  uint8_t month() const { return mMonth; }
308 
310  void month(uint8_t month) { mMonth = month; }
311 
313  uint8_t day() const { return mDay; }
314 
316  void day(uint8_t day) { mDay = day; }
317 
324  uint8_t dayOfWeek() const {
325  // The "year" starts in March to shift leap year calculation to end.
326  int16_t y = year() - (mMonth < 3);
327 
328  // Each year shifts the day of week by one. Each leap year by one.
329  // Except every 100 years. Unless divisible by 400.
330  int16_t d = y + y/4 - y/100 + y/400 + sDayOfWeek[mMonth-1] + mDay;
331 
332  // 2000-01-01 was a Saturday=6, so set the offsets accordingly
333  return (d < -1) ? (d + 1) % 7 + 8 : (d + 1) % 7 + 1;
334  }
335 
337  bool isError() const {
338  return mYear == kInvalidYear
339  || mDay < 1 || mDay > 31
340  || mMonth < 1 || mMonth > 12;
341  }
342 
352  int32_t toEpochDays() const {
353  if (isError()) return kInvalidEpochDays;
354  int32_t days = ACE_TIME_EPOCH_CONVERTER::toEpochDays(mYear, mMonth, mDay)
356  return days;
357  }
358 
360  int32_t toUnixDays() const {
361  if (isError()) return kInvalidEpochDays;
363  }
364 
372  if (isError()) return kInvalidEpochSeconds;
373  return (int32_t) 86400 * toEpochDays();
374  }
375 
379  int64_t toUnixSeconds64() const {
380  if (isError()) return kInvalidUnixSeconds64;
381  return (int64_t) 86400 * toUnixDays();
382  }
383 
391  int16_t daysUntil(uint8_t month, uint8_t day) const {
392  int16_t y = year();
394  if (this->compareTo(target) > 0) {
395  target.year(y + 1);
396  }
397  return target.toEpochDays() - this->toEpochDays();
398  }
399 
406  int8_t compareTo(const LocalDate& that) const {
407  if (mYear < that.mYear) return -1;
408  if (mYear > that.mYear) return 1;
409  if (mMonth < that.mMonth) return -1;
410  if (mMonth > that.mMonth) return 1;
411  if (mDay < that.mDay) return -1;
412  if (mDay > that.mDay) return 1;
413  return 0;
414  }
415 
422  void printTo(Print& printer) const;
423 
424  // Use default copy constructor and assignment operator.
425  LocalDate(const LocalDate&) = default;
426  LocalDate& operator=(const LocalDate&) = default;
427 
428  private:
429  friend bool operator==(
430  const LocalDate& a, const LocalDate& b);
431 
433  explicit LocalDate(int16_t year, uint8_t month, uint8_t day):
434  mYear(year),
435  mMonth(month),
436  mDay(day) {}
437 
438  private:
440  static const uint8_t kDateStringLength = 10;
441 
447  static const uint8_t sDayOfWeek[12];
448 
450  static const uint8_t sDaysInMonth[12];
451 
452  int16_t mYear; // [0,10000], INT16_MIN indicates error
453  uint8_t mMonth; // [1, 12], 0 indicates error
454  uint8_t mDay; // [1, 31], 0 indicates error
455 };
456 
458 inline bool operator==(const LocalDate& a, const LocalDate& b) {
459  return a.mDay == b.mDay
460  && a.mMonth == b.mMonth
461  && a.mYear == b.mYear;
462 }
463 
465 inline bool operator!=(const LocalDate& a, const LocalDate& b) {
466  return ! (a == b);
467 }
468 
469 }
470 
471 #endif
static int32_t daysToCurrentEpochFromInternalEpoch()
Number of days from the internal epoch (2000-01-01) to the current epoch.
Definition: Epoch.h:50
static int32_t daysToCurrentEpochFromUnixEpoch()
Return the number of days from the Unix epoch (1970-01-01T00:00:00) to the current epoch.
Definition: Epoch.h:58
static int64_t secondsToCurrentEpochFromUnixEpoch64()
Return the number of seconds from the Unix epoch (1970-01-01T00:00:00) to the current epoch.
Definition: Epoch.h:69
The date (year, month, day) representing the date without regards to time zone.
Definition: LocalDate.h:46
friend bool operator==(const LocalDate &a, const LocalDate &b)
Return true if two LocalDate objects are equal in all components.
Definition: LocalDate.h:458
static const uint8_t kWednesday
Wednesday ISO 8601 number.
Definition: LocalDate.h:111
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
static const int16_t kMaxYear
The largest year that is expected to be handled by LocalDate.
Definition: LocalDate.h:78
static bool isLeapYear(int16_t year)
True if year is a leap year.
Definition: LocalDate.h:128
static const int32_t kInvalidEpochDays
Sentinel epochDays which indicates an error.
Definition: LocalDate.h:81
bool isError() const
Return true if any component indicates an error condition.
Definition: LocalDate.h:337
static const uint8_t kTuesday
Tuesday ISO 8601 number.
Definition: LocalDate.h:108
int32_t toUnixDays() const
Return the number of days since Unix epoch (1970-01-01 00:00:00).
Definition: LocalDate.h:360
static LocalDate forError()
Factory method that returns a LocalDate which represents an error condition.
Definition: LocalDate.h:291
static const acetime_t kMinEpochSeconds
Minimum valid epochSeconds.
Definition: LocalDate.h:95
static LocalDate forDateString(const char *dateString)
Factory method.
Definition: LocalDate.h:246
static LocalDate forUnixSeconds64(int64_t unixSeconds)
Factory method that takes the 64-bit number of seconds since Unix Epoch of 1970-01-01.
Definition: LocalDate.h:224
void day(uint8_t day)
Set the day of the month.
Definition: LocalDate.h:316
static const int64_t kInvalidUnixSeconds64
Sentinel unixSeconds64 which indicates an error.
Definition: LocalDate.h:87
uint8_t dayOfWeek() const
Calculate the day of week given the (year, month, day).
Definition: LocalDate.h:324
static const uint8_t kFriday
Friday ISO 8601 number.
Definition: LocalDate.h:117
static const int16_t kMinYear
The smallest year that is expected to be handled by LocalDate.
Definition: LocalDate.h:69
int64_t toUnixSeconds64() const
Return the number of seconds since Unix epoch (1970-01-01 00:00:00).
Definition: LocalDate.h:379
void printTo(Print &printer) const
Print LocalDate to 'printer' in ISO 8601 format, along with the day of week.
Definition: LocalDate.cpp:58
int8_t compareTo(const LocalDate &that) const
Compare 'this' LocalDate to 'that' LocalDate, returning (<0, 0, >0) according to whether 'this' occur...
Definition: LocalDate.h:406
static uint8_t daysInMonth(int16_t year, uint8_t month)
Return the number of days in the given (year, month).
Definition: LocalDate.h:133
void month(uint8_t month)
Set the month.
Definition: LocalDate.h:310
static bool isYearValid(int16_t year)
Return true if year is within the range of [0,10000]
Definition: LocalDate.h:139
static const int32_t kInvalidEpochSeconds
Sentinel epochSeconds which indicates an error.
Definition: LocalDate.h:84
int16_t year() const
Return the year.
Definition: LocalDate.h:301
static const acetime_t kMaxEpochSeconds
Maximum valid epochSeconds.
Definition: LocalDate.h:102
static LocalDate forEpochSeconds(acetime_t epochSeconds)
Factory method using the number of seconds since the current epoch year given by currentEpochYear().
Definition: LocalDate.h:205
int32_t toEpochDays() const
Return number of days since the current epoch year sCurrentEpochYear.
Definition: LocalDate.h:352
static const uint8_t kThursday
Thursday ISO 8601 number.
Definition: LocalDate.h:114
static const uint8_t kSaturday
Saturday ISO 8601 number.
Definition: LocalDate.h:120
static const uint8_t kMonday
Monday ISO 8601 number.
Definition: LocalDate.h:105
static LocalDate forUnixDays(int32_t unixDays)
Factory method using the number of days since Unix epoch 1970-01-01.
Definition: LocalDate.h:183
LocalDate()=default
Default constructor does nothing.
int16_t daysUntil(uint8_t month, uint8_t day) const
Calculate number of days from current LocalDate to the next target (month, day).
Definition: LocalDate.h:391
static const int16_t kInvalidYear
Sentinel year which indicates one or more of the following conditions:
Definition: LocalDate.h:58
static LocalDate forEpochDays(int32_t epochDays)
Factory method using the number of days since the current epoch (usually 2000-01-01).
Definition: LocalDate.h:166
static LocalDate forDateStringChainable(const char *&dateString)
Variant of forDateString() that updates the pointer to the next unprocessed character.
Definition: LocalDate.h:260
uint8_t month() const
Return the month with January=1, December=12.
Definition: LocalDate.h:307
acetime_t toEpochSeconds() const
Return the number of seconds since the currentEpochYear().
Definition: LocalDate.h:371
static const uint8_t kSunday
Sunday ISO 8601 number.
Definition: LocalDate.h:123
void year(int16_t year)
Set the year.
Definition: LocalDate.h:304
uint8_t day() const
Return the day of the month.
Definition: LocalDate.h:313
Identifiers used by implementation code which need to be publically exported.
int32_t acetime_t
Type for the number of seconds from epoch.
Definition: common.h:24