Recurring date using dayjs with dayrs-recur - javascript

I’m willing to create a recurring date based on "nth weekday of month"
Here is my solution work when I select current Date
let dates = {};
const currentDate = dayjs();
const recurrence = currentDate
.recur(dayjs().add(4, "month"))
.every("Wednesday")
.daysOfWeek()
.every(currentDate.monthWeekByDay())
.weeksOfMonthByDay();
recurrence.all().forEach((date) => {
dates[date.format("YYYY-MM-DD")] = { selected: true, };
});
// dates = ["2022-09-21","2022-10-19","2022-11-16","2022-12-21","2023-01-18"]
but if put last day of this month which is 30
let dates = {};
const lastDayofMonth = dayjs().endOf("month");
const recurrence = lastDayofMonth
.recur(dayjs().add(4, "month"))
.every("Friday")
.daysOfWeek()
.every(lastDayofMonth.monthWeekByDay())
.weeksOfMonthByDay();
I was expecting to get
["2022-09-30","2022-10-28","2022-11-25","2022-12-30"..]
instead of
["2022-09-30","2022-12-30"]
Here is demo
Am I missing something ?
Thanks in advance

It possible to create a recurring date based on "nth weekday of month" with dayjs and dayjs-recur as all months as different number of weeks
But there are some challenges:
A month has 4 weeks on average (some months have few or no days for fifth week)
Due to this there may be cases where there is no fifth week or the fifth week doesn't have the nth weekday
To resolve this
If you are getting an nth weekday of month where the week is the last week of the month (could be 4th/5th week)
Get both the nth weekday of month for the last week (5th) and the fourth (4th) week
From the list of dates returned filter if dates for a month occur multiple times and select the latest/greatest one
The filtered result should have the nth weekday of month where the week is the last week of the month
Demo
Below is a link to a working demo forked from #Achraf's demo on code sandbox
Demo Link
Code Example
const lastDayofMonth = dayjs().endOf("month");
const recurrence = lastDayofMonth
.recur(dayjs().add(4, "month"))
.every("Friday")
.daysOfWeek()
.every([3, 4])
.weeksOfMonthByDay();
// filter recurrence
const months = {};
recurrence.all().forEach((date) => {
months[date.month()] = date;
})
// get filtered dates
const filteredDates = Object.values(months);
// formot date into dates object
filteredDates.forEach((date) => {
dates[date.format("YYYY-MM-DD")] = { selected: true, color: "#2FB0ED" };
});
console.log("dates", dates);
// ["2022-09-30","2022-10-28","2022-11-25","2022-12-30"..]

Related

How to get data between today and 7 days before from sequelize?

I create it like this. I couldn't get value for the start date.
var datetime = new Date();
let endDate = (datetime.toISOString().slice(0,10)); // today
const startDate= endDate -7; // 7 days before
const places = await Places.findAll({
where: {createDate: {between : [endDate, startDate]}}
}
);
You can add or subtract whole days from the third parameter of new Date(...):
const startDate = new Date(datetime.getFullYear(),
datetime.getMonth(),
datetime.getDate() - 7).toISOString().slice(0,10);
This works even if the current date is, say, the 6th of a month. The result will then be the last-but-one day of the previous month.

CYPRESS: How to add one month to my current date with consideration to months like February(28 days) and months that have 30 days?

