For sake of an example lets use the following cron expression: "0 0 14 1 * ?"
-> Fire on the 1st day of every month at 14:00 hours.
I used the Quartz CronScheduleBuilder to build the expession, but this is irrelevant.
My Local timezone is UTC+01:00 and the summertime (this year) begins on 31.03.2013 2:00, where the time is adjusted to 3:00.
When i schedule a new Job using the proposed trigger on lets say 20.02.2013, Quartz calculates the System.DateTimeOffset for the "NextFireTimeUtc" correctly to:
DateTime: 01.03.2013 13:00:00 (this is the UTC time, which is one hour behind the local timezone)
LocalDateTime: 01.03.2013 14:00:00
The job will correctly trigger on 14:00 hours as specified.
Now if i schedule the job on 20.03.2013, the "NextFireTimeUtc" results in:
DateTime: 01.04.2013 13:00:00 (this is the UTC time, which is now two hours behind the local timezone)
LocalDateTime: 01.04.2013 15:00:00
Notice, that the resulting NextFireTimeUtc now falls within the local summertime. As a result, the LocalDateTime was also "corrected" by an additional hour from the UTC. This results in the job running at 15:00 hours, which is not what i want.
What i (obviously) expected is that the "14" in the cron expression should always result in the trigger firing at 14:00, even during summertime.
There must be an easy way to deal with this phenomenon, i am probably just missing something conceptional. I am confused.
EDIT:
The problem seems to be, that Quartz calculates the first NextFireTimeUtc depending on the current timezone information. To test this, i scheduled two different cron triggers and called GetFireTimeAfter() on the trigger with an increasing offset to view the resulting fire times over the year.
Trigger 1: Fire on the 28th of every month at 14:00
GetFireTimeAfter now + 00 months: 28.03.2013 13:00:00 +00:00 <- this is correct
GetFireTimeAfter now + 01 months: 28.04.2013 12:00:00 +00:00
GetFireTimeAfter now + 02 months: 28.05.2013 12:00:00 +00:00
GetFireTimeAfter now + 03 months: 28.06.2013 12:00:00 +00:00
GetFireTimeAfter now + 04 months: 28.07.2013 12:00:00 +00:00
GetFireTimeAfter now + 05 months: 28.08.2013 12:00:00 +00:00
GetFireTimeAfter now + 06 months: 28.09.2013 12:00:00 +00:00
GetFireTimeAfter now + 07 months: 28.10.2013 13:00:00 +00:00 <- summertime already ended
GetFireTimeAfter now + 08 months: 28.11.2013 13:00:00 +00:00
The first fire time is correct, since it still falls into "wintertime". The times during "summertime" are off by an additional -1, resulting in the correct fire time after the local timezone adds +2.
Trigger 1: Fire on the first day of every month at 14:00
GetFireTimeAfter now + 00 months: 01.04.2013 13:00:00 +00:00 <- this is wrong?
GetFireTimeAfter now + 01 months: 01.05.2013 12:00:00 +00:00
GetFireTimeAfter now + 02 months: 01.06.2013 12:00:00 +00:00
GetFireTimeAfter now + 03 months: 01.07.2013 12:00:00 +00:00
GetFireTimeAfter now + 04 months: 01.08.2013 12:00:00 +00:00
GetFireTimeAfter now + 05 months: 01.09.2013 12:00:00 +00:00
GetFireTimeAfter now + 06 months: 01.10.2013 12:00:00 +00:00
GetFireTimeAfter now + 07 months: 01.11.2013 13:00:00 +00:00 <- summertime already ended
GetFireTimeAfter now + 08 months: 01.12.2013 13:00:00 +00:00
The first fire already falls within summertime, but its only offset by -1, resulting in a local trigger time of 15:00.
So the trigger is fine, except for the first trigger time, if its scheduled during wintertime and the first execution falls within summertime. How to handle this?
NextFireTimeUtcthen successively adding to that one value? - Peter Ritchietrigger.GetFireTimeAfter(DateTimeOffset.Now.AddMonths(i))where i is incrementing in a for loop. - Rev