RRULE 20 days after every 15th in a month,in icalendar (RFC 5545)? - icalendar

I'm searching a way to express a situation like this in icalendar: an event happens every month, x days after a given date.
e.g.: 20 days after 15th day in every month. so, it might be 3rd, 4th, 5th,6th( like February )
if bymonthday can be set to 35, it's ok.
But in outlook this won't work.
How to solve this question?

You could perhaps try adding ";BYSETPOS=20" to the rule. The specification shows an example of BYSETPOS when using it with BYDAY, but it is not clear to me how it is handled when using BYMONTHDAY. I don't see another option looking at the spec.
http://icalendar.org/iCalendar-RFC-5545/3-3-10-recurrence-rule.html
http://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html

Sorry, what you want is not possible with a RRULE.
What you want is RRULE:FREQ=MONTHLY;BYMONTHDAY=35. Unfortunately, it's invalid - BYMONTHDAY can't exceed 31.
BYSETPOS won't work either. In RFC 5545, page 43 under BYSETPOS is the following:
"BYSETPOS operates on a set of recurrence instances in one interval of the recurrence rule."
That means you can't get a value beyond the interval. If you use Monthly you are restricted to the one month.
If you want to experiment with some RRULEs try my recurrence rule (RRULE parser) at
http://balsoftware.net/index.php/open-source/rrule-parser/

Related

How to calculate recurring/repeating monthly events (e.g. first Friday)?

How to calculate dates for things like 1st Friday or 3rd Saturday?
I took Dave Peterson's answer from 2005(!) and adapted it a bit so you can drag down in google sheets.
Example for 3rd saturdays:
In A1, put "DATE(YEAR(TODAY()),MONTH(TODAY()),1+7*3)
-WEEKDAY(DATE(YEAR(TODAY()),MONTH(TODAY()),8-7))"
In A2, put "DATE(YEAR(A1),MONTH(A1)+1,1+7*3)
-WEEKDAY(DATE(YEAR(A1),MONTH(A1)+1,8-7))"
That will calculate the year based off your current date. The part that is controlling the week number (ie 3rd or 1st) is that 7*3(3rd week) part. That part that is controlling the day of the week is the 8-7 part. Still trying to grok that. The +1 is adding a month, thus allowing you to do a fill down.
Test this against google calendar to get it right. Hope this can help someone stuck!
Make a copy of it if you'dlike: https://docs.google.com/spreadsheets/d/1lOroSjy9EXLoiu-kDE3w1EMWw42HMIG7YJ3iGNhpl34/edit?usp=sharing
For the first five mondays from March 2018,
=ARRAYFORMULA(WORKDAY.INTL(DATE(2018,3,),ROW(A1:A5),"0111111"))
Uses string method of WORKDAY.INTL to declare specific weekday as the only working day.
For third Saturday of each month from March 2018,
=ARRAYFORMULA(WORKDAY.INTL(DATE(2018,ROW(A3:A12),),3,"1111101"))

Determine number of days represented by a time range in Java

