Quartz-scheduler scheduling job every 2 weeks ignoring previous misfires - c#

I'm trying to schedule a job on a given day (user defined) on an interval of every 2 weeks and ignoring and previous misfires using Quartz-Scheduler.
For example:
If I set the start date to 7th Oct(Sunday) and today's date is 26th Oct, it should trigger on 4th Nov(Sunday), 18th Nov(Sunday)...
The only way I found to do this is using the WithCalendarIntervalSchedule extension with StartAt. The issue with this approach is that, if the start date is before today then all the misfires will be triggered when the trigger is being scheduled.
Cron expression and CronScheduleBuilder does not seem to allow this.
I cannot ignore misfires as i do not want triggers that failed to start on time for whatever reason to be ignored.
And i cannot force the start date to be after today.
Let me know if I'm missing anything, I've been looking for a solution to this for a couple of days now.

Turns out Quartz scheduler does not support schedule for every 2 weeks very well.
The trick to make it work is to set the start date to be the next DateTime that it should be triggered using the StartAt extension then use WithCalendarIntervalSchedule with WithIntervalInWeeks.

Related

How to handle when timezone goes backwards in the future

I am generating two sets of repeating events in seperate loop iterations but am having a conflict when comparing the generated results for conflicts. This seems to be when the times go backwards and I am unsure how to solve this?
The first repeat event will:
repeat everyday at 00:00 to 01:00 in "Europe/Stockholm" time
from 03/11/2015
looping until forever.
The second repeat event will:
repeat everyday at 01:00 to 02:00 in "Europe/Stockholm" time
from 03/11/2015
again looping forever.
To generate the events I am looping through everyday in the local time zone "Europe/Stockholm" using Nodatime like this:
String timeZone = "Europe/Stockholm";
for (ZonedDateTime date_Local = repeatSeriesStartDate_Local; date_Local <= LoopEndDate_Local; date_Local = new ZonedDateTime(Instant.FromDateTimeUtc(date_Local.ToDateTimeUtc().AddDays(1).ToUniversalTime()),timeZone))
My issue arises on October 29/30th 2016 When the clocks go backwards and the 2nd rule conflicts with the first.
http://www.timeanddate.com/time/change/sweden/stockholm?year=2016
The conflict times are as follows:
"2016-10-29T23:00:00Z" to "2016-10-30T01:00:00Z"
"2016-10-30T00:00:00Z" to "2016-10-30T01:00:00Z"
I am using an algorithm like this one to test for conflicts
https://stackoverflow.com/a/325964/884132
How should I handle these time shifting conflicts?
Though it would really help if you'll clarify the question, I'll make a few assumptions for now. I can edit the question later if necessary.
What you probably want to do is something like this:
for (LocalDate date = startDate; date <= endDate; date = date.PlusDays(1))
{
ZonedDateTime zdt = date.At(eventTime).InZone(tz, SchedulingResolver);
Console.WriteLine(zdt); // or whatever you want to do from here
}
The SchedulingResolver implementation is here, and is only necessary if you are using the 1.x version of Noda Time. If you are using 2.x, then you can just use InZoneLeniently(tz) instead, as the behavior of the lenient resolver in 2.x has changed to match (see "lenient resolver changes" in the 2.x migration guide).
The key points are:
ZonedDateTime is often best used as an intermediary type.
You have daily events that are based on the local day, so LocalDate is more appropriate.
If you had events based on a fixed 24-hour rotation (aka, the UTC day), then Instant would be more appropriate.
Resolvers are used to map ambiguous or invalid LocalDateTime values back to specific moments in time. The resolver I recommend for scheduling purposes is the one that:
Advances by the DST bias (usually 1 hour) when the clocks go forward (spring)
Picks the first instance when the clocks go back (fall)
Though as Jon mentioned - your needs may vary, and really we can't answer what you should do. There are indeed business that need different resolver rules than the ones I am recommending.

NodaTime addition when DST happens

