nodatime / nodatime

A better date and time API for .NET

Home Page:https://nodatime.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Inconsistency between generated version and nzd version?

rogerhival opened this issue · comments

Hi, currently working on timezone updates.
We are having problems with America/Santiago daylight updates.

This url https://nodatime.org/tzvalidate/generate?version=2022c shows start time for 2022 as 11th Sept (apparently correct).
When reading the file from https://nodatime.org/tzdb/tzdb2022c.nzd, the result is start date 04th Sept (incorrect).

According to TimeAndDate website, they have postponed the start date:
https://www.timeanddate.com/news/time/chile-dst-delay-2022.html

Code debug for context (reading from https://nodatime.org/tzdb/tzdb2022c.nzd) :
image

What is the code reading the nzd file? It would really help of you'd provide a complete example I can run for myself. The type and method names there don't look familiar - if you've written your own code to read the nzd file, that's probably where the problem is, given that tzvalidate generation is using NodaTime to read the nzd file.

We do nothing special:

image

Using the api to get the transitions(which is what I'm showing in the original post).

Editing to include the class in case you ask:
image

It would be really useful if you could post code as text rather than as screenshots. It makes it much easier for me to run the same code.

Sure, no worries, I'm not used to post stuff on github, sorry.

This is where we read the file:

public TimezoneSetResult ParseTimezoneDatabase()
{
	IDateTimeZoneProvider provider;
	var result = new List<RefTimeZoneSet>(); //our own class for time zones
	using (var stream = File.OpenRead("downloaded file https://nodatime.org/tzdb/tzdb2022c.nzd"))
	{
		var source = TzdbDateTimeZoneSource.FromStream(stream);
		provider = new DateTimeZoneCache(source);
		foreach (var zone in DateTimeZoneProviders.Tzdb.GetAllZones())
		{
			result.Add(ParseZone(zone));
		}
	}
	return new TimezoneSetResult(result.ToArray());
}

Then the ParseZone (just the piece that returns the record incorrectly):

protected RefTimeZoneSet ParseZone(DateTimeZone zone)
{
	var transitions = GetDaylightSavingTransitions(zone, DateTime.UtcNow.Year);
}

Then the extract method:

protected List<ZoneIntervalWtg> GetDaylightSavingTransitions(DateTimeZone timeZone, int year)
{
	var yearStart = new LocalDateTime(2000, 1, 1, 0, 0).InZoneLeniently(timeZone).ToInstant();
	var yearEnd = new LocalDateTime(year + 100, 1, 1, 0, 0).InZoneLeniently(timeZone).ToInstant();
	var result = new List<ZoneIntervalWtg>();
	foreach (var interval in timeZone.GetZoneIntervals(yearStart, yearEnd))
	{
		result.Add(new ZoneIntervalWtg(interval));
	}
	return result;
}

Let me know if you need anything else

That's still code I can't run - I've no idea what ZoneIntervalWtg is, for example. Here's the sort of code I would prefer to see - this is a complete console app in .NET 6, showing the transitions in America/Santiago from https://nodatime.org/tzdb/tzdb2022c.nzd (again, downloaded just for simplicity).

using NodaTime;
using NodaTime.Text;
using NodaTime.TimeZones;

using var stream = File.OpenRead("tzdb2022c.nzd");
var source = TzdbDateTimeZoneSource.FromStream(stream);
Console.WriteLine(source.VersionId);
var zone = source.ForId("America/Santiago");
var start = Instant.FromUtc(2020, 1, 1, 0, 0);
var end = Instant.FromUtc(2024, 1, 1, 0, 0);
var zoneIntervals = zone.GetZoneIntervals(start, end);
foreach (var zoneInterval in zoneIntervals)
{
    Console.WriteLine(LocalDateTimePattern.GeneralIso.Format(zoneInterval.IsoLocalStart));
}

Output:

TZDB: 2022c (mapping: $Revision$)
2019-09-08T01:00:00
2020-04-04T23:00:00
2020-09-06T01:00:00
2021-04-03T23:00:00
2021-09-05T01:00:00
2022-04-02T23:00:00
2022-09-11T01:00:00
2023-04-01T23:00:00
2023-09-03T01:00:00

Note that that shows September 11th, as you'd expected. Please run that code for yourself with the file you've downloaded. If you get the same output, then presumably the problem is somewhere in the code you haven't shown. If you get different output, then perhaps you've downloaded the wrong file accidentally?

Found the problem, we are using DateTimeZoneProviders.Tzdb.GetAllZones() and our dll is not the latest, so we are not considering the TzdbDateTimeZoneSource to get the zones.
I updated the dll and it worked.

Thanks for your help

Rather than updating the DLL, I'd suggest that if you're trying to load from an NZD file, you just do that consistently. You just need var provider = new DateTimeZoneCache(source); and then you can use provider.GetAllZones() etc.