Quartz.NET - Shouldn't this unit test pass?

c#, dst, quartz.net, timezone, unit-testing

Solution

I figured out that this actually is a bug in Quartz.NET 2.0.1, but it has already been fixed in 2.1.0.

I checked the change-log on the site, which does not mention a related fix. The comment from Peter Ritchie encouraged me to take another look at the newer Quartz versions. When i looked through the commits in the repository i noticed there actually was a fix for this.

It has been fixed in revision 665:

Merge pull request #72 from amazing-andrew/master Time zone issues with CronExpression, calendars, CalendarIntervalTriggerImpl

The first official release that contains this fix is v2.1.0, which was tagged at revision 685.

The bug was located in `CronExpression.GetTimeAfter()` (which is called by `CronExpression.GetNextValidTimeAfter()`):

...
d = new DateTimeOffset(year, d.Month, d.Day, d.Hour, d.Minute, d.Second, d.Offset);

// apply the proper offset for this date (this wasn't there)
d = new DateTimeOffset(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second, this.TimeZone.GetUtcOffset(d.DateTime));
...

Problem

This question is related to this one, but is kept more general and can be treated independently. EDIT: Quartz version is v2.0.1 From my understanding, the following unit test should pass: ``` [Test] public void Test() { // run every first day of month at 14:00 hours CronExpression expression = new CronExpression("0 0 14 1 * ?"); // TimeZoneInfo.Local = {(UTC+01:00) Amsterdam, Berlin, Bern, Rom, Stockholm, Wien} if (!TimeZoneInfo.Local.SupportsDaylightSavingTime) { return; } // get "summertime" period for current timezone var daylightChange = TimeZone.CurrentTimeZone.GetDaylightChanges(2013); // -> daylightChange.Start {31.03.2013 02:00:00} System.DateTime // -> daylightChange.End {27.10.2013 03:00:00} System.DateTime // get one startpoint before and one after begin of summertime DateTimeOffset beforeSummertime = daylightChange.Start.ToUniversalTime().AddDays(-1); DateTimeOffset afterSummertime = daylightChange.Start.ToUniversalTime().AddDays(1); // -> beforeSummertime {30.03.2013 01:00:00 +00:00} System.DateTimeOffset // -> afterSummertime {01.04.2013 01:00:00 +00:00} System.DateTimeOffset DateTimeOffset? nextValidTimeFromBefore = expression.GetNextValidTimeAfter(beforeSummertime); DateTimeOffset? nextValidTimeFromAfter = expression.GetNextValidTimeAfter(afterSummertime); // nextValidTimeFromBefore {01.04.2013 13:00:00 +00:00} System.DateTimeOffset? // nextValidTimeFromAfter {01.04.2013 12:00:00 +00:00} System.DateTimeOffset? Assert.AreEqual(nextValidTimeFromBefore, nextValidTimeFromAfter); } ``` However (as you can see), the `nextValidTimeFromBefore` differs from `nextValidTimeFromAfter`. The result in `nextValidTimeFromAfter` is correct. The UTC 12:00 will result in 14:00 during summertime (which already started at that point). It shouldn't matter if the `GetNextValidTimeAfter()` parameter specifies a time inside or outside of the summertime period. Should the NextValidTimes be equal or is my approach flawed?

Original source