Using Java 8 time I am simply trying to figure out the number of days represented in a time range. Consider the following:
LocalDate start = LocalDate.of(2016, Month.MARCH, 28);
LocalDate end = LocalDate.of(2016, Month.MARCH, 31);
Period period = Period.between(start, end);
The number of days in period is 3 which represents the number of days between the 2 dates, inclusive of start and exclusive of end. What I want is the number of days represented by the 2 dates which is actually 4 (March 28, March 29, March 30, March 31).
I know I can just add 1 to the number of days returned from Period.between() but I guess I was surprised that I couldn't find another call to return exactly what I want. Am I missing something or is adding 1 the only solution?
tl;dr
Always define your spans of time by the Half-Open approach where:
Beginning is inclusive.
Ending is exclusive.
When you want the four days of March 28, March 29, March 30, March 31, make the beginning March 28 and the ending April 1. Run through those dates starting at the first (March 28th) while going up to, but not including, the last (April 1st).
2016-03-28/2016-04-01
Half-Open
Am I missing something
You may be missing an appreciation for the usefulness of the Half-Open approach in defining spans of time.
Generally, the best practice for defining spans of time is the Half-Open approach. In Half-Open, the beginning is inclusive while the ending is exclusive.
This approach solves the problem of dealing with fractional seconds. Intuitively, many programmers will try to find the last possible moment as the ending of a span of time. But that last moment involves an infinitely divisible last second. You might think, "Well, just go to three decimal place for milliseconds, 12:59.59.999 for the end of noon lunch break, as that is all the resolution I will ever need, and that is the resolution of the legacy java.util.Date class.”. But then you would fail to find matches in your database like Postgres that store date-time values with a resolution of microseconds, 12:59:59.999999. So you decide to use six decimal places of fraction, x.999999. But the start experiencing mismatches with date-time values in the java.time classes, and you learn the offer a resolution of nanoseconds for nine digits of fractional second, x.999999999. You can disembark this carousel of frustrating bugs by using the Half-Open approach where the ending runs up to, but does not include, the next whole second.
I believe you will find consistent use of the Half-Open approach throughout your date-time handling code (whether fractional seconds may be involved or not) will:
Make your code easier to read and comprehend.
Ease the cognitive load overall.Knowing all your spans of time carry the same definition eliminates ambiguity.
Reduce bugs.
Examples:
A noon lunch period starts at the moment the clock strikes noon (12:00:00) and runs up to, but does not include, the moment when the clock strikes one o’clock. That means 12:00:00 to 13:00:00.
A full day starts at the first moment of the day (not always 00:00:00, by the way) and runs up to, but does not include, the first moment of the following day.
A week starts on a Monday and runs up to, but does not include, the following Monday. That means seven days in Monday-Monday.
A month starts of the first of the month and runs up to, but not including, the first of the following month. So the month of March is March 1 to April 1.
LocalDate
Rather than one adding 1 to get a total of days, define your span of time as Half-Open: beginning-is-inclusive, ending-is-exclusive. If you are trying to represent the four dates of March 28, 29, 30, and 31, then I suggest you define a span of time from March 28 to April 1.
LocalDate start = LocalDate.of( 2016, Month.MARCH, 28 ) ; // inclusive
LocalDate stop = LocalDate.of( 2016, Month.APRIL, 1 ) ; // exclusive
Period
The java.time classes wisely use the Half-Open approach. So the Period.between method treats the ending as exclusive, as noted in the Question. I suggest you go-with-the-flow here rather than fight it. Search Stack Overflow for many more examples of how well this approach works.
Period p = Period.between( start , stop );
p.toString(): P4D
ChronoUnit
If you want a total number of days, such as 45 for a month and a half, use the ChronoUnit enum, an implementation of TemporalUnit. See this Question for discussion.
Again, the java.time classes use the Half-Open approach. So
long daysBetween = ChronoUnit.DAYS.between( start, stop );
4
Live code
See this example code run live at IdeOne.com.
There doesn't seem to be an inclusive end date method in either Period or LocalDate so it seems that the only thing to do is something like:
Period.between(start, end.plusDays(1))
or
start.until(end.plusDays(1))
(Period.between just calls LocalDate.until)
I belive your day counting differs from java's. Period.between according to documentation: http://docs.oracle.com/javase/8/docs/api/java/time/Period.html#between-java.time.LocalDate-java.time.LocalDate-
"The start date is included, but the end date is not." Having that in mind - yes, adding 1 is the only solution.
the signature of the method is
between(LocalDate startDateInclusive, LocalDate endDateExclusive) {
and the method is not oerloaded, you have no choice other than add 1 to the given result...

How can I exclude DTSTART from generated events if its day not among days specified by BYDAY?

I'm using google-rfc-2445 to generate repeating events according to according to rfc-2445:
The "DTSTART" property for a "VEVENT" specifies the inclusive start of
the event. For recurring events, it also specifies the very first
instance in the recurrence set.
So, for example RRULE for event which occures every Friday 5 times:
DTSTART;TZID=US-Eastern:20160204T090000
RRULE:FREQ=WEEKLY;COUNT=5;BYDAY=FR;INTERVAL=1;
So according to rfc-2445 it will generate 6 events. First event on Thursday 4 February 2016, second event on Friday 5 February 2016, and so on.
How can I achieve that it will exclude first event if it isn't in a pattern? In the example above it should exclude first occurrence, 4 February 2016. In case of defining DTSTART;TZID=US-Eastern:20160205T090000 which is Friday it should leave first occurrence.
Can it be done by defining such "exclusion rule" in RRULE itself or I need to make a check in a code and if DTSTART isn't the same day as defined in BYDAY I should look for closest date in code (manually) and change DTSTART accordingly?
UPDATE
Ok, according to rfc-2445 and this question on google group: https://groups.google.com/forum/#!topic/google-rfc-2445/xqYFe411ysA
The "EXDATE" property can be used to exclude the value specified in
"DTSTART". However, in such cases the original "DTSTART" date MUST
still be maintained by the calendaring and scheduling system because
the original "DTSTART" value has inherent usage dependencies by other
properties such as the "RECURRENCE-ID".
it looks that I need to use EXDATE property to achieve what do I need. Trying to achieve this by following RRULE:
EXDATE;TZID=Asia/Jerusalem:20160210T000000
RRULE:FREQ=WEEKLY;COUNT=5;BYDAY=WE;INTERVAL=1;
And start date is: 2016-02-10T00:00:00.000+02:00 in the following code:
DateTimeIterable dti = DateTimeIteratorFactory.createDateTimeIterable(RRULE, DTSTART, dateTimeZone, true);
But it returns only 4 events, so it always remove first event.
From the description of the problem you give, you will get 6 events when DTSTART is added and you would not want it to be part of the list of instances and 5 events when it is a good date.
So what you want is to only get the last 5 events, which is possible by using the BYSETPOS in your RRULE, the following should do the trick:
BYSETPOS=-5,-4,-3,-2,-1
which will return in all cases the last 5 events that your RRULE gives regardless if the DTSTART is matching the pattern of your RRULE or not.

Date no greater than the current year or next year

I need to set a validation rule in Access so that the DateOfArrival is always after the DateOfTheOrder.
I also have to make sure that the DateOfArrival is not set too far away in the future...so it shouldn't be greater than the current year or the following at max (for cases such: order 31 dec 2015, arrival 1 jan 2016).
I've put:
[DateOfArrival]>[DateofOrder] AND [DateOfArrival]<=Year(Date())+1
in the validation rules but if I enter DateofOrder=31/12/2015 and DateOfArrival=01/01/2016 it gives me an error. Can you help me?
The error must be in the second part of the rule.
[dateOfArrival] is a Date, while YEAR(Date()) is an Integer ...
When comparing them, [dateOfArrival] will be considered as a number, being the number of days since the 31/12/1899, and YEAR(date()) will be definitely and always lower than this number.
You should compare YEAR(dateOfArrival) with YEAR(date()))!

single icalendar rule for 1st weekday of multiple months every year?

Is it possible to specify an event to occur on the 1st weekday of multiple months every year in a single RRULE? Using January and June as a test case, my initial attempt was:
FREQ=YEARLY;BYDAY=MO,TU,WE,TH,FR;BYMONTH=1,6;BYSETPOS=1
but BYSETPOS reduces the set down to January only. I think splitting it out into multiple rrules would work, but it would greatly increase the complexity of this area of my app so I was hoping for one rrule with a yearly freq.
Thanks!
You could try:
FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=1;BYMONTH=<SELECTED_MONTHS_FROM_UI>
Please note the order of options is different.