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

2020-02-29 01:56发布

问题:

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?

回答1:

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));
...