summaryrefslogtreecommitdiff
path: root/absl/time/internal/cctz/src/time_zone_format.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/time/internal/cctz/src/time_zone_format.cc')
-rw-r--r--absl/time/internal/cctz/src/time_zone_format.cc124
1 files changed, 100 insertions, 24 deletions
diff --git a/absl/time/internal/cctz/src/time_zone_format.cc b/absl/time/internal/cctz/src/time_zone_format.cc
index a4428632..2e02233c 100644
--- a/absl/time/internal/cctz/src/time_zone_format.cc
+++ b/absl/time/internal/cctz/src/time_zone_format.cc
@@ -67,6 +67,48 @@ char* strptime(const char* s, const char* fmt, std::tm* tm) {
}
#endif
+// Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0).
+int ToTmWday(weekday wd) {
+ switch (wd) {
+ case weekday::sunday:
+ return 0;
+ case weekday::monday:
+ return 1;
+ case weekday::tuesday:
+ return 2;
+ case weekday::wednesday:
+ return 3;
+ case weekday::thursday:
+ return 4;
+ case weekday::friday:
+ return 5;
+ case weekday::saturday:
+ return 6;
+ }
+ return 0; /*NOTREACHED*/
+}
+
+// Convert a tm_wday value (0-6, Sunday = 0) to a cctz::weekday.
+weekday FromTmWday(int tm_wday) {
+ switch (tm_wday) {
+ case 0:
+ return weekday::sunday;
+ case 1:
+ return weekday::monday;
+ case 2:
+ return weekday::tuesday;
+ case 3:
+ return weekday::wednesday;
+ case 4:
+ return weekday::thursday;
+ case 5:
+ return weekday::friday;
+ case 6:
+ return weekday::saturday;
+ }
+ return weekday::sunday; /*NOTREACHED*/
+}
+
std::tm ToTM(const time_zone::absolute_lookup& al) {
std::tm tm{};
tm.tm_sec = al.cs.second();
@@ -84,34 +126,19 @@ std::tm ToTM(const time_zone::absolute_lookup& al) {
tm.tm_year = static_cast<int>(al.cs.year() - 1900);
}
- switch (get_weekday(al.cs)) {
- case weekday::sunday:
- tm.tm_wday = 0;
- break;
- case weekday::monday:
- tm.tm_wday = 1;
- break;
- case weekday::tuesday:
- tm.tm_wday = 2;
- break;
- case weekday::wednesday:
- tm.tm_wday = 3;
- break;
- case weekday::thursday:
- tm.tm_wday = 4;
- break;
- case weekday::friday:
- tm.tm_wday = 5;
- break;
- case weekday::saturday:
- tm.tm_wday = 6;
- break;
- }
+ tm.tm_wday = ToTmWday(get_weekday(al.cs));
tm.tm_yday = get_yearday(al.cs) - 1;
tm.tm_isdst = al.is_dst ? 1 : 0;
return tm;
}
+// Returns the week of the year [0:53] given a civil day and the day on
+// which weeks are defined to start.
+int ToWeek(const civil_day& cd, weekday week_start) {
+ const civil_day d(cd.year() % 400, cd.month(), cd.day());
+ return static_cast<int>((d - prev_weekday(civil_year(d), week_start)) / 7);
+}
+
const char kDigits[] = "0123456789";
// Formats a 64-bit integer in the given field width. Note that it is up
@@ -355,7 +382,7 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
if (cur == end || (cur - percent) % 2 == 0) continue;
// Simple specifiers that we handle ourselves.
- if (strchr("YmdeHMSzZs%", *cur)) {
+ if (strchr("YmdeUuWwHMSzZs%", *cur)) {
if (cur - 1 != pending) {
FormatTM(&result, std::string(pending, cur - 1), tm);
}
@@ -376,6 +403,22 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
if (*cur == 'e' && *bp == '0') *bp = ' '; // for Windows
result.append(bp, static_cast<std::size_t>(ep - bp));
break;
+ case 'U':
+ bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::sunday));
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'u':
+ bp = Format64(ep, 0, tm.tm_wday ? tm.tm_wday : 7);
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'W':
+ bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::monday));
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'w':
+ bp = Format64(ep, 0, tm.tm_wday);
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
case 'H':
bp = Format02d(ep, al.cs.hour());
result.append(bp, static_cast<std::size_t>(ep - bp));
@@ -610,6 +653,17 @@ const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) {
return dp;
}
+// Sets year, tm_mon and tm_mday given the year, week_num, and tm_wday,
+// and the day on which weeks are defined to start.
+void FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
+ const civil_year y(*year % 400);
+ civil_day cd = prev_weekday(y, week_start); // week 0
+ cd = next_weekday(cd - 1, FromTmWday(tm->tm_wday)) + (week_num * 7);
+ *year += cd.year() - y.year();
+ tm->tm_mon = cd.month() - 1;
+ tm->tm_mday = cd.day();
+}
+
} // namespace
// Uses strptime(3) to parse the given input. Supports the same extended
@@ -659,6 +713,8 @@ bool parse(const std::string& format, const std::string& input,
const char* fmt = format.c_str(); // NUL terminated
bool twelve_hour = false;
bool afternoon = false;
+ int week_num = -1;
+ weekday week_start = weekday::sunday;
bool saw_percent_s = false;
std::int_fast64_t percent_s = 0;
@@ -697,10 +753,27 @@ bool parse(const std::string& format, const std::string& input,
case 'm':
data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
if (data != nullptr) tm.tm_mon -= 1;
+ week_num = -1;
continue;
case 'd':
case 'e':
data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
+ week_num = -1;
+ continue;
+ case 'U':
+ data = ParseInt(data, 0, 0, 53, &week_num);
+ week_start = weekday::sunday;
+ continue;
+ case 'W':
+ data = ParseInt(data, 0, 0, 53, &week_num);
+ week_start = weekday::monday;
+ continue;
+ case 'u':
+ data = ParseInt(data, 0, 1, 7, &tm.tm_wday);
+ if (data != nullptr) tm.tm_wday %= 7;
+ continue;
+ case 'w':
+ data = ParseInt(data, 0, 0, 6, &tm.tm_wday);
continue;
case 'H':
data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
@@ -891,6 +964,9 @@ bool parse(const std::string& format, const std::string& input,
year += 1900;
}
+ // Compute year, tm.tm_mon and tm.tm_mday if we parsed a week number.
+ if (week_num != -1) FromWeek(week_num, week_start, &year, &tm);
+
const int month = tm.tm_mon + 1;
civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);