Possible to change CronTrigger DST behavior?

601 views
Skip to first unread message

Matt Johnson

unread,
Nov 18, 2015, 11:53:42 PM11/18/15
to Quartz.NET
Hello,

In both the FAQ and Best Practices docs on the website, it explains the CronTrigger's behavior for daylight saving time is to 1) skip occurrences that are in the spring-forward transition gap, and 2) run for both daylight and standard occurrences when in the overlap created by the fall-back transition.

What it does say is how to control this behavior.  Is it possible?  I work a lot with date/time issues, contributing to many projects such as Noda Time, moment.js, and answering questions on Stack Overflow.  I often recommend Quartz, but was surprised that it doesn't seem to address this pain point.

In general, while the rules should indeed be configurable by the implementer, in most cases I find that the desired behavior is to 1) advance by the DST bias when time is skipped, and 2) choose the first (daylight) occurrence when time is repeated.  In other words, for the US, a 2:30 occurrence runs at 3:30 on the spring-forward day, and a 1:30 occurrence runs at 1:30 daylight time on the fall-back day.

How would I configure CronTrigger for this behavior?  Or do I have to write a custom trigger of some sort?

Sorry if this has been asked before.  I am not super familiar with Quartz yet.

-Matt

Marko Lahma

unread,
Nov 19, 2015, 2:01:44 PM11/19/15
to quar...@googlegroups.com
Hi,

Thanks for you interest on the matter. Just to shed some light on the
implementation and the underlying cause(s) why things operate like
this...

Main thing to consider is that Quartz calculates next fire time based
on some "fixed time" (last fire time) and keeps it persisted (memory
or DB) and scans for triggers to fire based on that persisted next
time.

So when clock jumps backwards the next fire time could occur again (or
a misfire when jumping forward) and next fire time(s) are calculated
again based on the clock's current time when trigger fires. And yes, I
hate the whole concept of DST.

So there's no easy remedy to determining whether trigger should just
run again, skip running etc when there's no persisted job history
available to help (and probably would not be such an easy task
anyway).

Some sorcery could be done when determining the next fire time and if
it's in the time window of DST adjust to next possible time that is
not part of DST. But out of the box, there's nothing but the advice to
keep this in mind, avoid scheduling the danger zone, be grateful that
it's only twice a year and hope that world gets rid of this DST
nonsense :)

But if you're keen to try things out, you might want to override
GetNextFireTimeUtc and check what do with the determined time when it
hits DST zone.

-Marko


On 11/19/15, Matt Johnson <mj1...@hotmail.com> wrote:
> Hello,
>
> In both the FAQ and Best Practices docs on the website, it explains the
> CronTrigger's behavior for daylight saving time is to 1) skip occurrences
> that are in the spring-forward transition gap, and 2) run for both daylight
>
> and standard occurrences when in the overlap created by the fall-back
> transition.
>
> What it does say is how to control this behavior. Is it possible? I work
> a lot with date/time issues, contributing to many projects such as Noda
> Time, moment.js, and answering questions on Stack Overflow. I often
> recommend Quartz, but was surprised that it doesn't seem to address this
> pain point.
>
> In general, while the rules should indeed be configurable by the
> implementer, in most cases I find that the desired behavior is to 1)
> advance by the DST bias when time is skipped, and 2) choose the first
> (daylight) occurrence when time is repeated. In other words, for the US, a
>
> 2:30 occurrence runs at 3:30 on the spring-forward day, and a 1:30
> occurrence runs at 1:30 *daylight *time on the fall-back day.
>
> How would I configure CronTrigger for this behavior? Or do I have to write
>
> a custom trigger of some sort?
>
> Sorry if this has been asked before. I am not super familiar with Quartz
> yet.
>
> -Matt
>
> --
> You received this message because you are subscribed to the Google Groups
> "Quartz.NET" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to quartznet+...@googlegroups.com.
> To post to this group, send email to quar...@googlegroups.com.
> Visit this group at http://groups.google.com/group/quartznet.
> For more options, visit https://groups.google.com/d/optout.
>

Matt Johnson

unread,
Nov 20, 2015, 11:58:33 AM11/20/15
to Quartz.NET
From your description, it sounds like there are routines to calculate the next UTC run time.  That is where I would expect it to handle this.

Since the trigger is defined in terms of civil time + time zone, then it sounds doable.  It's not necessary to have access to job history, as one can deterministically tell which instance of a repeated civil time is which, based on its time zone and corresponding UTC time and/or offset.  I'll dig into the code and let you know what I come up with.

Thanks,
Matt

Matt Johnson

unread,
Nov 20, 2015, 12:07:12 PM11/20/15
to Quartz.NET
Also - while I agree that DST is an abomination, it's the unfortunate reality of the world.  The idea of just avoiding scheduling during the transition window is not realistic, IMHO.  Consider that some time zones have transitions right at the stroke of midnight, and many people run daily reports and other events during the midnight hour.  If the generalized solution I described is possible within Quartz, then it should be offered as an option.  I'll work on it.

This part of the puzzle is relatively straightforward actually.  The bigger challenge is being aware of time zone updates, and knowing what to reschedule when things change.  Does Quartz persist the calculated next UTC run times when the system reboots? Or does it recalculate them on startup?

Thanks,
Matt

Matt Johnson

unread,
Dec 23, 2015, 3:00:06 PM12/23/15
to Quartz.NET
Marko - Please see https://github.com/quartznet/quartznet/pull/317

Note that the current implementation is actually NOT what is described in the docs.

Regards,
Matt
Reply all
Reply to author
Forward
0 new messages