How to get all particular weekDays between two date objects in momentJS - javascript

How can I get all weekDays(a particular weekday concerned) between a start Date and an end date inclusively. The function would take startDate, endDate (both as moment objects), dayNum(as integer)(0 - Sun, 1 - Mon ... 6 - Sat) and return a list of moment objects of such days.
I have written a function but it is not working.
const getDates = (startDate, endDate, dayNum) => {
let realStart = moment(startDate);
let end = moment(endDate);
let start = realStart.clone();
start.add(-15, "days");
let result = [];
var current = start.clone();
current.day(dayNum + 1);
while (current.isSameOrBefore(end)) {
if (current.isSameOrAfter(realStart)) {
let temp = current.clone();
result.push(temp);
current.day(8 + dayNum);
} else {
current.day(8 + dayNum);
}
}
return result;
};

rzr_f's answer always increments one day at a time, which is inefficient when there is a large span between startDate and endDate, or when the function is called repeatedly.
Here is a more efficient version which increments by 7 days at a time, and never has to check whether the date it's adding is on the correct weekday since it always starts on the correct weekday:
const getDates = (startDate, endDate, dayNum) => {
let current = moment(startDate)
const end = moment(endDate)
const results = []
// If current is on the wrong weekday, move it forward to the first matching weekday:
if (current.weekday() !== dayNum) {
current.add(dayNum >= current.weekday() ? ( dayNum - current.weekday() ) : ( 7 - ( current.weekday() - dayNum ) ), 'day')
}
while(current.isSameOrBefore(end)) {
results.push(current.clone())
current.add(7, 'day')
}
return results
}

I think something like this would work for what you're trying to do:
const getDates = (startDate, endDate, dayNum) => {
let current = moment(startDate)
const end = moment(endDate)
const results = []
while(current.isSameOrBefore(end)) {
if (current.weekday() === dayNum) results.push(current.clone())
current.add(1, 'day')
}
return results
}

Related

Split month into first and second half based on current date and return weekdays (JS)

perhaps someone can give me some good ideas of how to accomplish this.
I would like to get the weekdays for either the first two weeks or last two weeks of a month based on the current date.
So if we are using the following to get the date today (2022-07-06)
const current = new Date();
const date = `${current.getFullYear()}-${current.getMonth()+1}-${current.getDate()}`;
The results I would be looking for are
const firstHalfWeekdates = ['2022-07-04', '2022-07-05', '2022-07-06', '2022-07-07', '2022-07-08', '2022-07-11', '2022-07-12', '2022-07-13', '2022-07-14', '2022-07-15']
and if the date fell on 2022-07-18 it would return
const secondHalfWeekdates = ['2022-07-18', '2022-07-19', '2022-07-20', '2022-07-21', '2022-07-22', '2022-07-25', '2022-07-26', '2022-07-27', '2022-07-28', '2022-07-29']
Also happy to use a library
Maybe this can give you a start. It returns the weekdays, divided by week.
I was trying to do everything you asked, but I ran into some problems, for example you want to divide the month into 4 weeks, 2 in the first half and 2 in the second half, but for example this month now July/2022, has a week that has only one weekday (July 1º), but in your expected results you ignored this week, whats the logic to ignore weeks? It has to be a complete week with 5 weekdays?
What about last month Jun/2022, there were not 4 complete weeks, there were only 3 complete weeks, the other 2 has 3 and 4 days respectively, which week would you ignore in this case?
function isWeekDay(day) {
return day != 0 && day != 6;
}
function formatDateYYYYMMDD(date) {
let dateString = date.toLocaleDateString('en-GB');
let year = dateString.substring(6, 10);
let month = dateString.substring(3, 5);
let day = dateString.substring(0, 2);
return `${year}-${month}-${day}`;
}
function getWeekdaysOfTheCurrentMonthDividedByWeek() {
let currentDate = new Date();
let month = currentDate.getMonth();
let weekdays = [];
let tempDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1);
let week = [];
while (tempDate.getMonth() == month) {
if (isWeekDay(tempDate.getDay())) {
week.push(formatDateYYYYMMDD(tempDate));
} else if (week.length > 0) {
weekdays.push(week);
week = [];
}
tempDate.setDate(tempDate.getDate() + 1);
}
return weekdays;
}
console.log(getWeekdaysOfTheCurrentMonthDividedByWeek());
You could split the month up into calendar weeks. (e.g. for July 2022 it would be: July 1-2, 3-9, 10-16, ect…)
Then, depending on the day, take either the first or second half of the weeks.
Iterate over the filtered weeks, counting the weekdays.
I choose to include the third week in the first half of the month if there were 5 weeks, but you could change that by changing Math.ceil to Math.floor
/**
* Get the last item in an array, or undefined if the array is empty.
* #template T
* #param {[T]} array
* #returns {T|undefined}
*/
const lastItem = array => array[array.length - 1];
const getWeekdays = current => {
/** #type {[[Date]]} */
const weeks = [];
// Get the weeks
/**
* Get the calendar week of the given date.
* #param {Date} firstDay The first day of the week.
* #returns {[Date]}
*/
const getWeek = firstDay => {
/** #type {[Date]} */
let days = [];
let dateToTest = new Date(firstDay);
// Continue until the end of the week or month, whichever comes first.
while (
dateToTest.getDay() <= 6 &&
dateToTest.getMonth() == firstDay.getMonth()
) {
days.push(new Date(dateToTest));
dateToTest.setDate(dateToTest.getDate() + 1);
}
return days;
};
// The first day of the month
const firstDay = new Date(current.getFullYear(), current.getMonth());
let dateToTest = new Date(firstDay);
do {
weeks.push(getWeek(dateToTest));
dateToTest = new Date(lastItem(lastItem(weeks)));
dateToTest.setDate(dateToTest.getDate() + 1);
} while (dateToTest.getMonth() == firstDay.getMonth());
// Filter to half of the month
// Get the week of the given date
let currentWeek = 0;
weekLoop: for (let i = 0; i < weeks.length; i++) {
const week = weeks[i];
for (const day of week) {
if (day == current) {
currentWeek = i;
break weekLoop;
}
}
}
/** #type {[[Date]]} */
let weeksInHalf = [];
const numOfWeeksInFirstHalf = Math.ceil(weeks.length / 2),
numOfWeeksInSecondHalf = weeks.length - numOfWeeksInFirstHalf;
for (
let i = 0;
i <
(currentWeek < numOfWeeksInFirstHalf
? numOfWeeksInFirstHalf
: numOfWeeksInSecondHalf);
i++
) {
weeksInHalf.push(weeks[i]);
}
// Filter out weekends
// Format dates
return weeksInHalf
.flat()
.filter(day => day.getDay() > 0 && day.getDay() < 6)
.map(
day => `${day.getFullYear()}-${day.getMonth() + 1}-${day.getDate()}`
);
};
// Tests
for (let i = 0; i < 12; i++) {
const weekdays = getWeekdays(new Date(2022, i));
weekdays.forEach(dateString => {
const [year, month, day] = dateString.split("-");
const date = new Date(year, month - 1, day);
if (date.getDay() == 0 || date.getDay() == 6)
throw new Error("Invalid day: (day)");
else console.log(dateString)
});
}

