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