shithub: scc

Download patch

ref: 3a91086edd50be172bf1f2305967e145d3c4faf8
parent: 2e11e73feafef4fd29df8e3a46e767da3b9a1877
author: Naveen Narayanan <[email protected]>
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;