Suggest Next available date(closest) but don't suggest dates which are in array

I have a list of array exdate which has some date. I want to exclude those dates and suggest the next available date from today. Date should not be random.
const exdate = ["24/08/2020", "8/8/2020"] //dates needs to be excluded [DD/MM/YYYY]
The newly generated date would be "25/08/2020" which is the closest one and not in the array.
This post has a question that is generating a random date using math.random function but my scenario is different.
Iterate inside a while loop and check if exdate contains the current date. If it doesnt contain the date, add 1 day to the current date and check it again. If the current date is not present inside the exdate array, exit the while loop and print the value.
A thing you might consider: What is the expected format of your dates? You should make sure it stays consistent. e.g. dont use leading 0s in front of months. My answer should point you into the right direction.
exdate = ['24/8/2020', '8/8/2020'];
let currDate = new Date();
let dd = currDate.getDate();
let mm = currDate.getMonth() + 1;
let y = currDate.getFullYear();
let dateFormat = dd + '/' + mm + '/' + y;
while (true) {
dd = currDate.getDate();
mm = currDate.getMonth() + 1;
y = currDate.getFullYear();
dateFormat = dd + '/' + mm + '/' + y;
if (!exdate.includes(dateFormat)) break;
currDate.setDate(currDate.getDate() + 1);
}
console.log(dateFormat);
I think this code does what you are after and is quite simple:
import moment from "moment";
// Constants
const dateFormat = 'DD/MM/YYYY'
// Utils
const strToDate = (date) => moment(date, dateFormat)
const dateToStr = (date) => date.format(dateFormat)
const sortByMoment = (a, b) => b.diff(a)
const incrementDate = (date) => date.add(1, 'day')
const isToday = (date) => moment().isSame(date, 'day')
// Data
const exdate = ["17/08/2020", "24/08/2020", "8/8/2020"];
// Implementation
const sortNewestToOldest = (data) => data
.map(strToDate)
.sort(sortByMoment)
const nextAvailableDate = ([head]) => isToday(head) ? [dateToStr(incrementDate(head))] : [dateToStr(moment())]
nextAvailableDate check if todays date is in the exdate list, if yes return tomorrow, else return today. If you also had future dates in there that you need to accomodate for you could expand isToday to be isTodayOrInTheFuture. The moment functions you would need can all be found here.

