Get last day in month in AppleScript and holidays in current month - excel

I am writing an AppleScript which generates an MS Excel spreadsheet every month. I need to know how many days are in the current month, then go trough all months and decide if a given day is a weekday or a holiday.
I suppose I would save holidays (from this web http://kalendar365.cz/statni-svatky/2016 as table and access them locally) for this.
My question is:
How do I get the last day in a month?
How do I efficiently loop trough all days in the current month and decide if it is Sunday, Saturday or a day specified somewhere else (for example, in a text file of xlsx spreadsheet)?

pbell's answer is promising, but the GetLastDay function doesn't work correctly for months that have fewer than 31 days; here's a function that fixes that:
# Returns the number of days in the month that the given date falls in.
# Example:
# my GetNumberOfDaysInMonth(current date)
on GetNumberOfDaysInMonth(aDate)
local aDateCopy
copy aDate to aDateCopy
set day of aDateCopy to 1
if month of aDateCopy is December then
set year of aDateCopy to ((year of aDateCopy) + 1)
set month of aDateCopy to 1
else
set month of aDateCopy to ((month of aDateCopy) + 1)
end if
return day of (aDateCopy - 1 * days)
end GetNumberOfDaysInMonth
The approach is based on setting the date to the 1st of the month, then incrementing the month (possibly rolling over into the next year), and subtracting 1 day, which works correctly with all dates, even in leap years.

How about a simple no-function-needed method?
set currdate to the current date
set nextmonth to currdate + (30 * days)
set {year:y, month:m, day:d, time:t} to nextmonth
set ms to m as string --month as string
set ys to y as string --year as string
set firstday to date (m & " 1," & y as string) --midnight at the first day of next month
set lastday to (firstday - 1) --minus one second
return lastday -- last day of the this month at 11:59 PM
As for weekends and holidays in Excel, doesn't Excel provide its own functions for that, as dirk-reichel mentioned?
However, if you want to use AppleScript to filter out these days using a pre-specified list of holidays, maybe this example will help. It loops through October through December of 2022, with USA holidays Halloween, Thanksgiving and Christmas Day specified. Note that Christmas Day happens to land on a Sunday in 2022.
set weekend to {"Saturday", "Sunday"}
set holidays to {date "October 31, 2022", date "November 24, 2022", date "December 25, 2022"}
set workdays to {}
set my_date to (date "Saturday, October 1, 2022 at 12:00:00 AM")
repeat
set dy to the weekday of my_date
set mydy to dy as string
if weekend does not contain mydy and holidays does not contain my_date then
set workdays to workdays & my_date
end if
set my_date to my_date + (1 * days)
if my_date contains (date "January 1, 2023") then --specify an end date for your loop
exit repeat
end if
end repeat
return workdays

The script below contains the 2 routines you're looking for : GetlastDay and isWorkingDay :
set myDate to current date -- just for example !
set N to GetlastDay(myDate)
log N --> number of days in month of myDate
set A to IsWorkingday(myDate)
log A --> true if Monday to Friday, false if Saturday/Sunday
on GetlastDay(LDate) -- return last day of month of LDate
copy LDate to L -- to not change LDate
set L's day to 32 -- = first day of next month
set L to L - (1 * days) -- last day of month
return day of L
end GetlastDay
on IsWorkingday(LDate) -- true if date is not Saturday or Sunday
set SD to weekday of LDate
return (SD is not in {Saturday, Sunday})
end IsWorkingday

Related

How to get the Week of the month (1:6)

We can find different approaches to determining the week of the month, and even though there are many pages on 1:4 and/or 1:5, there is very few around 1:6 approach.
So to give you a bit of the context, I am working with a pivot table in Excel which gets its values from a Power Query source.
In Power Query, there is a function Date.WeekOfMonth which takes in the date and returns a number between 1 and 6.
In this definition, weeks start from Sunday and ends on Saturday.
So, for example, the first two days of October 2021 -i.e. Fri & Sat- fall in the 1st week of Oct, while the 3rd day of Oct 2021 starts the second week, and then the last day of October 2021,i.e. Oct 31, is the only day in the 6th week.
I had an automation task on hand in which I needed to pull data from the Power Query-generated pivot, so I had to implement a piece of code in VBA which calcs weeks the same.
Unfortunately, I couldn't find any prepared snippet, so after implementing I though it might worth sharing.
(Any comments and suggestions appreciated)
The DatePart function is perfect for this. Using DatePart with the interval set to "weeks" you can find the week of a given date. Then you subtract the number of weeks before the first day of that month (which sets the first day to week = 1).
Function WeekNumOfDate(D As Date) As Integer
WeekNumOfDate = DatePart("ww", D) - DatePart("ww", DateSerial(Year(D), Month(D), 1)) + 1
End Function
Here is a second version of the function that has the ability to set the FirstDayOfWeek argument:
Function WeekNumOfDate(D As Date, Optional FirstDayOfWeek As VbDayOfWeek = vbSunday) As Integer
WeekNumOfDate = DatePart("ww", D, FirstDayOfWeek) - DatePart("ww", DateSerial(Year(D), Month(D), 1), FirstDayOfWeek) + 1
End Function
As an example for using FirstDayOfWeek: With FirstDayOfWeek set to vbThursday, the date "Nov 5th, 2021" will return as Week 2, whereas it would by default be counted as Week 1. November 1st to 3rd of 2021 will be week 1, and then 4th to 10th will be week 2.
Its implementation in VBA is:
Function WeekOfMonth(My_Date As Date)
If Day(My_Date) > Day(My_Date - 1) And Weekday(My_Date) > Weekday(My_Date - 1) Then
WeekOfMonth = WeekOfMonth(My_Date - 1)
ElseIf Day(My_Date) > Day(My_Date - 1) And Weekday(My_Date) < Weekday(My_Date - 1) Then
WeekOfMonth = WeekOfMonth(My_Date - 1) + 1
Else
WeekOfMonth = 1
End If
End Function
Note that even though the above function is recursive, its time and space complexity is an expression of order N, which here cannot exceed 31.

Get the first Friday of the Quarter of Today's Date

I was trying to get the first Friday of the quarter of today's date or any given date. Let's say the date is 12/06/2020, which falls to the 2nd quarter of the year. I should be able to get the first Friday of the 2nd Quarter and that should be April 3rd.
I was only been able to get the quarter of a given date, which you can see in the code below. Been stuck here for a while. Thanks in advance.
quarter = Int((Month(Now) + 2) / 3)
Here's a function that takes a date and returns the first Friday of the quarter:
Function FirstFridayOfTheQuarter(MyDate As Date) As Date
Dim FirstDayOfTheQuarter As Date
FirstDayOfTheQuarter = DateSerial(Year(MyDate), Int((Month(MyDate) - 1) / 3) * 3 + 1, 1)
FirstFridayOfTheQuarter = DateAdd("d", (13 - Weekday(FirstDayOfTheQuarter)) Mod 7, FirstDayOfTheQuarter)
End Function
This function is taking advantage of the Weekday function that returns:
1 for a Sunday
2 for a Monday
3 for a Tuesday
4 for a Wednesday
5 for a Thursday
6 for a Friday
7 for a Saturday
In case you want a non VBA solution:
My formula is:
=CEILING(EOMONTH(DATE(YEAR(A1);ROUNDUP(MONTH(A1)/3;0)+(ROUNDUP(MONTH(A1)/3;0)-1)*2;1);-1)-5;7)+6

How to define a variable in between 2 date periods and time periods?

So I'm trying to define a variable or multiple variable so I can easily filter in my data set. Essentially I need to filter by date/time in my data set. The format of the date and time in the data set is as such: 2019-01-03 8:45:30 PM
What I want to do is to define a variable in order to always filter the data based on the current date. My data always changes every day, therefore my point of reference is today's date. Essentially I need to filter data starting from 2 days ago at 11am all the way to yesterdays date ending at 10am. How would i go about defining my variable? I tried doing the following:
Dim StandardH As Date
StandardH = Date - 1 + (1 / 24)
And do the same thing all the way to 10 am and do - (1/24) all the way till 11am but that doesn't seem to work.
I realize that there's probably a simpler way of doing this. Any ideas?
Thanks,
In VBA:
"2 days ago at 11 AM" translates to Date - 2 + TimeSerial(11, 0, 0)
"Yesterday at 10 AM" translates Date - 1 + TimeSerial(10, 0, 0)
That's in relation to the date and time the code is being run, and assumes by "2 days ago" you mean "the day prior to yesterday".
If I had some dates on "Sheet4" in the range "B7:B17" (assume there is a header in cell B6), then I think I could use the code below to filter from (and including) 2 days ago at 11 AM, up to (and including) yesterday at 10 AM:
Option Explicit
Sub FilterDatesInclusively()
With ThisWorkbook.Worksheets("Sheet4")
.AutoFilterMode = False
Dim fromDate As Date
fromDate = Date - 2 + TimeSerial(11, 0, 0)
Dim toDate As Date
toDate = Date - 1 + TimeSerial(10, 0, 0)
.Range("B6:B17").AutoFilter Field:=1, Criteria1:=">=" & CDbl(fromDate), Operator:=xlAnd, Criteria2:="<=" & CDbl(toDate)
End With
End Sub
Maybe there is some way of filtering without converting to double, but I couldn't work it out.

Retutn only Buisness days in custom date function in excel

I have a date which I will need to increment the date by a day, month or year from the actual date. This is based of a list of fields below and is different per the input. Also each resultant date has to be a business day i.e not a weekend day or a bank holiday. Also if the resultant date is either Dec 25 or Jan 1st the day needs to move forward to the next business day (not a weekend day).
I have created this in Excel using a couple of formulas though it is a bit clunky.
Below is my data set
Business Date 15/05/2018
Tenor Settlement Value Settlement Period
ON 1 Day
TN 2 Day
SP 2 Day
SN 3 Day
1W 7 Day
2W 14 Day
3W 21 Day
1M 1 Month
2M 2 Month
3M 3 Month
In column E - I am using formula
=IF(D4="Day",$B$1+C4,IF(D4="Month",EDATE($B$1,C4),(TEXT($B$1,"dd/mm/")&(YEAR($B$1)+C4))+0))
In column F - I am using formula
=E4+LOOKUP(WEEKDAY(E4),{1,2,3,4,5,6,7},{1,0,0,0,0,0,2})
In column G - I am using formula
=F4+IF(AND(OR(TEXT(F4,"ddmm")="2512",TEXT(F4,"ddmm")="0101"),WEEKDAY(F4)>=2,WEEKDAY(F4)<=6),LOOKUP(WEEKDAY(F4),{1,2,3,4,5,6,7},{0,1,1,1,1,3,0}),LOOKUP(WEEKDAY(F4),{1,2,3,4,5,6,7},{1,0,0,0,0,0,2}))
In H I format the date in mm/dd/yyyy and I have my desired result.
storax has kindly created a function for me which replicates my excel formula in column E - on this thread Increment a date by a number of days, months or years
Function IncDate(ByVal dt As Date, ByVal add As Long, ByVal dmy As String) As Date
Select Case UCase(dmy)
Case "DAY"
IncDate = DateAdd("d", add, dt)
Case "MONTH"
IncDate = DateAdd("m", add, dt)
Case "YEAR"
IncDate = DateAdd("yyyy", add, dt)
Case Else
IncDate = dt
End Select
Could use some advise on how I could incorporate my formulas in columns F & G to make the process less clunky.
Manipulating the DATE function (DateSerial in vba) with the WORKDAY.INTL function seems to produce the correct business dates.
Put this in E4 and fill down.
=WORKDAY.INTL(DATE(YEAR(B$1)+(D4="year")*C4, MONTH(B$1)+(D4="month")*C4, DAY(B$1)+(D4="day")*C4)-1, 1, 1, holidays)
[holidays] is a named range (Formulas, Defined Names, Defined Name) with a Refers To: of,
=Sheet10!$Z$2:INDEX(Sheet10!$Z:$Z, MATCH(1E+99, Sheet10!$Z:$Z))

Start the Week Number from the first sunday of every fiscal year in Excel

I am trying to find the week number for a fiscal year which is starts on first sunday of February. I have got it to a point where I can get the week number which starts on first of every year (in my case feb).
Not able to start it from First Sunday. Below is what I've come up with.
=IF(AND(MONTH($E2)=2,DAY($E2)=1),1,ROUNDUP(($E2-DATE(YEAR($E2)-IF(MONTH($E2)<2,1,0),2,0)+WEEKDAY(DATE(YEAR($E2)-IF(MONTH($E2)<2,1,0),2,0)))/7,0))
I would also like it to end on Saturday of last week of the year.
For example: in Feb 2016, the week count should start from 7thFeb2016 and the count should end on 4thFeb2017.
Use this formula to find week number of given date:
=IF(A1>=IF(WEEKDAY(DATE(YEAR(A1),2,1),1)=1,DATE(YEAR(A1),2,1),DATE(YEAR(A1),2,7-WEEKDAY(DATE(YEAR(A1),2,1),1)+2)),ROUNDUP((A1-IF(WEEKDAY(DATE(YEAR(A1),2,1),1)=1,DATE(YEAR(A1),2,1),DATE(YEAR(A1),2,7-WEEKDAY(DATE(YEAR(A1),2,1),1)+2))+1)/7,0),ROUNDUP((A1-IF(WEEKDAY(DATE(YEAR(A1),2,1),1)=1,DATE(YEAR(A1)-1,2,1),DATE(YEAR(A1)-1,2,7-WEEKDAY(DATE(YEAR(A1)-1,2,1),1)+2))+1)/7,0))
I hope you want this.
UPDATED
If you want week number of fiscal quarter, use this:
=ROUNDUP(MOD(=IF(A1>=IF(WEEKDAY(DATE(YEAR(A1),2,1),1)=1,DATE(YEAR(A1),2,1),DATE(YEAR(A1),2,7-WEEKDAY(DATE(YEAR(A1),2,1),1)+2)),ROUNDUP((A1-IF(WEEKDAY(DATE(YEAR(A1),2,1),1)=1,DATE(YEAR(A1),2,1),DATE(YEAR(A1),2,7-WEEKDAY(DATE(YEAR(A1),2,1),1)+2))+1)/7,0),ROUNDUP((A1-IF(WEEKDAY(DATE(YEAR(A1),2,1),1)=1,DATE(YEAR(A1)-1,2,1),DATE(YEAR(A1)-1,2,7-WEEKDAY(DATE(YEAR(A1)-1,2,1),1)+2))+1)/7,0)),13.01),0)
I just chucked this together (no doubt there is a more elegant way to do this). You can use it by putting it into a Module in your VBA editor and then on the worksheet use the function =AltWeekNumber(E2)
Function AltWeekNumber(endDate As Range) As Date
Dim startDate As Date
startDate = FirstFebruarySunday(year(endDate.Value))
If startDate > endDate Then
startDate = FirstFebruarySunday(year(endDate.Value) - 1)
End If
AltWeekNumber = DateDiff("w", startDate, endDate.Value, vbSunday)
End Function
Private Function FirstFebruarySunday(year As Integer) As Date
For i = 1 To 7
If Weekday(DateSerial(year, 2, i)) = 1 Then
FirstFebruarySunday = DateSerial(year, 2, i)
Exit Function
End If
Next i
End Function

Resources