AceTime  2.3.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()
8 #include "ZoneProcessor.h"
9 
10 namespace ace_time {
11 namespace internal {
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 
91 void createAbbreviation(
92  char* dest,
93  uint8_t destSize,
94  const char* format,
95  uint32_t deltaSeconds,
96  const char* letterString) {
97 
98  // Check if FORMAT contains a '%'.
99  if (strchr(format, '%') != nullptr) {
100  // Check if RULES column empty, therefore no 'letter'
101  if (letterString == nullptr) {
102  strncpy(dest, format, destSize - 1);
103  dest[destSize - 1] = '\0';
104  } else {
105  // Copy `letterString` into a local buffer, in case `letterString` is
106  // the same as `dest.
107  char letter[internal::kAbbrevSize];
108  if (letterString) {
109  strncpy(letter, letterString, internal::kAbbrevSize - 1);
110  letter[internal::kAbbrevSize - 1] = '\0';
111  } else {
112  letter[0] = '\0';
113  }
114 
115  ace_common::copyReplaceString(dest, destSize, format, '%', letter);
116  }
117  } else {
118  // Check if FORMAT contains a '/'.
119  const char* slashPos = strchr(format, '/');
120  if (slashPos != nullptr) {
121  if (deltaSeconds == 0) {
122  uint8_t headLength = (slashPos - format);
123  if (headLength >= destSize) headLength = destSize - 1;
124  memcpy(dest, format, headLength);
125  dest[headLength] = '\0';
126  } else {
127  uint8_t tailLength = strlen(slashPos+1);
128  if (tailLength >= destSize) tailLength = destSize - 1;
129  memcpy(dest, slashPos+1, tailLength);
130  dest[tailLength] = '\0';
131  }
132  } else {
133  // Just copy the FORMAT disregarding deltaSeconds and letterString.
134  strncpy(dest, format, destSize - 1);
135  dest[destSize - 1] = '\0';
136  }
137  }
138 }
139 
140 } // internal
141 } // ace_time
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 uint8_t daysInMonth(int16_t year, uint8_t month)
Return the number of days in the given (year, month).
Definition: LocalDate.h:133