Skip to content

Commit 928475e

Browse files
committed
Fix edge case in strftime %V (ISO 8601 week number)
strftime() now returns correct week number *51* instead of *50* for date 2018-12-17. Code is based on musl's ``strftime.c:week_num()``. Signed-off-by: Christian Heimes <[email protected]>
1 parent ed8acb3 commit 928475e

File tree

3 files changed

+38
-26
lines changed

3 files changed

+38
-26
lines changed

src/library.js

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -862,34 +862,28 @@ LibraryManager.library = {
862862
// or more days in the new year, then it is considered week 1.
863863
// Otherwise, it is the last week of the previous year, and the next week is week 1.
864864
// Both January 4th and the first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday]
865-
var janFourthThisYear = new Date(date.tm_year+1900, 0, 4);
866-
var janFourthNextYear = new Date(date.tm_year+1901, 0, 4);
867-
868-
var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
869-
var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
870-
871-
var endDate = __addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday);
872-
873-
if (compareByDay(endDate, firstWeekStartThisYear) < 0) {
874-
// if given date is before this years first week, then it belongs to the 53rd week of last year
875-
return '53';
865+
var val = Math.floor((date.tm_yday + 7 - (date.tm_wday + 6) % 7 ) / 7);
866+
// If 1 Jan is just 1-3 days past Monday, the previous week
867+
// is also in this year.
868+
if ((date.tm_wday + 371 - date.tm_yday - 2) % 7 <= 2) {
869+
val++;
876870
}
877-
878-
if (compareByDay(firstWeekStartNextYear, endDate) <= 0) {
879-
// if given date is after next years first week, then it belongs to the 01th week of next year
880-
return '01';
881-
}
882-
883-
// given date is in between CW 01..53 of this calendar year
884-
var daysDifference;
885-
if (firstWeekStartThisYear.getFullYear() < date.tm_year+1900) {
886-
// first CW of this year starts last year
887-
daysDifference = date.tm_yday+32-firstWeekStartThisYear.getDate()
888-
} else {
889-
// first CW of this year starts this year
890-
daysDifference = date.tm_yday+1-firstWeekStartThisYear.getDate();
871+
if (!val) {
872+
val = 52;
873+
// If 31 December of prev year a Thursday, or Friday of a
874+
// leap year, then the prev year has 53 weeks.
875+
var dec31 = (date.tm_wday + 7 - date.tm_yday - 1) % 7;
876+
if (dec31 == 4 || (dec31 == 5 && __isLeapYear(date.tm_year%400-1))) {
877+
val++;
878+
}
879+
} else if (val == 53) {
880+
// If 1 January is not a Thursday, and not a Wednesday of a
881+
// leap year, then this year has only 52 weeks.
882+
var jan1 = (date.tm_wday + 371 - date.tm_yday) % 7;
883+
if (jan1 != 4 && (jan1 != 3 || !__isLeapYear(date.tm_year)))
884+
val = 1;
891885
}
892-
return leadingNulls(Math.ceil(daysDifference/7), 2);
886+
return leadingNulls(val, 2);
893887
},
894888
'%w': function(date) {
895889
return date.tm_wday;

tests/core/test_strftime.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,21 @@ int main() {
287287
size = strftime(s, sizeof(s), "%Y-%m-%d %W %U", &tm);
288288
test(!cmp(s, "2013-01-07 01 01"), "strftime test #36a", s);
289289

290+
// strftime %V (ISO 8601 week number) edge cases
291+
time_t dec17 = 1481929200;
292+
gmtime_r(&dec17, &tm);
293+
size = strftime(s, sizeof(s), "%Y-%m-%d %G %V %w", &tm);
294+
test(!cmp(s, "2016-12-17 2016 50 06"), "strftime test #37", s);
295+
296+
dec17 = 1513465200;
297+
gmtime_r(&dec17, &tm);
298+
size = strftime(s, sizeof(s), "%Y-%m-%d %G %V %w", &tm);
299+
test(!cmp(s, "2017-12-17 2017 50 00"), "strftime test #37a", s);
300+
301+
dec17 = 1545001200;
302+
gmtime_r(&dec17, &tm);
303+
size = strftime(s, sizeof(s), "%Y-%m-%d %G %V %w", &tm);
304+
test(!cmp(s, "2018-12-17 2018 51 01"), "strftime test #37b", s);
290305

291306
return 0;
292307
}

tests/core/test_strftime.out

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,6 @@ strftime test #34: 1
6363
strftime test #35: 1
6464
strftime test #36: 1
6565
strftime test #36a: 1
66+
strftime test #37: 1
67+
strftime test #37a: 1
68+
strftime test #37b: 1

0 commit comments

Comments
 (0)