AceTime 3.0.0 Date and time classes for Arduino that support timezones from the TZ Database.

ZoneProcessor.cpp
1 /*
2 * MIT License
3 * Copyright (c) 2019 Brian T. Park
4 */
5
6 #include <string.h> // strchr(), strncpy(), memcpy()
7 #include <AceCommon.h> // copyReplaceString(), PrintStr
8 #include "ZoneProcessor.h"
9 #include "common/DateConv.h" // secondsToHms()
10
11 namespace ace_time {
12
13 MonthDay calcStartDayOfMonth(int16_t year, uint8_t month,
14 uint8_t onDayOfWeek, int8_t onDayOfMonth) {
15 if (onDayOfWeek == 0) return {month, (uint8_t) onDayOfMonth};
16
17 if (onDayOfMonth >= 0) {
18 // Convert "last{Xxx}" to "last{Xxx}>={daysInMonth-6}".
19 uint8_t daysInMonth = LocalDate::daysInMonth(year, month);
20 if (onDayOfMonth == 0) {
21 onDayOfMonth = daysInMonth - 6;
22 }
23
24 auto limitDate = LocalDate::forComponents(year, month, onDayOfMonth);
25 uint8_t dayOfWeekShift = (onDayOfWeek - limitDate.dayOfWeek() + 7) % 7;
26 uint8_t day = (uint8_t) (onDayOfMonth + dayOfWeekShift);
27 if (day > daysInMonth) {
28 // TODO: Support shifting from Dec to Jan of following year.
29 day -= daysInMonth;
30 month++;
31 }
32 return {month, day};
33 } else {
34 onDayOfMonth = -onDayOfMonth;
35 auto limitDate = LocalDate::forComponents(year, month, onDayOfMonth);
36 int8_t dayOfWeekShift = (limitDate.dayOfWeek() - onDayOfWeek + 7) % 7;
37 int8_t day = onDayOfMonth - dayOfWeekShift;
38 if (day < 1) {
39 // TODO: Support shifting from Jan to Dec of the previous year.
40 month--;
41 uint8_t daysInPrevMonth = LocalDate::daysInMonth(year, month);
42 day += daysInPrevMonth;
43 }
44 return {month, (uint8_t) day};
45 }
46 }
47
48 void createAbbreviation(
49 char* dest,
50 uint8_t destSize,
51 const char* format,
52 int32_t stdSeconds,
53 int32_t dstSeconds,
54 const char* letterString) {
55
56 // Check if FORMAT is a '%z'
57 if (*format == '\0') {
58 int32_t totalSeconds = stdSeconds + dstSeconds;
59 uint32_t secs = (totalSeconds >= 0) ? totalSeconds : -totalSeconds;
60 ace_common::PrintStr<kAbbrevSize> buf;
61 uint16_t hh, mm, ss;
62 secondsToHms(secs, &hh, &mm, &ss);
63 buf.print((totalSeconds >= 0) ? '+' : '-');
64 ace_common::printPad2To(buf, hh, '0'); // pad with leading '0'
65 if (mm != 0 || ss != 0) {
66 ace_common::printPad2To(buf, mm, '0');
67 }
68 if (ss != 0) {
69 ace_common::printPad2To(buf, ss, '0');
70 }
71 strncpy(dest, buf.cstr(), kAbbrevSize);
72 dest[destSize - 1] = '\0';
73
74 // Check if FORMAT contains a '%s'.
75 } else if (strchr(format, '%') != nullptr) {
76 // Check if RULES column empty, therefore no 'letter'
77 if (letterString == nullptr) {
78 strncpy(dest, format, destSize - 1);
79 dest[destSize - 1] = '\0';
80 } else {
81 // Copy `letterString` into a local buffer, in case `letterString` is
82 // the same as `dest.
83 char letter[kAbbrevSize];
84 if (letterString) {
85 strncpy(letter, letterString, kAbbrevSize - 1);
86 letter[kAbbrevSize - 1] = '\0';
87 } else {
88 letter[0] = '\0';
89 }
90
91 ace_common::copyReplaceString(dest, destSize, format, '%', letter);
92 }
93 } else {
94 const char* slashPos = strchr(format, '/');
95 if (slashPos != nullptr) {
96 if (dstSeconds == 0) {
97 uint8_t headLength = (slashPos - format);
98 if (headLength >= destSize) headLength = destSize - 1;
99 memcpy(dest, format, headLength);
100 dest[headLength] = '\0';
101 } else {
102 uint8_t tailLength = strlen(slashPos+1);
103 if (tailLength >= destSize) tailLength = destSize - 1;
104 memcpy(dest, slashPos+1, tailLength);
105 dest[tailLength] = '\0';
106 }
107 } else {
108 // Just copy the FORMAT disregarding dstSeconds and letterString.
109 strncpy(dest, format, destSize - 1);
110 dest[destSize - 1] = '\0';
111 }
112 }
113 }
114
115 } // ace_time
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::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::kAbbrevSize
const uint8_t kAbbrevSize
Size of the c-string buffer needed to hold a time zone abbreviation.
Definition: common.h:44