Given a start date, number of days, and holidays, this script calculates the end date of a workday period using JavaScript.
If you are looking to get a list of workdays in a range, then check out this tutorial:
Table of Contents
The Example
Let’s say we have an array of starting dates for a work project and can estimate the number of days that each project will take, we want to determine the end date not including holidays and regular weekly days off, like weekends.
Let’s say our typical work week is Monday to Friday with Saturday and Sunday off.
We also have the following somewhat random holidays:
- 15 Sep 2024
- 31 Oct 2024 🎃🦇👻
- 24 Dec 2024
- 25 Dec 2024
- 01 Jan 2025
Finally here are 3 sample example jobs that we need to calculate the last workday for:
- 10 Sep 2024 running for 10 workdays.
- 26 Oct 2024 running for 5 workdays.
- 22 Dec 2025 running for 16 workdays.
The blue represents the actual workdays, while the white section indicates the actual date range. Orange bold and underlined days are holidays that don’t fall on weekends. Light red days are weekly days off (in our case, weekends).
Across the top of the dates are the days of the week as a JavaScript day running from 0 (Sunday) to 8 (Saturday).
The Video
https://youtu.be/pJLlAE8REZY
Releases 1 Oct 2024
The Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
// CALCULATE THE WORKDATE END DATE IN JAVASCRIPT // Given a start date, number of days and holidays, calculate the end date of a workday period. /** * Gets the end date for each workday in the workdays array. * @param {Object} workdays * @param {String} workdays.startDate - Target date as valid JS date-string * @param {Number} workdays.workdays - Number of workdays. * @param {Number[]} weekends - Array of days off as JS day of week. Sunday = 0, Saturday = 6 * @param {String[]} holdays - Array of hoidays as JS-valid date-strings * @returns {Date[]} Array of Dates in YYYY-MM-DD format */ function getWorkdayEndDate(workdays, weekends, holidays){ const dayMilliseconds = 24 * 60 * 60 * 1000 /** * Gets the UTC for current day. * @param {Sting} date * @returns {Number} UTC Date in milliseconds */ function getUTC(date){ const dt = new Date(date) return Date.UTC( dt.getFullYear(), dt.getMonth(), dt.getDate() ) } // Convert holidays of day of year as number. const holidayUTC = holidays.map(holiday => getUTC(holiday)) console.log(holidayUTC) // Iterate over each date let endDates = workdays.map(workday => { // -- Get day of year as number. const dayStart = getUTC(workday.startDate) // Get day of week let dayOfWeek = new Date(workday.startDate).getDay() let daysRemaining = workday.workdays let day = dayStart while(daysRemaining > 0){ // Check if not weekends or holidays if(!weekends.includes(dayOfWeek) && !holidayUTC.includes(day)){ daysRemaining-- if(daysRemaining == 0) break } day += dayMilliseconds dayOfWeek = dayOfWeek + 1 == 7? 0 : dayOfWeek + 1 } const endDate = new Date(day) console.log(endDate) return new Date(endDate).toISOString().substring(0, 10) }) return endDates } /** * Main run test function */ function runsies(){ // #### SAMPLE DATA // HOLIDAYS const holidays_eg = ["2024-09-15","2024-10-31","2024-12-24","2024-12-25","2025-01-01"] // DAYS OFF [Sun: 0, Sat: 6] <- JavaScript Day of Week Standard. const weekends_eg = [0, 6] // SAMPLE RANGE const samples = [ { startDate: "2024-09-10", workdays: 10 }, { startDate: "2024-10-26", workdays: 5 }, { startDate: "2024-12-22", workdays: 16 }, ] const respArray = getWorkdayEndDate(samples, weekends_eg, holidays_eg) samples.map((sample, idx) => { sample.endDate = respArray[idx] return sample }) console.table(samples) } runsies() |
The code above is divided into two functions:
The runsies() function
This is the main example run function containing the data samples including the array of start dates and number of required workdays along with the selected days off as an array of days off the week in JavaScript Date days format, and finally the array of holidays.
I’m using the year-month-date
format here, because…computers, but you could use other JS Date acceptable formats.
We then add these data samples to the getWorkdayEndDate function arguments. This will return an array of end dates the same length as the sample array. So we will iterate over the sample array and map our end dates to it before logging the samples
array to see our results which will look like this:
1 2 3 4 5 6 7 |
┌─────────┬──────────────┬──────────┬──────────────┐ │ (index) │ startDate │ workdays │ endDate │ ├─────────┼──────────────┼──────────┼──────────────┤ │ 0 │ '2024-09-10' │ 10 │ '2024-09-23' │ │ 1 │ '2024-10-26' │ 5 │ '2024-11-04' │ │ 2 │ '2024-12-22' │ 16 │ '2025-01-16' │ └─────────┴──────────────┴──────────┴──────────────┘ |
The getWorkdayEndDate() function
Parameters
This function takes 3 arguments:
workdays
: An array of objects containing astartDate
and number ofworkdays
.weekends
: The array of weekends to not count. These are depicted as JavaScript numbers with Sunday starting at zero (0) and ending with Saturday (6). You can add any day of the week here to exclude it from the weekdays.holidays
: This is the array of date strings for each holiday to exclude. You may wish to generate this from a local holiday API relevant to your area and then include any additional days your company might have.
Main variables & UTC DAtes
We need to convert each of our dates into milliseconds to more efficiently compare our time-off periods against our start date and consecutive days.
Line 17 – First, we calculate a whole day in milliseconds.
Line 23-30 – To avoid any weirdness that might occur in our current timezone with any potential daylight-saving events, we will convert our date periods to UTC (Coordinated Universal Time). This will occur a few times within our code so we will add a small private method up here at the top of the function to handle this.
You can see another example of UTC dates in practice here:
Typically, I would abstract this getUTC
function out as a separate function or include it as a prototype, but you’re likely to just copy and paste the function so inside as a method it goes 😉.
Line 33 – Now we can convert the array of dates to UTC time in milliseconds.
Create an array of end dates
Line 38 – Next, we use the JavaScirpt map function to create an array of end dates by iterating over the workdays
array.
For each workday, we need to set some variables that:
- Line 40 –
dayStart
: Set the start date to UTC format. - Line 43 –
dayOfWeek
: Determine the first day of the week for the start day and then allow it to be updated each day. - Line 44 –
daysRemaining
: Set the first day remaining to the number of workdays. We will subtract from this every time we find a workday. - Line 45 –
day
: Set the current day to thedayStart
. This will be updated as we iterate through each consecutive day.
Looping through the remaining days
Line 47 – Our next task is to iterate over the remaining days.
Line 50 – If a date is not a holiday or a weekend then we can subtract one from our remaining days.
Line 53 – If the day remaining then equals zero, we want to break from our loop and record the current day as our end day.
Line 56-57 – Upon each loop over the day except for the last target day, we need to add a day to our current day and then get the next day of the week.
Getting the end date and converting it to a date string.
The last thing we need to do on our map is to return the end date to our array of end dates.
Line 60 – First we convert our day from UTC back into a JavaScript date.
Line 63 – Then we convert that date to a JavaScript ISO string which will display our our UTC date by year month and day in the format that we want. This will also display the time, which we don’t want. So we get the substring of this value by collecting the first 10 characters (YYYY-MM-DD
).
Another example of ISO string data in action:
Create a ISO String from date text input intended for UTC date in JavaScript
Send it back.
Line 67 – Lastly, we send our mapped array of end dates back to runsies.
If you have found the tutorial helpful, why not shout me a coffee ☕? I'd really appreciate it.
It’s always great to see how people use these tutorials and bits of code in their own projects. Feel free to share in the comments below.
~ Yagi
One thought on “Calculate the Workday End Date in JavaScript”