I have this cypress test where Im checking for a correct billing date. Our website has monthly subscriptions and it works as follows:
If you start your subscription on January 31st, your next billing date will automatically be on the 1st of March since February has only 28 days.
Same if you start your subscription on the 31st of March, then your next billing date will be on the first of 1st of May since there is no 31st in April and it automatically changes to the first day of the next month.
Starting on other normal dates like the 15th will always be the same date (15th) of the next month etc..
My issue is when testing this with cypress, i always get the last day of the next month. For example if i test that Im gonna start my subscription on the 31st of March, my test will have 30th of April as an expected result, which is not correct since i want the expected result of my test to be 1st of May.
I am using this function but i cant seem to make it work properly since there are many differences in the months.
export const getBillingDate = (todayDate: string, months: number) => {
const date1 = new Date(todayDate)
const date2 = new Date(todayDate)
date1.setDate(1)
const daysInNextMonth = getDaysInMonth(addMonths(date1, months))
date2.setDate(Math.min(date2.getDate(), daysInNextMonth))
return format(addMonths(date2, months), 'MMMM do, yyyy')
}
I would really appreciate anyone's help with this since i am new to Cypress and testing in general. (Sorry english is not my first language)
Both dayjs and javascript new Date() fail to add all the dates exactly as you want.
But you can use dayjs().daysInMonth() to get results exactly as per your description,
const getBilling = (startDate) => {
const [year, month, day] = startDate.split('/')
const sd = dayjs(startDate)
const firstOfNextMonth = sd.month(sd.month() + 1).date(1)
const daysInNextMonth = dayjs(firstOfNextMonth).daysInMonth()
let end;
if (daysInNextMonth < day) {
end = `${year}/${+month+2}/${1}` // always bump to 1st day of month + 2
} else {
end = `${year}/${+month+1}/${day}`
}
return dayjs(end, 'YYYY/MM/DD').format('YYYY/MM/DD')
}
it('gets billing date, accounting for short months', () => {
//Jan
expect(getBilling('2022/01/15')).to.eq('2022/02/15')
expect(getBilling('2022/01/31')).to.eq('2022/03/01')
//Feb
expect(getBilling('2022/02/15')).to.eq('2022/03/15')
expect(getBilling('2022/02/28')).to.eq('2022/03/28')
//Mar
expect(getBilling('2022/03/15')).to.eq('2022/04/15')
expect(getBilling('2022/03/31')).to.eq('2022/05/01')
})
Day.js already exists to do date math.
You can use their .add() to add 30 days to a date dayjs().add(30, 'day').
You can also format the dates with .format() to format the way you want it dayjs('2019-01-25').format('DD/MM/YYYY') // '25/01/2019'
Your requirements are a little unusual. Typically when adding a month and it overflows, the requirement is to return the last day of the month, not the first of the following month. But it's not difficult, just get the starting date (day in month), add a month, and if the resulting date isn't the same, set it to the 1st, e.g.:
function addBillingMonth(date = new Date()) {
let d = new Date(+date);
let dayNum = d.getDate();
d.setMonth(d.getMonth() + 1);
if (dayNum !== d.getDate()) {
d.setDate(1);
}
return d;
}
// Examples
[ new Date(2021,11,31), // 31 Dec
new Date(2022, 0,15), // 15 Jan
new Date(2022, 0,31), // 31 Jan
new Date(2022, 2,31), // 31 Mar
].forEach(d => console.log(d.toDateString() +
' next bill: ' + addBillingMonth(d).toDateString())
);
You have a months parameter, if you want to increase by more that one month you should calculate each month separately.
'dayjs` definitely gives you more options to play with.
const expect = chai.expect
const addBillingMonth = (start) => {
let next = start.add(1, 'month')
if (start.date() !== next.date()) {
next = next.add(1, 'month').startOf('month')
}
return next
}
const getBilling = (startDate, months = 1) => {
let result = dayjs(startDate)
for (let i = 0; i < months; i++) {
result = addBillingMonth(result) // repeat for each month
}
return result.format('YYYY/MM/DD')
}
expect(getBilling('2022/01/15')).to.eq('2022/02/15')
expect(getBilling('2022/01/31')).to.eq('2022/03/01')
expect(getBilling('2022/02/15')).to.eq('2022/03/15')
expect(getBilling('2022/02/28')).to.eq('2022/03/28')
expect(getBilling('2022/03/15')).to.eq('2022/04/15')
expect(getBilling('2022/03/31')).to.eq('2022/05/01')
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/4.3.6/chai.min.js"></script>
<script src="https://unpkg.com/dayjs#1.8.21/dayjs.min.js"></script>

How to check is today a working day (mon-fri)

