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:
153 static LocalDate forComponents(
154 int16_t year, uint8_t month, uint8_t day) {
155 year = isYearValid(year) ? year : kInvalidYear;
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
176 epochDays += Epoch::daysToCurrentEpochFromInternalEpoch();
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
229 - Epoch::secondsToCurrentEpochFromUnixEpoch64();
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)
355 - Epoch::daysToCurrentEpochFromInternalEpoch();
356 return days;
357 }
358
360 int32_t toUnixDays() const {
361 if (isError()) return kInvalidEpochDays;
362 return toEpochDays() + Epoch::daysToCurrentEpochFromUnixEpoch();
363 }
364
371 acetime_t toEpochSeconds() const {
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();
393 LocalDate target = LocalDate::forComponents(y, month, day);
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
ace_time::Epoch::daysToCurrentEpochFromInternalEpoch
static int32_t daysToCurrentEpochFromInternalEpoch()
Number of days from the internal epoch (2000-01-01) to the current epoch.
Definition: Epoch.h:50
ace_time::Epoch::daysToCurrentEpochFromUnixEpoch
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
ace_time::Epoch::secondsToCurrentEpochFromUnixEpoch64
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
ace_time::LocalDate
The date (year, month, day) representing the date without regards to time zone.
Definition: LocalDate.h:46
ace_time::LocalDate::operator==
friend bool operator==(const LocalDate &a, const LocalDate &b)
Return true if two LocalDate objects are equal in all components.
Definition: LocalDate.h:458
ace_time::LocalDate::kWednesday
static const uint8_t kWednesday
Wednesday ISO 8601 number.
Definition: LocalDate.h:111
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::kMaxYear
static const int16_t kMaxYear
The largest year that is expected to be handled by LocalDate.
Definition: LocalDate.h:78
ace_time::LocalDate::isLeapYear
static bool isLeapYear(int16_t year)
True if year is a leap year.
Definition: LocalDate.h:128
ace_time::LocalDate::kInvalidEpochDays
static const int32_t kInvalidEpochDays
Sentinel epochDays which indicates an error.
Definition: LocalDate.h:81
ace_time::LocalDate::isError
bool isError() const
Return true if any component indicates an error condition.
Definition: LocalDate.h:337
ace_time::LocalDate::kTuesday
static const uint8_t kTuesday
Tuesday ISO 8601 number.
Definition: LocalDate.h:108
ace_time::LocalDate::toUnixDays
int32_t toUnixDays() const
Return the number of days since Unix epoch (1970-01-01 00:00:00).
Definition: LocalDate.h:360
ace_time::LocalDate::forError
static LocalDate forError()
Factory method that returns a LocalDate which represents an error condition.
Definition: LocalDate.h:291
ace_time::LocalDate::kMinEpochSeconds
static const acetime_t kMinEpochSeconds
Minimum valid epochSeconds.
Definition: LocalDate.h:95
ace_time::LocalDate::forDateString
static LocalDate forDateString(const char *dateString)
Factory method.
Definition: LocalDate.h:246
ace_time::LocalDate::forUnixSeconds64
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
ace_time::LocalDate::day
void day(uint8_t day)
Set the day of the month.
Definition: LocalDate.h:316
ace_time::LocalDate::kInvalidUnixSeconds64
static const int64_t kInvalidUnixSeconds64
Sentinel unixSeconds64 which indicates an error.
Definition: LocalDate.h:87
ace_time::LocalDate::dayOfWeek
uint8_t dayOfWeek() const
Calculate the day of week given the (year, month, day).
Definition: LocalDate.h:324
ace_time::LocalDate::kFriday
static const uint8_t kFriday
Friday ISO 8601 number.
Definition: LocalDate.h:117
ace_time::LocalDate::kMinYear
static const int16_t kMinYear
The smallest year that is expected to be handled by LocalDate.
Definition: LocalDate.h:69
ace_time::LocalDate::toUnixSeconds64
int64_t toUnixSeconds64() const
Return the number of seconds since Unix epoch (1970-01-01 00:00:00).
Definition: LocalDate.h:379
ace_time::LocalDate::printTo
void printTo(Print &printer) const
Print LocalDate to 'printer' in ISO 8601 format, along with the day of week.
Definition: LocalDate.cpp:58
ace_time::LocalDate::compareTo
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
ace_time::LocalDate::daysInMonth
static uint8_t daysInMonth(int16_t year, uint8_t month)
Return the number of days in the given (year, month).
Definition: LocalDate.h:133
ace_time::LocalDate::month
void month(uint8_t month)
Set the month.
Definition: LocalDate.h:310
ace_time::LocalDate::isYearValid
static bool isYearValid(int16_t year)
Return true if year is within the range of [0,10000]
Definition: LocalDate.h:139
ace_time::LocalDate::kInvalidEpochSeconds
static const int32_t kInvalidEpochSeconds
Sentinel epochSeconds which indicates an error.
Definition: LocalDate.h:84
ace_time::LocalDate::year
int16_t year() const
Return the year.
Definition: LocalDate.h:301
ace_time::LocalDate::kMaxEpochSeconds
static const acetime_t kMaxEpochSeconds
Maximum valid epochSeconds.
Definition: LocalDate.h:102
ace_time::LocalDate::forEpochSeconds
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
ace_time::LocalDate::toEpochDays
int32_t toEpochDays() const
Return number of days since the current epoch year sCurrentEpochYear.
Definition: LocalDate.h:352
ace_time::LocalDate::kThursday
static const uint8_t kThursday
Thursday ISO 8601 number.
Definition: LocalDate.h:114
ace_time::LocalDate::kSaturday
static const uint8_t kSaturday
Saturday ISO 8601 number.
Definition: LocalDate.h:120
ace_time::LocalDate::kMonday
static const uint8_t kMonday
Monday ISO 8601 number.
Definition: LocalDate.h:105
ace_time::LocalDate::forUnixDays
static LocalDate forUnixDays(int32_t unixDays)
Factory method using the number of days since Unix epoch 1970-01-01.
Definition: LocalDate.h:183
ace_time::LocalDate::LocalDate
LocalDate()=default
Default constructor does nothing.
ace_time::LocalDate::daysUntil
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
ace_time::LocalDate::kInvalidYear
static const int16_t kInvalidYear
Sentinel year which indicates one or more of the following conditions:
Definition: LocalDate.h:58
ace_time::LocalDate::forEpochDays
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
ace_time::LocalDate::forDateStringChainable
static LocalDate forDateStringChainable(const char *&dateString)
Variant of forDateString() that updates the pointer to the next unprocessed character.
Definition: LocalDate.h:260
ace_time::LocalDate::month
uint8_t month() const
Return the month with January=1, December=12.
Definition: LocalDate.h:307
ace_time::LocalDate::toEpochSeconds
acetime_t toEpochSeconds() const
Return the number of seconds since the currentEpochYear().
Definition: LocalDate.h:371
ace_time::LocalDate::kSunday
static const uint8_t kSunday
Sunday ISO 8601 number.
Definition: LocalDate.h:123
ace_time::LocalDate::year
void year(int16_t year)
Set the year.
Definition: LocalDate.h:304
ace_time::LocalDate::day
uint8_t day() const
Return the day of the month.
Definition: LocalDate.h:313
common.h
Identifiers used by implementation code which need to be publically exported.
ace_time::acetime_t
int32_t acetime_t
Type for the number of seconds from epoch.
Definition: common.h:24