scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

commit 112057b0a1b3a504ac31a05b4a3e30bcdbde385e
parent c7111312b27a90c04e7487a3f97123f9f8145670
Author: Naveen Narayanan <zerous@simple-cc.org>
Date:   Sat, 29 Aug 2020 14:58:33 +0200

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.

Diffstat:
Msrc/libc/time/strftime.c | 47+++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/src/libc/time/strftime.c b/src/libc/time/strftime.c @@ -28,6 +28,7 @@ first(int day, int year) return 7 - ny + day; } + static int weeknum(struct tm* tm, int day) { @@ -44,6 +45,42 @@ weeknum(struct tm* tm, int day) 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 @@ strftime(char * restrict s, size_t siz, 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;