Is there a way to find the Nth occurrence of a specific weekday in each month between two given dates using JavaScript?

Within my program, users can set events with start and end dates, as well as the period of repetition: weekly, monthly by date, monthly by weekday, or yearly. Once an event is created, it's stored in the database and displayed on the main calendar page.

I've successfully implemented algorithms for repeating events weekly, monthly by date, and yearly. However, I'm facing a challenge with monthly repetition based on weekdays. This refers to events that occur on the same weekday each month between the specified start and end dates.

For instance, an event might repeat on the first Monday of every month from March 1st to November 1st. The goal is to generate dates like April 5th (the first Monday in April) and continue this pattern until November.

The function below handles monthly repetition by date for events occurring on the 15th of any month:

function repeatEventMonthly(jsonArray, num){

// Extracting start and end dates from JSON and creating Date objects

var split = jsonArray[num].Fecha.split("/");
var split2 = jsonArray[num].fechaFin.split("/");

var dd = split[1];
var mm = split[0];
var yy = split[2];

var dd2 = split2[1];
var mm2 = split2[0];
var yy2 = split2[2];

var starDate = new Date();
var endDate = new Date();

starDate.setFullYear(yy);
starDate.setMonth(mm-1);
starDate.setDate(dd);
endDate.setFullYear(yy2);
endDate.setMonth(mm2-1);
endDate.setDate(dd2);

// Calculating days between start and end date

var top = getDaysInDates(starDate, endDate);

if (jsonArray[num].tipoRepeticion == "2") {

 // Handling Monthly by Weekday

}else if(jsonArray[num].tipoRepeticion == "3"){

    // Generating dates for Monthly by Date
    
    for (let index = 0; index < top; index++) {
        let sd = new Date(starDate);
        sd.setDate(sd.getDate()+index);
        if (sd.getDate() == starDate.getDate()) {
            let str = ((sd.getMonth()+1) + "/" + sd.getDate() + "/" + sd.getFullYear()).toString();
            eventMen.push({
                date: constructDates(str, 0, jsonArray[num].tipoRepeticion),
                title: jsonArray[num].titulo,
                descripcion: jsonArray[num].descripcion,
                tipo: jsonArray[num].tipo,
                tipoRepeticion : jsonArray[num].tipoRepeticion
            });
        }
    }
}

This function effectively generates events one month apart on the same date, such as repeating an event on the 3rd of each month between March and December. While I have tackled other types of recurring dates successfully, calculating monthly repetition by weekday poses a greater challenge due to varying month lengths. For example, determining the "first Monday of a month" requires more complex logic compared to fixed-date repetitions. Any suggestions or solutions on how to address this issue would be greatly appreciated. Additionally, there are various scenarios for monthly recurrence, not just limited to the "first Monday" but also involving the second Tuesday or last Friday of each month.

Answer №1

In order to retrieve the Nth occurrence of a specific day within a month, begin by setting a date for the first day of that month, then navigate to the first occurrence of the desired day and add (N-1) weeks' worth of days.

/* Function to obtain the Nth instance of a particular weekday in a month
 *
 * @param {number|string} nth - the Nth instance of the day (1 to 4)
 * @param {number|string} day - the day of the week (Sun 0, Mon 1, etc.)
 * @param {Date} month - any date within the target month
 * @returns {Date} representing the Nth instance of the specified day in the month
*/
function getNthDayInMonth(nth, day, month) {
  // Create a new date object for the 1st day of the month
  let d = new Date(month.getFullYear(), month.getMonth());
  // Move to the first instance of the day in the month and 
  // add (N - 1) weeks
  d.setDate(1 + (7 - d.getDay() + day)%7 + (nth - 1)*7);
  return d;
}

// Formatter
let f = (d) => new Intl.DateTimeFormat('en-GB', {
  weekday:'short',
  day:'2-digit',
  month:'short',
  year: 'numeric'
}).format(d);

// Examples
[[1,1,new Date(2021,11),'1st Mon in Dec 2021'],
 [3,3,new Date(2022, 0),'3rd Wed in Jan 2022'],
 [4,1,new Date(2022, 1),'4th Mon in Feb 2022'],
 [4,2,new Date(2022, 1),'4th Tue in Feb 2022'],
 [4,3,new Date(2022, 1),'4th Wed in Feb 2022'],
 [1,3,new Date(2022, 5),'1st Wed in Jun 2022'],
 [5,5,new Date(2022,11),'5th Fri in Dec 2022']
].forEach(a => {
  let [n,d,m,note] = a;
  console.log(`${note}: ${f(getNthDayInMonth(n,d,m))}`);
});

Each day in a month has at least 4 instances, with some having up to 5 occurrences (e.g. there are 5 Saturdays, Sundays, and Mondays in Jan 2022). The value of Nth may be restricted to 4, or extended to 5 only after ensuring it aligns with the end month being the same as the start month. If not, consider throwing an error or returning undefined.

To obtain all Nth days across months between two given dates, iterate through the months to extract the Nth instances, filtering out any dates falling before the start or beyond the end.

Answer №2

Find the day of the week for the first day of the month, then calculate the number of days until the desired day of the week. Proceed by adding multiples of 7 to reach the desired date.

For instance:

const startDate = new Date("2021-03-01"); // Mon Mar 01 2021
const friday = 5;        // Friday is the 5th day (Monday is 1)
const weekOfMonth = 2;   // Targeting the 3rd week (1st week is 0)

// Initiate calculations
const dayOfWeek = startDate.getUTCDay(); // 1
const diff = friday - dayOfWeek;         // 4
const dateOf3rdFriday = new Date(
    startDate.getUTCFullYear(),
    startDate.getUTCMonth(),
    startDate.getUTCDay() + diff + 7 * weekOfMonth
); // Fri Mar 19 2021

When aiming for the last Friday of the month, follow a similar approach in reverse.

Answer №3

How to Find the nth Day of a Month Efficiently

Discover a unique approach that leverages a human-readable string while handling the 4th and 5th occurrences of a day within a month.

The user-friendly string format is exemplified as "1st Sun Dec" denoting a specific date.

If the final occurrence (the 5th instance) falls in the subsequent month, the second-to-last occurrence assumes the role of the last occurrence.

function nthDayInMonth(str , y) {
let days    = ["sun","mon","tue","wed","thu","fri","sat"],
    months  = ["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"],
       pos  = ["1st","2nd","3rd","4th","last"],
[nth,day,m] = str.replace(/\s+/g," ").trim().toLowerCase().split(" ");
m  = months.indexOf(m);
let d = new Date(Date.UTC(y,m,1)),
    n = 1 + (7 - d.getDay() + days.indexOf(day))%7 + pos.indexOf(nth)*7;
d.setUTCDate(n);
return d.getUTCMonth()==m ? d : new Date(Date.UTC(y,m,n-7));
}
//================ tests ==========================
console.log(nthDayInMonth("1st Sun Dec",2023));  // 2023-12-03
console.log(nthDayInMonth("2nd Sun Dec",2023));  // 2023-12-10
console.log(nthDayInMonth("4th Sun Dec",2023));  // 2023-12-24
console.log(nthDayInMonth("last Sun Dec",2023)); // 2023-12-31
console.log(nthDayInMonth("Last   mon   dec",2023)); // 2023-12-25
console.log(nthDayInMonth("4th Sun Nov",2023));  // 2023-11-26 same as Last Sun Nov
console.log(nthDayInMonth("Last Sun Nov",2023)); // 2023-11-26 same as 4th Sun Nov

A Versatile Function to Identify the nth Day of a Month within a Date Range

The previous function can be slightly adapted to retrieve the nth Days of the Month within 2 provided dates.

This revised function yields an array containing the respective dates.

For instance, the following test cases showcase extracting the dates for the 1st Monday of each Month throughout 2023 and then identifying the dates for the last Friday of each Month during 2024.

function nthDayInMontBetweenDates(str,d1,d2) {
let days    = ["sun","mon","tue","wed","thu","fri","sat"],
       pos  = ["1st","2nd","3rd","4th","last"];
d1=new Date(d1); d2=new Date(d2);
let     m = d1.getUTCMonth(), arr=[],
[nth,day] = str.replace(/\s+/g," ").trim().toLowerCase().split(" ");
        y = d1.getFullYear();
while (d1<=d2) {
let d = new Date(d1),
    n = 1 + (7 - d.getDay() + days.indexOf(day))%7 + pos.indexOf(nth)*7;
    d.setUTCDate(n);
    arr.push(d.getUTCMonth()==m ? d : new Date(Date.UTC(y,m,n-7)));
    m++;
    m>11 && (m=0,y++);
    d1=new Date(Date.UTC(y,m,1));
}
return arr
}

console.log(nthDayInMontBetweenDates("1st Mon" ,"2023-01","2023-12"));
console.log(nthDayInMontBetweenDates("last fri","2024-01","2024-12"));

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Retrieving component layout from file

Storing the component template within inline HTML doesn't seem very sustainable to me. I prefer to load it from an external file instead. After doing some research, it appears that utilizing DOMParser() to parse the HTML file and then incorporating th ...

What is the best way to combine a string with a variable in sass?

Is there a way to merge a string and a variable in Sass to form a variable name that is already present? $size: "sm"; $button-sm: 1rem; $buttom-md: 1.5rem; body { font-size: $button-#{$size}; } The desired output is: body { font-size: 1r ...

Angular component with optional one-way binding for version 1.5 and above

Copied from the official AngularJS 1 documentation: To make a binding optional, simply add ?: <? or <?attr. What are the differences between the optional and non-optional one-way bindings? I can't seem to find the dissimilarities for the op ...

Display only one dropdown menu at a time

Hey there, I'm currently working on a dropdown menu and struggling to figure out how to keep only one item open at a time. I've tried using an array with useState for all my dropdowns but haven't been able to find a solution yet: code co ...

What could be causing my React function to be declared but not utilized?

Struggling with my React project, I hit a roadblock when trying to import my generalInput file into my App file. The error message stated that the generalInput was declared but never read. Desperate for a solution, I even turned to AI for help, but it too ...

navigate a specific web address using Express routing

Is there a specific regex pattern that should be used in an Express application to match a URL? For example, if the endpoint is www.mydomain.com/v1/https://www.url-to-be-matched.com. I am aiming to accept https://www.url-to-be-matched.com as parameters. H ...

How to extract latitude and longitude data from a JSON file on an Android device

An edited version of the previous question, previously answered by @santalu. Great work! Now, I have a new query regarding accessing data from a JSON file obtained through the following function. My goal is to develop an application that showcases all tour ...

How can I add seconds to the jquery datetimepicker plugin?

Looking to implement the datetimepicker plugin from here, but I'm having trouble finding information on how to include the seconds part. Is there a way to add seconds to this plugin? It's a crucial requirement, so any suggestions for another good ...

conceal elements using the <option> class隐藏

Although it seems like a simple task, I'm struggling to make it work. I created a form where the user can select a month from a list using the tags: <select> <option> When the selection is changed, the class .gone from the day SELECT is ...

Setting a default currency value (either in dollars or euros) in an input field

Is there a way to automatically insert a currency symbol (€, $) in a text field by default when entering a number? Are there any default values for this feature? Thank you Here is an example ...

Shortcut for JSON formatting in Sublime Text

I prefer using SublimeText for coding. Is there a quick way to reindent JSON code in SublimeText? I've successfully installed Package Control and it's functioning properly. I attempted to use the JsonReindent package, but couldn't find a ...

Is it possible to transfer the style object from PaperProps to makeStyles in Material UI?

I am working with a Material UI Menu component and attempting to customize its border. Currently, I am only able to achieve this customization by using PaperProps inline on the Menu element. However, I already have a makeStyles object defined. Is there a ...

Receive regular position updates every second in React Native

Currently, my code is functional but lacks reliability. I often encounter delays and sometimes it doesn't update at all. My goal is to achieve real-time position updates. To accomplish this, I have utilized the setInterval() function within the compon ...

Ways to identify when a file download has finished with the help of javascript

let pageUrl = "GPGeneration_Credit.ashx?UniqueID=" + __uniqueId + "&supplierID=" + supplierID + "&CreditID=" + OrderIds; window.open(pageUrl); // Want to check if the file download is complete and then refresh the page location.r ...

Issues with JavaScript Content Loading in epub.js on a Website

Hey there, I'm currently experimenting with the epub.js library and trying to set up the basics. However, I'm encountering an issue where the ebook is not showing up in my browser: <!DOCTYPE html> <html lang="en"> <head&g ...

Looking to transmit metadata in JSON format for Paystack integration

Lately, I've been exploring Paystack which is quite similar to Stripe. However, I'm encountering some difficulties with including metadata in my transactions. Despite following the instructions and adding it to my dashboard, I seem to have hit a ...

Looking for assistance with overriding kendo UI validation requirements

I'm looking to customize the date validation in my code to validate the date as DD/MM/YYYY. Here's my current code snippet and I'm getting an error message that says: Unable to get property 'methods' of undefined or null referen ...

Tips on building an immersive interactive panoramic website

I have a vision for a website that will simulate being in a room, where users can explore the space with limited panoramic views - allowing them to look up/down 30 degrees and left/right 45 degrees. In addition, I would like to integrate interactive object ...

Tips for securely integrating freelancers into your web project

Looking for a secure way to bring in freelancers to assist with tasks on our website, where the freelancer only has write access to specific pages. I'm aware that this can be done with tools like Windows Team Foundation Server. However, I need the fr ...

Using Jest to mock a single function within a class

I'm a beginner when it comes to node and javascript, and I am currently attempting to create a unit test using jest where I only need to mock one function of a class (and object). Below is the code template I am using: // myModule.js class MyModule ...