ref: 3a91086edd50be172bf1f2305967e145d3c4faf8
parent: 2e11e73feafef4fd29df8e3a46e767da3b9a1877
author: Naveen Narayanan <zerous@simple-cc.org>
date: Sat Aug 29 10:58:33 EDT 2020
libc: Implement %g, %G, and %V (strftime) Conversion specifiers such as %g, %G, and %V get replaced by appropriate values according to the ISO 8601 week-based year. In this system, weeks begin on a Monday and week 1 of the year is the week that includes January 4th, which is also the week that includes the first Thursday of the year, and is also the first week that contains at least four days in the year. If the first Monday of January is the 2nd, 3rd, or 4th, the preceding days are part of the last week of the preceding year; thus, for Saturday 2nd January 1999, %G is replaced by 1998 and %V is replaced by 53. If December 29th, 30th, or 31st is a Monday, it and any following days are part of week 1 of the following year. Thus, for Tuesday 30th December 1997, %G is replaced by 1998 and %V is replaced by 01.
--- a/src/libc/time/strftime.c
+++ b/src/libc/time/strftime.c
@@ -28,6 +28,7 @@
return 7 - ny + day;
}
+
static int
weeknum(struct tm* tm, int day)
{
@@ -44,6 +45,42 @@
return val;
}
+static int
+isoyear(struct tm* tm)
+{
+ int monday;
+
+ if (tm->tm_yday < 7) {
+ monday = first(THU, tm->tm_year) - 3;
+ if (tm->tm_yday < monday)
+ return tm->tm_year - 1;
+ } else if (tm->tm_yday > 357) {
+ monday = first(THU, tm->tm_year + 1) - 3;
+ if (tm->tm_mday >= (31 + monday))
+ return tm->tm_year + 1;
+ }
+ return tm->tm_year;
+}
+
+static int
+isoweek(struct tm* tm)
+{
+ int year, monday, yday, val;
+
+ year = isoyear(tm);
+ monday = first(THU, year) - 3;
+ yday = tm->tm_yday;
+ if (year > tm->tm_year) {
+ yday = tm->tm_mday - 31 + monday;
+ } else if (year < tm->tm_year) {
+ yday = _daysyear(year) + yday;
+ }
+ val = yday - monday;
+ val /= 7;
+ val++;
+ return val;
+}
+
static size_t
sval(char *s, size_t siz, char **strs, int abrev, int idx, int max)
{
@@ -202,10 +239,16 @@
val = tm->tm_mday;
goto number;
case 'V':
+ val = isoweek(tm);
+ goto number;
case 'g':
+ val = isoyear(tm);
+ goto number;
case 'G':
- inc = 0;
- break;
+ val = isoyear(tm);
+ val += 1900;
+ width = 4;
+ goto number;
case 'C':
val = tm->tm_year / 100;
goto number;