在纯Javascript中,我试图生成两个日期,一个next
和一个following
。我需要将这些日期生成为当月的最后一个星期五,其中next
将是当月的最后五(除非在月末的7天内,然后是下个月(,following
也一样,仅比next
提前一个月。
我的JS现在有几个助手函数,我已经编写了这些函数来将逻辑的一部分提取到可重用的部分中,并通过我的getPaydates
paydates函数进行调用。
然而,现在我的next
和following
似乎是错误的,例如:
provided date: 2021-06-01
next: 2021-06-24, following: 2021-07-24 (both wrong)
should be: 2021-06-25 (next) and 2021-07-30 (following)
provided date: 2021-06-25
next: 2021-08-24, following: 2021-10-24 (both wrong)
should be: 2021-07-30 (next) and 2021-08-27 (following)
我的代码中缺少什么?我有一个JS小提琴复制,可以查看,但我也会在这里添加代码:
/*
** Get days left in a month
**
** Get the number of days left in a month
*/
function getDaysLeftInMonth (date) {
const daysInMonth = getDaysInMonth(getCurrentYear(date), getCurrentMonth(date))
let left = getDateDiffInDays(date, getEndOfMonth(getCurrentYear(date), getCurrentMonth(date)))
if (left <= 0) left = 0
return left
}
/*
** Get Days In Month
**
** Get the number of days in a given month & year.
*/
function getDaysInMonth (year, month) {
// January is: 1
// 0 is the last day of the month
return new Date(year, month, 0).getDate()
}
/*
** Get end of month
**
** Get the date for the end of the month
*/
function getEndOfMonth (year, month) {
const lastDay = new Date(year, month + 1, 0)
return lastDay
}
/*
** Get Current Year
**
** Get the current year that we're in.
*/
function getCurrentYear (now = new Date()) {
return new Date(now).getFullYear()
}
/*
** Get Current Month
**
** Get the current month that we're in
*/
function getCurrentMonth (now = new Date()) {
return new Date(now).getMonth()
}
/*
** Add Months to date
**
** Add months to a date and move date forward
*/
function addMonthsToDate (date = new Date(), months = 0) {
const d = date.getDate()
date.setMonth(date.getMonth() + months)
if (date.getDate() != d) {
date.setDate(0)
}
return date
}
/*
** Add days to date
**
** Add days to date and return the date
*/
function addDaysToDate (date = new Date(), days = 0) {
const today = new Date(date)
today.setDate(today.getDate() + days)
return today
}
/*
** Difference between two dates
**
** Get the difference between two dates
*/
function getDateDiffInDays (start, end) {
const diffTime = end.getTime() - start.getTime()
const diffDays = Math.ceil(diffTime / (1000 * 3600 * 24))
return diffDays
}
/*
** Last Friday of Month
**
** Get the last friday of the month where the given year
** and month is provided
*/
function getLastFridayOfMonth (year, month) {
let lastDay = new Date(year, month + 1, 0)
lastDay.setDate(lastDay.getDate() - (lastDay.getDay() + 2) % 7)
return lastDay
}
/*
** Reverse date string
**
** Reverse date string, assumes already formatted date
*/
function reverseDateStr (str) {
return str.split('/').reverse().join('/')
}
/*
** Calculate paydates
**
** Programatically calculate the paydates
*/
function getPaydates (now = new Date()) {
const month = getCurrentMonth(now)
const year = getCurrentYear(now)
const lastFriday = getLastFridayOfMonth(year, month)
let next = new Date(lastFriday).toISOString().substr(0, 10)
let following = new Date(addMonthsToDate(lastFriday, 1)).toISOString().substr(0, 10)
if (getDaysLeftInMonth(now) <= 7) {
next = new Date(addMonthsToDate(lastFriday, 1)).toISOString().substr(0, 10)
following = new Date(addMonthsToDate(lastFriday, 2)).toISOString().substr(0, 10)
}
return {
next: reverseDateStr(next).split('/').join('-'),
following: reverseDateStr(following).split('/').join('-')
}
}
console.log(getPaydates(new Date('2021-06-01')))
更新
奇怪的是,如果我在getPaydates
函数中控制台记录next
和lastFriday
,一个结果在技术上是正确的,而另一个结果是一天?
const lastFriday = getLastFridayOfMonth(year, month)
let next = new Date(lastFriday).toISOString().substr(0, 10)
console.log(next) // <--- this should be 2021-06-25 but is a day out
console.log(lastFriday) // <-- why is this correct?
我不知道这是否符合您的需求,您可以看看。
function getPaydates(now = new Date()) {
// get this firday
const day = now.getDay() === 0 ? 7 : now.getDay();
const firday = new Date(now.getTime() + (5 - day) * 1000 * 24 * 3600);
const week = 7 * 1000 * 24 * 3600;
let next;
let following;
[8, 7, 6, 5, 4, 3, 2, 1, 0]
.map((i) => new Date(week * i + firday.getTime()))
.forEach((date) => {
if (!following && date.getMonth() === firday.getMonth() + 1)
following = date;
if (!next && date.getMonth() === firday.getMonth()) next = date;
});
return {
next: next.toISOString().slice(0, 10),
following: following.toISOString().slice(0, 10),
};
}
当now
为"2021-06-01"时,next
为"2021:06-25",following
为"2021-27-30",结果与now
为"20201-06-26"时相同。顺便说一下,Date.toISOString
将有时区问题。
首先,您需要更新getLastFridayOfMonth函数。
function getLastFridayOfMonth (year, month) {
let lastDay = new Date(year, month + 1, 0);
lastDay.setDate(lastDay .getDate() - (lastDay.getDay() + 2) % 7);
return lastDay
}
其次。您需要更新getPaydates函数。
function getPaydates (now = new Date()) {
const month = getCurrentMonth(now)
const year = getCurrentYear(now)
const lastFriday = getLastFridayOfMonth(year, month)
const followinglastFriday = getLastFridayOfMonth(year, month+1)
return {
next: lastFriday.getFullYear() + '-' + (lastFriday.getMonth() + 1) + '-' + lastFriday.getDate(),
following: followinglastFriday.getFullYear() + '-' + (followinglastFriday.getMonth() + 1) + '-' + followinglastFriday.getDate(),
}
}
您的代码似乎过于复杂,请考虑将其减少到所需的数量,然后在有意义的情况下用库函数替换部分。没有必要将函数包装在date.getMonth.周围
以下是一个简化版本,返回当月的最后一个星期五,如果通过的日期在月末的7天内,则返回下个月的最后一次星期五,再加上下个月最后一次的星期五。
一些功能被简化了,那些没有使用或不必要的功能被省略了getLastOfDay是一个获取月份中指定日期最后一天的通用函数,因此可以用于一周中的任何一天。
// Get last day of month
function getEOM (date) {
return new Date(date.getFullYear(), date.getMonth() + 1, 0);
}
// Return last of specified day in month of date
// ECMAScript day numbering: 0 = Sun, 1 = Mon, etc.
function getLastOfDay(date, day) {
// Get eom
let lastDay = getEOM(date);
// Set to last of specified day
lastDay.setDate(lastDay.getDate() - ((lastDay.getDay() + (7-day)) % 7));
return lastDay;
}
// Add months to Date
function addMonths(date, months) {
let d = new Date(date);
d.setMonth(d.getMonth() + Number(months));
// If new day not equal to old day then have overshot end of
// month, so set d to end of previous month
if (d.getDate() != date.getDate()) {
d.setDate(0);
}
return d;
}
/* Return last Friday of current month and next. If passed date
* is less than 7 days from end of month, return last Friday
* of next and following months.
*
* @param {Date} date - date to use to get Fridays
* @returns {Object} - {next: {Date}, following: {Date}
*/
function getFridays(date) {
let eom = getEOM(date);
// If date is within 7 days of eom, increment month
if (eom.getDate() - date.getDate() < 7) {
eom = addMonths(eom, 1);
}
// Get next Friday
let next = getLastOfDay(eom, 5);
// Get following Friday
let following = getLastOfDay(addMonths(eom, 1), 5);
return {next, following};
}
// Examples
[new Date(2021,3, 1), // 1 Apr 2021 - more than 7 days from EOM
new Date(2021,3,24), // 24 Apr 2021 - less than 7 days from EOM
new Date(2021,3,30), // 30 Apr 2021 - Friday at EOM
new Date(2021,5,23), // 23 Jun 2021 - 7 days from EOM
new Date() // Current date
].forEach(d => {
let result = getFridays(d);
console.log(
'Input : ' + d.toDateString() +
'nNext : ' + result.next.toDateString() +
'nFollowing : ' + result.following.toDateString()
);
});