简体   繁体   中英

Javascript Date and DST, add months modify hours

I know it's a famous question and i know to modify date, but i can't find anything regarding to this problem.

I have an ISO 8061 date and i want to add/substract month without modifying the hours and days:

I have the following input:

var add1Month = "2018-10-01T23:59:59.000Z";
var add10Month = "2018-12-01T00:00:00.000Z";

I want to add 1 month to add1Month and 10 to add10Month to have the following output:

var resAdd1Month  = "2018-11-01T23:59:59.000Z";
var resAdd10Month = "2019-10-01T00:00:00.000Z";

Note that days and hours aren't modified and musn't been modified.

Usually i use the couple setMonth/getMonth or moment to modify it but i can't have the good result with it :

// With date
var add1Month = new Date("2018-10-01T23:59:59.000Z");
add1Month.setMonth(add1Month.getMonth() + 1);
console.log(add1Month.toJSON()); // 2018-11-02T00:59:59.000Z


var add10Month = new Date("2018-12-01T00:00:00.000Z")
add10Month.setMonth(add10Month.getMonth() + 10);
console.log(add10Month.toJSON()); // 2019-09-30T23:00:00.000Z



// With moment
var add1Month = new Date(moment("2018-10-01T23:59:59.000Z").add(1, 'M').format()).toJSON();
console.log(add1Month); // 2018-11-02T00:59:59.000Z

var add10Month = new Date(moment("2018-12-01T00:00:00.000Z").add(10, 'M').format()).toJSON()
console.log(add10Month); // 2019-09-30T23:00:00.000Z

There's an easy way to add month to a date without modifying date or hours in case of DST cross ?

The only solution i've found now it's to add it by hand :

function addMonth(isoDate, month){

  var splitDate = isoDate.substr(0,10).split("-").map(function(e){return parseInt(e)});

   // modify month
   splitDate[1] = splitDate[1]+month;

   // modify year if needed
   splitDate[0] = splitDate[0] + Math.floor((splitDate[1] || -12) / 12);

   // remove extra month aleady added in year and take account negative for month substraction
   splitDate[1] = Math.abs((12 + splitDate[1]) % 12) || 12;

   // reformat with 2 digit month and days
   splitDate[1] = ("00"+splitDate[1]).substr(-2);
   splitDate[2] = ("00"+splitDate[2]).substr(-2);


   // manage end day of month 31/30 => 2018-07-31 - 1 month => 2018-06-31 => 2018-06-30 (remove day until valid date found)
    while(new Date(splitDate[0]+"-"+splitDate[1]+"-"+splitDate[2]+isoDate.substr(10)).toJSON() !=
splitDate[0]+"-"+splitDate[1]+"-"+splitDate[2]+isoDate.substr(10)
   )
   {
     splitDate[2] = parseInt(splitDate[2]) - 1;
     splitDate[2] = ("00"+(splitDate[2])).substr(-2);
   }


   return splitDate[0]+"-"+splitDate[1]+"-"+splitDate[2]+isoDate.substr(10);

}

addMonth("2018-10-01T23:59:59.000Z", 1); // "2018-11-01T23:59:59.000Z"
addMonth("2018-12-01T00:00:00.000Z", 10); // "2019-10-01T00:00:00.000Z"
addMonth("2018-06-01T00:00:00.000Z", -11); // "2017-05-01T00:00:00.000Z"
 addMonth("2018-03-31T23:59:59.000Z", -1); // "2018-02-28T23:59:59.000Z"

Thanks in advance !

That "by hand" can be beautified a bit:

 function addMonths(date, add) {
  const [day, time] = date.split("T");
  let [years, months, days] = day.split("-");

  months = +months + add;

  years = +years + Math.floor(months / 12);
  months = months % 12;



  return [years, months.padStart(2, 0), days].join("-") + "T" + time;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM