How to manually configure NodaTime IWeekYearRule correctly?

Viewed 143

I am wrapping NodaTime for use in our software, and to be future-proof I thought I'd set up IWeekYearRule according to Bcl DateTimeFormat, like this:

var culture = CultureInfo.CurrentCulture;
var weekRule = WeekYearRules.FromCalendarWeekRule(
    culture.DateTimeFormat.CalendarWeekRule,
    culture.DateTimeFormat.FirstDayOfWeek);

Here in Norway we're following the following settings:

CalendarWeekRule.FirstFourDayWeek
DayOfWeek.Monday

However, much to my surprise, when I checked the week number of the following two dates, kalender.no disagrees:

2018-12-31: week 53 of 2018 (kalender.no says week 1 [implied: of 2019])
2019-01-01: week 1 of 2019  (kalender.no agrees here)

However, if I use WeekYearRules.Iso, they both return "week 1 of 2019", which is the correct one.

I have a bunch of questions but let's focus on the most immediate one:

How can I write the code to "future-proof" this part of the library, so that when we start rolling out the software into more parts of the world, it will calculate week numbers correctly out of the box, according to the local culture?

Or is this just not possible, because the culture information doesn't contain this?

Here's a LINQPad example that demonstrates NodaTime behavior (sorry for not including a [mcve] to begin with):

void Main()
{
    "-------------- ISO --------------".Dump();
    Test(WeekYearRules.Iso);

    "-------------- BCL --------------".Dump();
    Test(WeekYearRules.FromCalendarWeekRule(CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday));
}

public static void Test(IWeekYearRule rule)
{
    var date = new LocalDate(2018, 12, 31);
    $"{date}, {rule.GetWeekOfWeekYear(date)} in {rule.GetWeekYear(date)}".Dump();

    date = new LocalDate(2019, 1, 1);
    $"{date}, {rule.GetWeekOfWeekYear(date)} in {rule.GetWeekYear(date)}".Dump();
}

Output:

-------------- ISO --------------
mandag 31. desember 2018, 1 in 2019
tirsdag 1. januar 2019, 1 in 2019
-------------- BCL --------------
mandag 31. desember 2018, 53 in 2018
tirsdag 1. januar 2019, 1 in 2019

(and just to be clear, the ISO output is the correct one for Norway)

This is NodaTime 2.4.4, Windows 10, .NET 4.7.2.


And here's a LINQPad example without using NodaTime:

void Main()
{
    var culture = CultureInfo.GetCultureInfo("nb-NO");

    var calendarWeekRule = culture.DateTimeFormat.CalendarWeekRule.Dump();
    var firstDayOfWeek = culture.DateTimeFormat.FirstDayOfWeek.Dump();

    var date = new DateTime(2018, 12, 31);
    $"{date.DayOfWeek} {date}, week {culture.Calendar.GetWeekOfYear(date, calendarWeekRule, firstDayOfWeek)}".Dump();

    date = new DateTime(2019, 1, 1);
    $"{date.DayOfWeek} {date}, week {culture.Calendar.GetWeekOfYear(date, calendarWeekRule, firstDayOfWeek)}".Dump();
}

Output:

FirstFourDayWeek
Monday
Monday 31.12.2018 00.00.00, week 53
Tuesday 01.01.2019 00.00.00, week 1

The Monday there is in the same week as week 1 of 2019, and is counted as week 1 in 2019 here in Norway, so the first of the two dates should really have been:

Monday 31.12.2018 00.00.00, week 1
0 Answers
Related