最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to calculate next's month date without knowing the client's timezone? - Stack Overflow

programmeradmin4浏览0评论

Dates are really weird, and I can't seem to solve this issue:

Client lives in GMT+2 time zone and server saves everything in UTC time zone.

Client provides date 2024-12-01 which is converted to UTC time 2024-11-30T22:00:00.000Z and saved in the server.

Then client needs to get a date from the server that is one month after the saved date, which should be 2025-01-01. However, the server will return to client: 2024-12-31

Because server saved date is going to be the last day of the month but not the first as client provided. So, the following function does not work:

const setToNextMonth = (date) => {
  date.setMonth(date.getMonth()+1)
}

// Correct
const clientDate = new Date('2024-12-01')
setToNextMonth(clientDate)
console.log(clientDate, '- Should return')

// Incorrect
const serverDate = new Date('2024-11-30T22:00:00.000Z')
setToNextMonth(serverDate)
console.log(serverDate, '- Actual return') 

Dates are really weird, and I can't seem to solve this issue:

Client lives in GMT+2 time zone and server saves everything in UTC time zone.

Client provides date 2024-12-01 which is converted to UTC time 2024-11-30T22:00:00.000Z and saved in the server.

Then client needs to get a date from the server that is one month after the saved date, which should be 2025-01-01. However, the server will return to client: 2024-12-31

Because server saved date is going to be the last day of the month but not the first as client provided. So, the following function does not work:

const setToNextMonth = (date) => {
  date.setMonth(date.getMonth()+1)
}

// Correct
const clientDate = new Date('2024-12-01')
setToNextMonth(clientDate)
console.log(clientDate, '- Should return')

// Incorrect
const serverDate = new Date('2024-11-30T22:00:00.000Z')
setToNextMonth(serverDate)
console.log(serverDate, '- Actual return') 

The question is how to get the correct next month date without knowing client timezone?

Share Improve this question edited Nov 19, 2024 at 11:06 MCTG asked Nov 19, 2024 at 8:09 MCTGMCTG 611 silver badge12 bronze badges 6
  • 2024-01-01(2024-12-31T22:00:00.000Z)? What format is: yyyy-mm=dd(yyyy-mm-ddThh:mm:ss. sssZ)? – zer00ne Commented Nov 19, 2024 at 9:13
  • My bad, I've updated description. First is formatted date according to client time zone and in the brackets I've provided server response. – MCTG Commented Nov 19, 2024 at 10:23
  • "…server will take November (30) month days instead of December (31)". Not exactly, it just adds 1 to the month number, so 30 Nov becomes 30 Dec. You want to treat a date as just the date part, without time, i.e. independent of timezone. The new Temporal object will let you do that. In the meantime consider passing date strings, treating them as local everywhere, making them timezone independent. "2024-12-01" should be parsed as local, but the ECMA-262 authors thought differently (which I consider a bug in the specification but it will be obviated by Temporal when it's introduced). – RobG Commented Nov 19, 2024 at 10:29
  • 1 Store dates without timezone as dates without timezone, not as JavaScript date. – Salman Arshad Commented Nov 19, 2024 at 10:57
  • What if storing the date as string is not an option? For example MongoDB strongly encourages using only native data type. – MCTG Commented Nov 19, 2024 at 11:30
 |  Show 1 more comment

1 Answer 1

Reset to default 1

Your issue is when the day does not exist in the next month. You said you want the last of next month if current day is larger than the number of days in next month.

I normalise on 15:00 to not run into DSL and timezone issues since the largest TZ difference is 13 hours.

const getNextMonthDate = (dateStringUTC) => {
  const date = new Date(dateStringUTC);
  const savedDays = date.getUTCDate(); // Days of the passed month
  const time = dateStringUTC.split('T')[1]; // Extract the time part

  // Normalize to 15:00 UTC to handle DSL and TZ
  date.setUTCHours(15, 0, 0, 0); 

  // Add one month 
  date.setUTCMonth(date.getUTCMonth() + 1);

  // If saved days are greater than 28 and the our new date < saved days we overshot the date

  if (savedDays > 28 && date.getUTCDate() < savedDays) {
    // Adjust to the last day of the next month
    const lastDayOfNextMonth = new Date(
      date.getUTCFullYear(), // No issue with year transitions
      date.getUTCMonth(),    // Month is already the next month
      0,                     // 0th day gives the last day of the month we are aiming for
      15, 0, 0, 0            // Set time to 15:00 for consistency
    ).getUTCDate();

    // Roll back the month
    date.setUTCMonth(date.getUTCMonth() - 1);
    // Set the date to the last day of the month
    date.setUTCDate(lastDayOfNextMonth);
  } else {
    // Otherwise, set the date to the saved days
    date.setUTCDate(savedDays);
  }
  // Return the final ISO string with the preserved time
  return `${date.toISOString().split('T')[0]}T${time};`
};



const inputDate = "2024-11-30T22:00:00.000Z";
console.log(getNextMonthDate(inputDate)); // Expected: 2024-12-30T22:00:00.000Z;

const inputDate1 = "2024-01-30T22:00:00.000Z";
console.log(getNextMonthDate(inputDate1)); // Feb 28 or 29 depending on leap

发布评论

评论列表(0)

  1. 暂无评论