How can I write an ICS file for the Friday before the first Saturday of the month? - icalendar

I've seen How can an ICS file be written for a recurring event? but I've got a rather complex recurrence and can't figure out a rule after looking at the syntax of RRULEs.
I want an event that happens on the Friday preceding the first Saturday of each month. This Friday-before-the-first-Saturday may of course be in the previous month. I assume that if I can get this to work, similar (but not identical) events for Friday-before-the-second-Saturday, and -third- and -fourth-, with Friday before 5th Saturdays undefined.
Obviously I'd have RRULE:FREQ=MONTHLY;BYDAY=FR; but if I try to follow some of the examples using BYMONTHDAY I run into trouble: 28 would be a valid Friday-before-a-first-Saturday in February, but in any other month, Friday 28th would be the Friday before a 5th Saturday. Similarly for 29 (in a leap year), 30 and 31.
The goal is to include this in a Google Calendar, which I know supports display of ICS RRULEs it can't edit. So, assuming it's possible, how can I create an RRULE for this event? I've considered a separate event and accompanying rule for each month length. 31: Jan, Mar, May, Jul, Aug, Oct, Dec and 30: Apr, Jun, Sep, Nov are OK, but leap years are still an issue: 28 Feb could be a Friday before a first Saturday or a 5th Saturday (e.g. 2020 so one of my first two cases fails).

You're on the right track with having to use BYDAY=FR, AND since you can do negative BYMONTHDAY, the following should do the trick:
RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=-1,1,2,3,4,5,6

Related

Google Sheets | Return last Friday's date on Sat to Wed apart from Thu and Fri

I'm a bit rubbish on Google Sheets formulas... would anyone be so kind to tell me how to achieve this ?
I'd like to have a cell that returns the last Friday's date on Sat to Wed, and instead the current date for Thursdays and Fridays.
Is it possible ?
e.g. this coming days:
Sat to Wed returns Friday 12th of March
Thu 18th returns Thu 18th
Fri 19th return Fri 19th
... and so on.
Thanks!
There are many ways to accomplish this, but try this:
=IF((WEEKDAY(TODAY())=5)+(WEEKDAY(TODAY())=6),TODAY(),TODAY()-VLOOKUP(WEEKDAY(TODAY()),{7,1; 1,2; 2,3; 3,4; 4,5},2,FALSE))
This formula is based on the us default numbers for weekdays, where Sunday = 1. If this formula produces unexpected results, your locale may be one where Monday = 1. In this case, you'll need to adjust as follows:
=IF((WEEKDAY(TODAY())=4)+(WEEKDAY(TODAY())=5),TODAY(),TODAY()-VLOOKUP(WEEKDAY(TODAY()),{6,1; 7,2; 1,3; 2,4; 3,5},2,FALSE))
Other things to keep in mind:
The + in (WEEKDAY(TODAY())=5)+(WEEKDAY(TODAY())=6) means OR (where * would mean AND).
The VLOOKUP is looking up the weekday of TODAY() within a simple virtual array, which is formed between the curly brackets and which instructs how many days to subtract from TODAY() given the current weekday in order to arrive at the previous Friday.

How to calculate the weekend when counting a date range in Google Sheets?

I have the below columns
StartDate EndDate CountDay
01 May 20 05 May 20 ?
As you see, 01 May is Friday, so from 01-05 May if we count all days including weekend it will be 4 days.
What I want is on column "CountDay" it only counts the Workdays, not the weekend.
SO the expected result would be 2.
Anyone know how to do it using a formula in Google Sheets?
Do you consider Fridays as part of the weekend?
If yes, then you could also try the following formula:
=NETWORKDAYS.INTL(A10, B10,"0000111")
If not, please use this formula:
=NETWORKDAYS.INTL(A10, B10)
How the formulas work.
By using the function NETWORKDAYS.INTL we can "adjust" the weekend (non-working weekdays) to our liking.
In this case we account Fridays as our non-working weekdays by using as the 3rd parameter 0000111 instead of the default 0000011 where every 0 represents a working weekday and every 1 a non-working weekday.
(Very useful for people working part-time)
Someone who has part-time work on only Mondays, Wednesdays and Fridays and wants to calculate the working days Friday, 1 May 2020 - Tuesday, 30 June 2020 could adjust the formula to:
=NETWORKDAYS.INTL(A10, B10,"0101011")
As explained on the official Google help page for NETWORKDAYS.INTL
weekend – [ OPTIONAL – 1 by default ] – A number or string representing which days of the week are considered weekends.
String method: Weekends can be specified using seven 0s and 1s, where the first number in the set represents Monday and the last number is for Sunday. A zero means that the day is a work day, a 1 means that the day is a weekend. For example, “0000011” would mean Saturday and Sunday are weekends.
Number method: Instead of using the string method above, a single number can be used. 1 = Saturday/Sunday are weekends, 2 = Sunday/Monday and this pattern repeats until 7 = Friday/Saturday. 11 = Sunday is the only weekend day, 12 = Monday is the only weekend day and this pattern repeats until 17 = Saturday is the only weekend day.
I just found how to do it:
=if(weeknum(A10)<weeknum(B10),B10-A10-2*(weeknum(B10)-weeknum(A10)),B10-A10)
something like that

RRULE for the weekend including the first sunday of a month

We have a event every year on the weekend (Fr-Su) that includes the first Sunday of June. How would I create a iCalendar Event that expresses these three days (whole day events)?
Creating a rule for the first Sunday is easy. But for the Saturday and Friday, I did not succeed to create a rule that counts backwards (RFC 5545 says INTERVAL, COUNT must be positive]. Moreover I could not think of a different expression that would start from the Friday - it could be the last Friday of May, but also the first in June.
The RRRULE specification in RFC 5545 is lacking in this regard. The INTERVAL and COUNT values are for the repeating events, not the event itself. I've come across a similar issue when trying to define the USA day "Black Friday", the day after the 4th Thursday in November (Friday after Thanksgiving). The 4th Friday in November could occur the day after the 4th Thursday, or the prior week. There is not a way that I have found to make a RRULE for this situation.
I believe you will need to code the events individually instead of using a recurring rule.
RRULE:FREQ=YEARLY;BYDAY=FR;BYMONTH=5,6;BYSETPOS=2;BYMONTHDAY=-2,-1,1,2,3,4,5,6,7' seems to do the trick.
How can I write an ICS file for the Friday before the first Saturday of the month? led me to the right track: with 'BYMONTHDAY' I can count backwards from the end of the month.
The Friday before the first Sunday of the next month can be the last or the second to last day of the previous month, or up to the 5th day of the month. If I include May and June, I will get a set that includes the day. 'BYSETPOS' allows me to choose the second of the found Fridays. To always have the second in the set being my desired day, I include the 6th and 7th day of the month, which gives me a stable first Friday in May. Possibly matched additional Fridays in June are discarded by 'BYSETPOS' anyway.
Extending this to Saturday is simple, and the first Sunday of June is trivial.
I developed the rule with rrule.js
https://jakubroztocil.github.io/rrule/#/rfc/RRULE:BYDAY=FR;BYMONTH=5,6;BYSETPOS=2;BYMONTHDAY=-2,-1,1,2,3,4,5,6,7

How to find a Friday after last Wednesday of month?

What iCal RRULE expression should I use to find a Friday after last Wednesday of month? So I need (RRULE:FREQ=MONTHLY;BYDAY=-1WE) + 2 days...
I agree with Evert that this is not possible with a single RRULE.
You can, however, achieve that with a combination of multiple RRULEs.
That way you can split your event into multiple events each one having one of the RRULEs below:
If Wednesday falls on the last or second last day of a month, our Friday will be the 1st or 2nd of the next month
FREQ=MONTHLY;BYMONTHDAY=1,2;BYDAY=1FR
In months with 31 days the earliest date for the last Wednesday is the 25th, so the next Friday will be one of day 27-31:
FREQ=MONTHLY;BYMONTH=1,3,5,7,8,10,12;BYMONTHDAY=27,28,29,30,31;BYDAY=FR
In months with 30 days the earliest date for the last Wednesday is the 24th, so the next Friday will be one of day 26-30:
FREQ=MONTHLY;BYMONTH=4,6,9,11;BYMONTHDAY=26,27,28,29,30;BYDAY=FR
February is a tricky one, because in non-leap years the the Friday we want will be between the 24th and 28th, but in leap years it's between the 25th and 29th. However, within the next 50 years there is only one leap year in which February 24th is a Friday, which is 2040 (check out the result of FREQ=MONTHLY;BYMONTHDAY=24;BYMONTH=2;BYDAY=FR), so the following RRULE will be correct until 2040:
FREQ=MONTHLY;BYMONTH=2;BYMONTHDAY=24,25,26,27,28,29;BYDAY=FR
If you're concerned about the leap years, add an EXDATE like below and you're good for the next 100 years (make these DATE-TIME values if your start date has a time):
EXDATE;VALUE=DATE:20400224,20680224,20960224,21080224
If you know for sure that your clients support multiple RRULEs (which has been deprecated halfheartedly in RFC 5545 but still was perfectly valid in RFC 2445) you could add them into a single event as well, but I wouldn't recommend that.

How to subtract two dates in Oracle and extract the year part from the difference?

My typical requirement is that I want to subtract two Dates cast as timestamp. The Minuend (First parameter) is the current date and the Subtrahend(second parameter) is stored separately as DD, MM and YYYY in three columns. The final output should be a discrete year as number. I am playing with something like :
SELECT (TO_DATE('05-DEC-2013') -
CASE LENGTH(CAND_DOB_DD)
WHEN 1 THEN
CAST(TO_DATE('0'||CAND_DOB_DD||'-'||CAND_DOB_MM||'- '||CAND_DOB_YYYY,'DD-MM-YY HH24:MI:SS')
AS TIMESTAMP)
ELSE
CAST(TO_DATE(CAND_DOB_DD||'-'||CAND_DOB_MM||'-'||CAND_DOB_YYYY,'DD-MM-YY HH24:MI:SS')
AS TIMESTAMP) / 365 END YEAR
FROM CANDIDATE
The Year part as Integer will be used for a very sensitive calculation. Please suggest if the above piece of SCRIPT will yield the desired result. Thanks in advance.
For most purposes you could just use the Months_Between() function to determine the number of months between two dates, and then divide by 12 etc.. Note that the number of months is an integer when comparing two dates that have the same day of the month or are both the last day of the month.
This is tricky when it comes to leap years.
Do you count 28th Feb 2015 to 28th Feb 2016 as exactly one year, when 28th Feb 2015 to 29th Feb 2016 is one day longer but plainly is a year?
What about 29th Feb 2016 to 28th Feb 2017, or 28th Feb 2016 to 28th Feb 2017?
Think carefully about these boundary cases, but Months_Between() is likely to be your best choice.