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

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"))

Related

RRULE for every other week except last week of month

I need an RRULE for every other Saturday except the last week of the month. I tried to create one with a weekly frequency, but didn't know how to apply an exception for the last week of the month:
RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=SA
I also tried creating a rule with a monthly frequency, which allowed me to skip the last week of the month, but I didn't know how to make it every other week:
RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=SA;BYSETPOS=-2,-3,-4,-5
I looked through the specification, but I'm not seeing anything that makes this possible.
The secret to the solution here is that BYMONTHDAY can be negative like BYSETPOS. This allows one to exclude the last 7 days of each month even though the number of days in the month varies. Your DTSTART should be on a SATURDAY, so one doesn't really need the BYDAY=SA
This rrule works in google calendar (if DTSTART is on Saturday and generally for any every 2nd week but not the last week rule for any day of week specified by the DTSTART):
RRULE:FREQ=WEEKLY;INTERVAL=2;BYMONTHDAY=-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,-19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31
See test calendar:
https://calendar.google.com/calendar/u/0?cid=ZXBwdWE4N2RwZm5xODVic3JydDJzaXFsY3NAZ3JvdXAuY2FsZW5kYXIuZ29vZ2xlLmNvbQ
Spec: https://datatracker.ietf.org/doc/html/rfc2445#page-43
and
https://icalevents.com/2447-need-to-know-the-possible-combinations-for-repeating-dates-an-ical-cheatsheet/ for the expansion & contraction (limiting) rules & combinations

Recurring calendar event on First of the month

I have a recurring calendar event on 1st of each month, when 1st falls on Sat/Sun is it possible for iCal to schedule it for last working day Fri?
If I understood you correctly the following RRULE should do the trick:
FREQ=MONTHLY;BYDAY=1MO,1TU,1WE,1TH,1FR,-1FR;BYMONTHDAY=1,-1,-2
See the next 100 instances
It basically does two things:
Iterate the first weekday that falls on the 1st day of the month
Iterate the last Friday of each month that falls on the last or 2nd last day of the month (in which cases the 1st of the next month falls on Saturday or Sunday).
A slightly shorter version that should yield the same results is
FREQ=MONTHLY;BYDAY=1MO,1TU,1WE,1TH,FR;BYMONTHDAY=1,-1,-2
This just iterates every Friday, but only keeps the ones that fall on the first, last and 2nd last day of each month. Though it looks like the recurrence expansion service above disagrees. That's probably a bug.
I'm assuming you mean "the last working day Friday of the previous month", in which case I don't think it possible. It would mean that some months have 2 occurrences when others have 0, which doesn't really work.
You could easily do the first working day of the month (the 1st, or the first Monday):
FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=1
Or, you could do always the last working day of the month:
FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1

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.

What's the name of this week number algorithm?

My customer wants to display week numbers as they show up in his wall calendar:
Week #1 starts on 1st January
Last week of the year (#53 or #54) ends on 31st December
All other weeks start on Monday and end on Sunday
(As a consequence, first and last weeks do not necessarily have 7 days.)
Does this week number algorithm have a name?
Clarification: I already have PHP code to calculate it, I'm just curious about whether this way of identifying weeks has a commonly accepted name.
There isn't one - that is a completely off-the-wall approach to week numbers. Weeks normally start either with Monday or Sunday when using the Gregorian Calendar. They do not start midway. This is not a criticism of your customer, but a comment on the fact that people invent new ways looking at date arithmetic. And get in trouble migrating to new systems.
RFC 3339
http://www.ietf.org/rfc/rfc3339.txt
See also ISO 8601

Is there a Haskell library for dates?

Is there a function in Haskell that will allow me to enter component of a date (like a string representation or day month year components) that I can get information from (like day of week, days in a month, etc.)?
I've looked online and it looks like there are a lot of custom libraries, but I'm hoping there's one in the standard prelude library of ghci 10.6.4 that's just not well documented?
Are Data.Time.Calendar and Data.Time.Format in the time library sufficient?
You can parse a string representation of a date and get the length of a month using gregorianMonthLength. Not sure about day of the week, though you could format the date as a string using a format that just displays the week day.
A quick Google search turns up this, which may be what you want. It lets you parse strings representing dates and extract information from them.
You can find the day of the week with mondayStartWeek or sundayStartWeek, depending on whether you think a week starts on Monday, or on Sunday. Both functions are in Data.Time.Calendar.OrdinalDate.
λ> snd $ mondayStartWeek $ fromGregorian 2017 10 3
2
In the above example, the return value is 2, which indicates the second day of the week. Since the function is called mondayStartWeek, Monday is the first day, so 2 corresponds to Tuesday. This is true of October 3, 2017.
A warning regarding week numbers
Both functions return a tuple, where the second element is the week day. As far as I can tell, that should be trustworthy.
The first element, however, is the week number of the year. Be careful with that, because the rules for week numbering are political. If I remember correctly, in USA, week 1 is the week that contains January 1. That's not the case in Denmark, where I live. Here, week 1 is the first week where Thursday falls in the new year. This can mean that December 31 can fall in week 1 of the next year. IIRC, this is the rule for many other European countries. Some years, the American and the European week numbers align, but some years, they don't.