Javascript array.filter changing type

The below function is inside a React Class Component.
When the function is called this.state.data.Date type changes to Date when originally it was a string. I need this to be a String and confused on how to prevent this from happening?
getYear = e => {
let year = e.target.value;
let start = new Date("01/01/" + year);
let end = new Date("12/31/" + year);
let filtered = this.state.data.filter(data => {
let day = data.Date.slice(0, 2);
let month = data.Date.slice(3, 5);
let year = data.Date.slice(6, 10);
return (
new Date(year, month, day) >= start && new Date(year, month, day) <= end
);
});
this.setState({ setData: filtered });
};

Get date/times between two Moment date/times

I am using Node.JS and the excellent Moment library. I have a function that needs to generate an agenda of future dates (like an appointment system)
I have two timestamps representing the start and end of a period of time.
I want to create an array of date/times between these two times, dependent on a specific day and time of that day.
An example would be:
START DATE: 2019-01-26 15:00:01 (Saturday)
END DATE: 2019-02-23 15:00:00 (also a Saturday)
WE NEED: EVERY SATURDAY # 1500
EXPECTED ARRAY:
2019-02-02 15:00:00
2019-02-09 15:00:00
2019-02-16 15:00:00
2019-02-23 15:00:00
Please note: The start is not included in the array because it is later (by one second) than what we are looking for.
Any idea on how to accomplish this in Node?
const moment = require('moment')
const formatDate = date => moment(date).format('MMMM Do YYYY, h:mm:ss a')
const START_DATE = '2019-01-26 15:00:00'
const END_DATE = '2019-02-23 15:00:00'
let current = formatDate(START_DATE)
const end = formatDate(END_DATE)
let days = 7
let result = []
while (current > end) {
current = moment(START_DATE).add(days, 'days')
current = formatDate(current)
result.push(current)
days += 7
}
result.push(end)
result.forEach(date=>console.log(date))
import moment from 'moment';
const getDaysBetween = (startDate, endDate, day, time) => {
// Define a first day of result
let firstDay = moment(startDate)
.day(day)
.set('hour', time.match(/[\d]+(?=:)/g)[0])
.set('minutes', time.match(/(?<=:)[\d]+/g)[0])
.set('seconds', 0);
let resultDates = [ firstDay ];
// Add the rest
let weekBetweenThese = endDate.diff(firstDay, 'week');
Array(weekBetweenThese).fill({}).forEach((d, i) => {
resultDates.push(moment(firstDay).add(i + 1, 'weeks'))
});
// Filter out somecase that result day match with startDate & endDate but time condition goes wrong
resultDates = resultDates.filter(resultDate =>
startDate <= resultDate &&
resultDate <= endDate
);
return resultDates.map(resultDate => resultDate.toDate());
// return resultDates; // Return array of moment date.
};
console.log(
getDaysBetween(
moment('2019-01-26 15:00:01'),
moment('2019-02-23 15:00:00'),
'Saturday', '15:00'
)
)
https://codesandbox.io/s/wkpz72mo9w

MomentJS getting previous dates relative to today

Is there anyway to get the days past the current day using MomentJS?
For example suppose it is January 5, 2018, how would I get the previous dates from January 1, 2018 through to January 5, 2018 ?
My current code looks like this:
const monthArr = [];
const dayArr= [];
const currentDate = moment(new Date()).format("DD");
for (let i = 0; i < +currentDate; i++) {
const month = moment(new Date())
.subtract(i, "day")
.format("MMYYYY");
const day = moment(new Date())
.subtract(i, "day")
.format("MMDDYYYY");
console.log("month" + month);
console.log("day" + day);
let monthObj = {};
let dailyObj = {};
monthArr.push(
(monthObj = {
data: {
[month]: Object.assign({}, document)
}
})
);
day.push(
(dailyObj = {
data: {
[day]: Object.assign({}, document)
}
})
);
monthly(user_id, monthArr[i]) &&
daily(user_id, dayArr[i]);
}
The code in the OP seems very inefficient and far more complex than required.
To generate a series of formatted strings for dates from today to the start of the month only needs one Date and some very simple arithmetic and formatting. It really doesn't need a library nor any date arithmetic, e.g.
// Pad single digit number with leading zero
function pad(n){
return (n < 10? '0' : '') + n;
}
var today = new Date(),
year = today.getFullYear(),
month = pad(today.getMonth() + 1),
day,
i = today.getDate();
do {
day = pad(i);
console.log(`Month: ${month + year}`);
console.log(`Day: ${month + day + year}`);
} while (--i)
There are a number of other issues with your code, but they're not directly related to the question.

Categories

Resources