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
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
const uint8_t kAbbrevSize
Size of the c-string buffer needed to hold a time zone abbreviation.
Definition: common.h:44