I'm searching to method how to check is today a working day monday-friday. I'm using moment.js. I'm getting today date as moment()
You can still use moment
const today = moment().format('dddd')
This will return the date string.
If you want the today week number than :
const today = moment().day();
which returns a number between 0 - 6
So day 6 and 0 are non working days.
I would wrap it in a function
function isWorkDay(date = moment()){
const day = moment(date).day())
return day && day < 6
}

MomentJS - how to select all days of the week by name?

How to sellect all same weekdays by using momentJS? Ex: All Mondays of current month. If the day is 15th day of the month, there are two Mondays in that month, from 0 to 15th day of the month. Maybe it is some kind of looping, because momenthJS should return two dates-one for first Monday and second for second Monday in the given range and so on.
Or is there any other way to do this by using any other JavaScript library?
As you said a loop can solve this problem
move 4 weeks before from the date you have e.g. if we were on the last monday of the month we move to the first monday of the month or a previous date (if we move to the previous month we can still get the correct dates by doing more iterations)
get the month of the date you have (all the dates you get should have the same month)
move forward from the initial date computed above a week each time and check if the new date has the same month as the input date
function weekdaysFromMonth (date) {
// all the weekdays previous/next to date should be
// 7 days apart and also have the same month
var month = date.get('month')
// make sure that the start date is 4 weeks before now
// we might go to the previous month but anyway we'll
// get the correct dates by doing more iterations
var start = moment(date).subtract(4 * 7, 'days')
var dates = []
for (var i = 0; i < 10; i += 1) {
start.add(7, 'days')
if (start.get('month') === month) {
dates.push(moment(start))
}
}
return dates
}
document.write(
JSON.stringify(
weekdaysFromMonth(moment()), null, ' '
)
)
<script src="http://momentjs.com/downloads/moment.js"></script>

MomentJS - How to get last day of previous month from date?

I'm trying to get last day of the previous month using:
var dateFrom = moment(dateFrom).subtract(1, 'months').format('YYYY-MM-DD');
Where:
dateFrom = 2014-11-30
But after using
subtract(1, 'months')
it returns date
DATE_FROM: "2014-10-30"
But last day of the 10'th month is 31.
How can I solve i please?
Many thanks for any help.
Simply add a endOf('month') to your calls:
var dateFrom = moment(dateFrom).subtract(1,'months').endOf('month').format('YYYY-MM-DD');
http://jsfiddle.net/r42jg/327/
An even easier solution would be to use moment.date(0). the .date() function takes the 1 to n day of the current month, however, passing a zero or negative number will yield a dates in the previous month.
For example if current date is February 3rd:
var _date = moment(); // 2018-02-03 (current day)
var _date2 = moment().date(0) // 2018-01-31 (start of current month minus 1 day)
var _date3 = moment().date(4) // 2018-02-04 (4th day of current month)
var _date4 = moment().date(-4) // 2018-01-27 (start of current month minus 5 days)
console.log(_date.format("YYYY-MM-DD"));
console.log(_date2.format("YYYY-MM-DD"));
console.log(_date3.format("YYYY-MM-DD"));
console.log(_date4.format("YYYY-MM-DD"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.js"></script>
Last month's First date and last month's last date from the current date basis. The Format of the date changes depending upon. (DD-MM-YYYY)
console.log("last month first date");
const lastmonthlastdate=moment().subtract(1, 'months').startOf('month').format('DD-MM-YYYY')
console.log(lastmonthlastdate);
console.log("lastmonth last date");
const lastmonthfirstdate=moment().subtract(1, 'months').endOf('month').format('DD-MM-YYYY')
console.log(lastmonthfirstdate);
moment().subtract(1, 'months').endOf('month').format('YYYY-MM-DD')
You can get the first day of the month then subtract 1 day to get the last day of the previous month.
const monthyear = moment().format('YYYY-MM')
const firstDay = moment(monthyear + "-01").format("YYYY-MM-DD");
// Subtract 1 day to get the end of the previous month
const dateTo = moment(firstDay).subtract('1', 'days').format("YYYY-MM-DD");

Categories

Resources