Home > other >  How to increment days in JavaScript ignoring time zones and daylight saving time?
How to increment days in JavaScript ignoring time zones and daylight saving time?

Time:08-24

Given a date (no time) in an ISO8601 format (e.g. 2022-10-01), how could I reliably increment a given amount of days to it and get back the same ISO8601 format?

I tried the approach below but it fails due to time zones / daylight saving time:

function incrementDays(dateStr, daysToIncrement) {
  const dateAtUTC = new Date(`${dateStr}T00:00:00.000Z`);

  dateAtUTC.setDate(dateAtUTC.getDate()   daysToIncrement);

  return dateAtUTC.toISOString().slice(0, 10);
}

const tests = [{
    dateStr: "2022-04-01",
    daysToIncrement: 10,
    expectedResult: "2022-04-11"
  },
  {
    dateStr: "2022-10-01",
    daysToIncrement: 1,
    expectedResult: "2022-10-02" // This is failing with "2022-10-01"
  },
  {
    dateStr: "2020-02-29",
    daysToIncrement: 3,
    expectedResult: "2020-03-03"
  },
]

tests.forEach(({
  dateStr,
  daysToIncrement,
  expectedResult
}) => {
  const result = incrementDays(dateStr, daysToIncrement);

  if (result === expectedResult) {
    console.log("PASSED", `${dateStr}   ${daysToIncrement} = ${result}`)
  } else {
    console.log("FAILED", `${dateStr}   ${daysToIncrement} = ${result} (expected: ${expectedResult})`)
  }
})

CodePudding user response:

use .setUTCDate and .getUTCDate instead

function incrementDays(dateStr, daysToIncrement) {
  const dateAtUTC = new Date(`${dateStr}T00:00:00.000Z`);

  dateAtUTC.setUTCDate(dateAtUTC.getUTCDate()   daysToIncrement);

  return dateAtUTC.toISOString().slice(0, 10);
}

const tests = [{
    dateStr: "2022-04-01",
    daysToIncrement: 10,
    expectedResult: "2022-04-11"
  },
  {
    dateStr: "2022-10-01",
    daysToIncrement: 1,
    expectedResult: "2022-10-02" // This is failing with "2022-10-01"
  },
  {
    dateStr: "2020-02-29",
    daysToIncrement: 3,
    expectedResult: "2020-03-03"
  },
]

tests.forEach(({
  dateStr,
  daysToIncrement,
  expectedResult
}) => {
  const result = incrementDays(dateStr, daysToIncrement);

  if (result === expectedResult) {
    console.log("PASSED", `${dateStr}   ${daysToIncrement} = ${result}`)
  } else {
    console.log("FAILED", `${dateStr}   ${daysToIncrement} = ${result} (expected: ${expectedResult})`)
  }
})

CodePudding user response:

Consider adding the days while parsing the string, e.g.

function incrementDays(s, days = 0) {
  let [y,m,d] = s.split(/\D/);
  return new Date(Date.UTC(y, m-1,  d    days)).toISOString().slice(0,10);
}

// Add 3 days
console.log(incrementDays('2022-10-01', 3));
// Subtract 23 days
console.log(incrementDays('2022-10-01', -23));

// OP test
const tests = [{
    dateStr: "2022-04-01",
    daysToIncrement: 10,
    expectedResult: "2022-04-11"
  },
  {
    dateStr: "2022-10-01",
    daysToIncrement: 1,
    expectedResult: "2022-10-02" // This is failing with "2022-10-01"
  },
  {
    dateStr: "2020-02-29",
    daysToIncrement: 3,
    expectedResult: "2020-03-03"
  },
]

tests.forEach(({
  dateStr,
  daysToIncrement,
  expectedResult
}) => {
  const result = incrementDays(dateStr, daysToIncrement);

  if (result === expectedResult) {
    console.log("PASSED", `${dateStr}   ${daysToIncrement} = ${result}`)
  } else {
    console.log("FAILED", `${dateStr}   ${daysToIncrement} = ${result} (expected: ${expectedResult})`)
  }
})

  • Related