I'm trying to replicate some scheduling functionality in Google Calendar in C# using the RFC5545 recurrence rule.
There are two options for scheduling monthly with Google calendar, either by every Nth day month, ie: Every 10th day of the month every 1 months, this will obviously occur regardless of the week day.
My recurrence rule for this is: FREQ=MONTHLY;BYMONTHDAY=10
The other option is to repeat the event on every Nth weekday, ie: "Every second Sunday every one months, this is the one I'm having trouble writing the rule for.
What should my rule be for the second rule? I've tried FREQ=MONTHLY;BYDAY=SU, but I'm unsure how/which parameters to use to specify to only do this every 2nd Sunday of the month.
I'm using the DDay iCal C# library to generate my recurrence rule, but I'm happy to just be shown what the rule string should look like to achieve the desired behavior.
I'm using the RFC 5545 recurrence rule.
You are nearly there. What you need is to set the index for the day, RFC5545 says:
Each BYDAY value can also be preceded by a positive (+n) or
negative (-n) integer. If present, this indicates the nth
occurrence of a specific day within the MONTHLY or YEARLY "RRULE".
for which RFC5545 later gives an example
Monthly on the first Friday for 10 occurrences:
DTSTART;TZID=America/New_York:19970905T090000
RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
so for you the rule has to be:
RRULE:FREQ=MONTHLY;BYDAY=2SU
I'm coding a scheduling app and I'm curious how to handle the following marginal situation concerning the Daylight Saving Time (DST) change:
Say, we're in the time zone where the DST:
Starts on 2014-Mar-9 at 2:00:00 AM (clock is adjusted forward)
Ends on 2014-Nov-2 at 2:00:00 AM (clock is adjusted backward)
Suppose, an end-user scheduled my app for 2014-Nov-2, 2:00:00 AM.
Let's assume that the local date/time now is 2014-Nov-2, 1:59:99 AM.
When should my app fire the schedule -- in 1 second, or in 1 hour and 1 second?
Is there a standard that defines how to deal with this situation?
According to wikipedia the rules for daylight saving time are:
...in spring the clock jumps forward from the last moment of 01:59
standard time to 03:00 DST and that day has 23 hours, whereas in
autumn the clock jumps backward from the last moment of 01:59 DST to
01:00 standard time, repeating that hour, and that day has 25
hours.[37] A digital display of local time does not read 02:00 exactly
at the shift to summertime, but instead jumps from 01:59:59.9 forward
to 03:00:00.0.
So while the time and date is different around the world the rules are similar(ignoring Australia's Lord Howe Island which uses a half-hour shift). The hour that jumps backwards or forwards is not touched but the hour that is jumped to.
So in my opinion you should trigger the schedule in one hour and one second.
If you would trigger it in one second and the user wants to stop the schedule at 3 o'clock it would run for two hours instead of one which appears to be incorrect (2-3 = 1 hour).
I agree about all of the comments that "what you should do" is highly dependent on what your users expect, but I will give my opinion anyway.
If you are scheduling a single event, you should be able to test the date and time the user provided to see if it's either invalid (in the spring DST transition), or ambiguous (in the fall DST transition). In the invalid case, prompt something like "sorry, that time is invalid". In the ambiguous case, prompt something like "did you mean 1:30 PDT (UTC-7) or 1:30 PST (UTC-8)?" and handle the selection accordingly.
But I'll approach your question from the use case of a recurring event, such as a daily alarm clock that fires every day at the same time. What would I expect as the user of an alarm clock?
If I schedule a daily time at 2:00 AM, but in the spring transition the clock goes from 1:59:59 to 3:00:00, I'd expect the alarm to go off right at 3:00:00. I certainly wouldn't want it to go off at 4:00:00 - that would be an extra hour. I also wouldn't want the alarm to not fire at all just because 2:00 didn't technically occur.
If I schedule a daily time at 1:00 AM, but in the fall transition the clock goes from 1:59:59 back to 1:00:00 - as a user of this alarm, I would expect it to go off on the first occurrence (the daylight time) only. Occurring twice would just be annoying.
But here we see how this illustrates needing to know your users expectations. What if I could tell my alarm clock to let me have that extra hour back? "Please Mr. Alarm Clock, I'd like to use my extra DST hour to sleep in late. Wake me up at the second occurrence of 1:00." - Now I haven't personally seen any alarm clocks that work this way, but I think you get my point.
Now maybe you're not working with alarm clocks. Maybe this is a timed wire-transfer or some other time-sensitive item. You should work through the expected logic and see what makes sense for you.
Be aware that DST rules vary drastically by time zone. The world does not do DST all at the same time. Much of it doesn't do it at all.
For additional clarity on DST behavior, see the charts in the DST tag wiki.
I am working on an application that needs to set rules for periods of time. The company has different branches, each branch can set its own rules (i.e a branch starts work at 8.30 am, ends work at 17.30 pm, with 30 minutes pause for lunch; another branch start at 9.00, ends at 19.00 with 1 hour pause...)
So I need to define a class (let's call it WorkingDayDefinition for the moment) where start and end are not actually a DateTime, because they are not referred to any specific day in particular.
At the moment the only option I see in C# is using Timespan for setting a duration from the beginning of the day, so that 8.30 pm would be TimeSpan(8,30,0) to be added to the Day part of whichever day.
Is this a best practice in C#?
I searched for third parties libraries that could help me, but so far my best bet is this one:
http://www.codeproject.com/Articles/168662/Time-Period-Library-for-NET
that is not strictly what I need
You could use Noda Time. It provides a LocalTime (see here):
LocalTime is an immutable struct representing a time of day, with no reference to a particular calendar, time zone or date.
For 8.30 you would do something like:
LocalTime openingAt = new LocalTime(8, 30);
To me TimeSpam seems very suitable for what you want. It holds an interval of time, sometimes between two events, but in your case between the start of the day and the time you start/finish work. There is no reason I can think of not to use it just because the name might suggest this wasn't the original intention of the class. Plus it already integrates well with DateTimes for any time calculations you need to do later on down the road.
I've got a C# class I'm working with representing a profile that includes some scheduling information indicating how many updates during the day, and which days to update with boolean values for each day of the week. I've seen some posts here and on other sites to find the next instance of a given weekday, etc. but not something where which days one is looking for can vary.
For example, I might be given an object with Monday, Wednesday, and Thursday as true. What's the best way to find the next instance of the next true day of the week?
I can think of some long and drawn out ways to find the next "true" day of the week, but is there something cleaner built in that I'm unfamiliar with that would do the trick? I'd prefer not to use any third party libraries, as that requires lots of special approval from information assurance folks.
Given that it's hardly going to take a long time to loop, that's going to be the simplest approach:
DateTime nextDay = currentDay.AddDays(1);
while (!profile.IsActive(nextDay.DayOfWeek))
{
nextDay = nextDay.AddDays(1);
}
(That's assuming you've already validated that the profile is active on at least one day... otherwise it'll loop forever.)
I am trying to develop a scheduler- and calendar-dependent event application in C#, for which a crucial requirement is to represent recurring events in the database.
What is the best way to represent recurring events in a database?
More Details:
While creating the event I am also sending invites to the certain users and the invitees should be allowed to login to the meeting only during the specified window(meeting duration) or may be decline the login when the invitee attempts to login say, 5 minutes before the scheduled start of the meeting.
The sysjobs, sysjobsschedule and sysschedules tables in SQL Server does a pretty good job of this. I wouldn't reinvent the wheel, I'd just copy their design.
Here are some of the important fields from sysschedules
freq_type
How frequently a job runs for this schedule.
1 = One time only
4 = Daily
8 = Weekly
16 = Monthly
32 = Monthly, relative to freq_interval
64 = Runs when the SQL Server Agent service starts
128 = Runs when the computer is idle
freq_interval
Days that the job is executed. Depends on the value of freq_type. The default value is 0, which indicates that freq_interval is unused.
Value of freq_type Effect on freq_interval
1 (once) freq_interval is unused (0)
4 (daily) Every freq_interval days
8 (weekly) freq_interval is one or more of the following: 1 = Sunday 2 = Monday 4 = Tuesday 8 = Wednesday 16 = Thursday 32 = Friday 64 = Saturday
16 (monthly) On the freq_interval day of the month
32 (monthly, relative) freq_interval is one of the following: 1 = Sunday 2 = Monday 3 = Tuesday 4 = Wednesday 5 = Thursday 6 = Friday 7 = Saturday 8 = Day 9 = Weekday 10 = Weekend day
64 (starts when SQL Server Agent service starts) freq_interval is unused (0)
128 (runs when computer is idle) freq_interval is unused (0)
freq_subday_type
Units for the freq_subday_interval. Can be one of the following values:
Value Description (unit)
1 At the specified time
2 Seconds
4 Minutes
8 Hours
freq_subday_interval
Number of freq_subday_type periods to occur between each execution of the job.
freq_relative_interval
When freq_interval occurs in each month, if freq_interval is 32 (monthly relative). Can be one of the following values:
0 = freq_relative_interval is unused
1 = First
2 = Second
4 = Third
8 = Fourth
16 = Last
freq_recurrence_factor
Number of weeks or months between the scheduled execution of a job. freq_recurrence_factor is used only if freq_type is 8, 16, or 32. If this column contains 0, freq_recurrence_factor is unused.
Well, to store the recurrence rule itself, you could use a cut down version of RFC 5545 (and I really suggest you cut it down heavily). Aside from anything else, that will make it easy to export into other applications should you wish to.
After you've made that decision, for the database side you need to work out whether you want to store each occurrence of the event, or just one record for the repeated event, expanding it as and when you need to. Obviously it's considerably easier to query the database when you've already got everything expanded - but it makes it trickier to maintain.
Unless you fancy writing some pretty complex SQL which may be hard to test (and you'll want a lot of unit tests for all kinds of corner cases) I would suggest that you make the database itself relatively "dumb" and write most of the business logic in a language like Java or C# - either of which may be embeddable within stored procedures depending on your database, of course.
Another thing you need to ask yourself is whether you need to cope with exceptions to events - one event in a series changing time/location etc.
I have some experience with calendaring (I've spent most of the last year working on the calendar bit of Google Sync via ActiveSync) and I should warn you that things get complicated really quickly. Anything you can deem "out of scope" is a blessing. In particular, do you need to work in multiple time zones?
Oh, and finally - be very, very careful when you're doing actual arithmetic with calendar operations. If you're going to use Java, please use Joda Time rather than the built-in Calendar/Date classes. They'll help you a lot.
The accepted answer here is too convoluted. For example, if an event occurs every 5 days, the 5 is stored in freq_interval, but if it occurs every 5 weeks, the 5 is stored in freq_recurrence. The biggest problem is that freq_interval means three different things depending on the value of freq_type (number of days between occurrences for daily recurrence, day of the month for monthly recurrence, or days of the week for weekly or monthly-relative). Also, the 1,2,4,8... type sequence is used when it is unnecessary and less than helpful. For example, freq_relative_interval can only be "one of" the possible values. This lines up with a drop-down box or radio button type input, not a checkbox type input where multiple choices can be selected. For coding, and for human readability, this sequence gets in the way and just using 1,2,3,4... is simpler, more efficient, more appropriate. Finally, most calendar applications don't need subday intervals (events occurring multiple times in a day - every so many seconds, minutes, or hours).
But, having said this, that answer did help me refine my thoughts on how I am doing this. After mix and matching it with other articles and going from what I see in the Outlook calendar interface and a few other sources, I come up with this:
recurs
0=no recurrence
1=daily
2=weekly
3=monthly
recurs_interval
this is how many of the periods between recurrences. If the event recurs every 5 days, this will have a 5 and recurs will have 1. If the event recurs every 2 weeks, this will have a 2 and recurs will have a 2.
recurs_day
If the user selected monthly type recurrence, on a given day of the month (ex: 10th or the 14th). This has that date. The value is 0 if the user did not select monthly or specific day of month recurrence. The value is 1 to 31 otherwise.
recurs_ordinal
if the user selected a monthly type recurrence, but an ordinal type of day (ex: first monday, second thursday, last friday). This will have that ordinal number. The value is 0 if the user did not select this type of recurrence.
1=first
2=second
3=third
4=fourth
5=last
recurs_weekdays
for weekly and monthly-ordinal recurrence this stores the weekdays where the recurrence happens.
1=Sunday
2=Monday
4=Tuesday
8=Wednesday
16=Thursday
32=Friday
64=Saturday
So, examples:
So, every 4 weeks on Saturday and Sunday would be
recurs = 2 ==> weekly recurrence
recurs_interval = 4 ==> every 4 weeks
recurs_weekdays = 65 ==> (Saturday=64 + Sunday=1)
recurs_day and recurs_ordinal = 0 ==> not used
Similarly, Every 6 months on the first Friday of the month would be
recurs = 3 ==> monthly recurrence
recurs_interval = 6 ==> every 6 months
recurs_ordinal = 1 ==> on the first occurrence
recurs_weekdays = 32 ==> of Friday
None of this business of having a field that means three entirely different things depending on the value of another field.
On the user interface side of things, I let the user specify a date, start time, end time. They can then specify if they want a type of recurrence other than none. If so, the app expands the relevant section of the web-page to give the user the options required for the stuff above, looking a lot like the Outlook options, except there is no "every weekday" under daily recurrence (that is redundant with weekly recurrence on every mon-fri), and there is no yearly recurrence. If there is recurrence then I also require the user to specify an end-date that is within one year of today (the users want it that way, and it simplifies my code) - I don't do unending recurrence or "end after ## occurrences."
I store these fields with the user selections in my event table, and expand that out in a schedule table which has all occurrences. This facilitates collision detection (I am actually doing a facility reservation application) and editing of individual occurrences or refactoring of future occurrences.
My users are all in CST, and I thank the good Lord for that. It is a helpful simplification for now, and if in the future the user base is going to expand beyond that, then I can figure out how to deal with it then, as a well separated task.
UPDATE
Since I first wrote this, I did add daily occurrence with "Every weekday". Our users had a bit of a hard time with thinking that you could use Weekly recurrence for events happening from Thursday one week to Tuesday the next week and only on weekdays. It was more intuitive for them to have this, even if there was already another way that they could do it.
I have been thinking about this too, although have not implemented it but these are my thoughts for a simple solution.
When setting up an event thats recurring, have the user specify the "end date" and create individual events for each one (based on the recurring options). Because its a recurring event, set a unique "recurring ID" for each of these. This ID will then be used to mark an event as recurring and if you change a future event, you can prompt the user to apply this to the rest of the future events by deleting and recreating the recurring events with a new "recurring ID" which will also differentiate this recurring event from the previously ones that have changed.
Hope this makes sense and would like any comments.
I would record recurring events as two separate things in the database. First of all, in an events table, record each and every occurence of the event. Secondly, have recurrences table in which you record the details that you ask for to set up the recurring event. Start date, periodicity, number of occurences, etc.
Then you might think of tying it all together by putting the PK of recurrences into each of the event records as an FK. But a better design would be to normalise the event table into two tables, one which is just the barebones of an event, and one which has the details, which could now be referring to multiple events. That way every event record, recurring or not, has an FK to the PK of the eventdetails table. Then in eventdetails, record the PK of recurrences somewhere along with agenda, invitees, etc. The recurrence record does not drive anything. For instance, if you want a list of all recurring events, you look through eventdetails for all events with a non-null FK to recurrences.
You'll need to be careful to synchronise all of these things, so that you insert or delete events when the recurrence data changes.
"Aside from anything else"
does this include "the very requirements" ?
"that will make it easy to export into other applications should you wish to."
Do the stated requirements include "it must be easy to export the calendars to other applications" ? My impression was that the problem consisted solely of building the FIRST application.
that said, my own response :
You need to limit yourself/your user on the types of "recurrency" your sytem will be able to support. And "All of the above" or "No Limitations" will not be a valid answer if you/your user want(s) to end up with a usable application.