Let's say I have the date 2014-11-2T00:00:00-0600 then I want to add 1 day, and have 2014-11-3T00:00:00-0700 .
Now if I do :
crtDay.Plus(Duration.FromStandardDays(1));
crtDay is a ZonedDateTime object
I end up with : 2014-11-2T23:00:00-0700 .
How do I move to the next day? (I could add hours until I moved to the next day, but it feels like there has to be a better way.)
Thanks.
(I'll assume from the values you gave that you are working in the US Mountain time zone.)
A "standard day" is 24 hours. However, on the day you mentioned, there are 25 hours in the calendar day, because the hour from 01:00 to 02:00 is repeated for the daylight saving time fall-back transition. Thus, you end up on the same day if you only add 24 hours.
In Noda Time, the ZonedDateTime structure is meant to represent a specific moment in time, with respect to a time zone. Thus, you can only move by linear instantaneous time, using Duration.
To move by calendar time, you'll have to take it's LocalDateTime and add a Period to it. If desired, you can then create a new ZonedDateTime from the result.
ZonedDateTime nextDay = zdt.LocalDateTime.PlusDays(1).InZoneLeniently(zdt.Zone);
Here I use InZoneLeniently for convenience. However, you should understand the behavior of that particular resolver. A different resolver (or a custom one) might be more appropriate, depending on your needs.
Say for example that you were starting at 1:30 on that day instead. The lenient resolver will assume you wanted to choose the latter of the two occurrences. Essentially you would be adding 25 hours even though 24 hours would still yield the same clock time. Perhaps your users might expect you to land on the first occurrence.
Also consider the spring-forward transition, where if you started at 2:30 then you'd land on date/time that doesn't exist. The lenient resolver will advance to the next valid clock time for the time zone - which might be acceptable, but it would have a different clock time of 2:00. Your users might expect you'd advance by a whole hour instead of just the next valid clock time.
The built-in resolvers are being reconsidered for Noda Time v2. See issue 295, and this alternate implementation.

Optimization With Dates and Events

This is a bit of a tricky problem to explain but I will try my best.
I have a calendar of events. In these there are non-working days. When any part of an event lands in on on a non-working day, its days are extended until it reaches a working day.
See here:
I have an orange 1 day event.
When it is dragged to the non-working day, it extends:
This works great and works fine. Here is the problem. I only show 2 weeks of the calendar at a time. Therefore, first, I fetch the visible events that start, end or fall in the range. Then, I fetch the nonworking days for the range and dynamically add the non-working days to its length.
Here is where the problem is:
Say there is an event that starts Jan 28th and ends Jan 29th. This means it will not get fetched. But because of Non-Working Days, it would end up on Feb 6th lets say. Well because I did not fetch it in my first step, I will not see it from feb 4 to 15. That is essentially my problem.
The naive solution would be to grab all events and all non-working days and then pre-calculate all end days dynamically, then filter the visible ones there. But that will get very expensive very fast.
But I cannot think of any other solution. It needs to be dynamic. Does anyone have any creative ideas on how I could solve this in a non O(N^2) manner. Just a general outline of a solution would be very helpful. I do not mind modifying the db if needed.
Currently a schedule has a start date and Hours. I dynamically calculate an event's length because different employees work different hours which is why I cannot have static end dates.

datetime checking for specific time

I have a windows service and I would like to insert a timer. How can I check if the present time is 9:00 AM ?
I would like my service to check this every day. Thank you a lot
My try:
Datetime dt=Datetime.parse("09:00:00 everyday");
if(datetime.now -dt ==0)
{
//fire event
}
Thats kinda sily of me though.
You need to make a timer and sets its interval to the timespan between now and tomorrow 9:00 AM. Next time the timer tick, set the interval again in the same way.
You should use this Timer class:
http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx
Please use DateTime.UtcNow.Hour to check current hour
By using UtcNow you will gets a DateTime object that is set to the current date and time on the computer, expressed as the Coordinated Universal Time (UTC).
var now = DateTime.Now;
var today = now.Date;
var nineAm = today.AddHours(9);
TimeSpan ts = nineAm - now;
var timeInMillisecondsTill9Am = ts.Milliseconds;
If(timeInMillisecondsTill9Am==0)
{
//your code goes here
}
Since you don't know when someone may shutdown or reboot your computer or service then you need to make sure that you use a method robust enough to handle these kinds of interruptions.
I suggest that when your service checks every 5 minutes or so if the time is after 9am and if the last run date is yesterday. If so, you update the last run date to day (perhaps in a simple text file) and then run the "9:00am" task. In this way your task only runs once per day, fairly close to 9am, and is robust against reboots.
You'll need to use a standard .NET timer to trigger the checks - and if you're clever enough you can make it fire a few seconds after 9am.
Let me know if that's a good solution.

DateTime issue in vb.net regarding automatic scheduling

I have a program that checks for the date and minute part of my job object. If these match then it triggers a particular job.
If jb.ScheduledStartTime.Value.ToString("MM/dd/yyyy mm") =
Now().ToString("MM/dd/yyyy mm") Then
'Do some work here.
End If
Issue:
If I schedule different jobs during the day at different time interval then they just work fine. I mean they are triggered and in the above code they enter the loop when it matches the current format.
However, it doesn't work when the date changes at 12:00. Even though I have scheduled start time set to trigger at 9:00 AM in the morning it enters the loop exactly at 12:00 AM which is invalidating my logic leaving me confused.
Why is this happening? Is my date and minute checking logic incorrect here? Is there any better way of doing this?
I don't check for exact seconds here I just check for the minute part.
Are you checking for a change in the day etc? Is your schedulestarttime getting changed correctly after it's been triggered.
BTW don't compare times as strings. It's painful and you will get hurt. Use TimeSpan you can then get how long things were.
If datetime.now > jb.ScheduledStartTime then
'Do Some work.
end if
If you need smaller checks
dim myDateCheck as Datetime = datetime.now
myDateCheck = myDateCheck.AddSeconds(-myDateCheck.Second)
if myDateCheck > jb.ScheduledStartTime then
'Do Some work
end if
Also check the hour part (HH) of the dateteime, your format should be "MM/dd/yyyy HH:mm"
try this
If jb.ScheduledStartTime.Value.ToString("MM/dd/yyyy HH:mm") =
Now().ToString("MM/dd/yyyy HH:mm") Then
'Do some work here.
End If

Categories

Resources