Я шукаю найпростіший, найпростіший спосіб додати X місяців до дати JavaScript.
Я б краще не впорався з перекочуванням року або мусив писати власну функцію .
Чи є щось вбудоване, що може це зробити?
Я шукаю найпростіший, найпростіший спосіб додати X місяців до дати JavaScript.
Я б краще не впорався з перекочуванням року або мусив писати власну функцію .
Чи є щось вбудоване, що може це зробити?
Відповіді:
Наступна функція додає місяці до дати в JavaScript ( джерело ). Він враховує перевернення року та різну тривалість місяця:
function addMonths(date, months) {
var d = date.getDate();
date.setMonth(date.getMonth() + +months);
if (date.getDate() != d) {
date.setDate(0);
}
return date;
}
// Add 12 months to 29 Feb 2016 -> 28 Feb 2017
console.log(addMonths(new Date(2016,1,29),12).toString());
// Subtract 1 month from 1 Jan 2017 -> 1 Dec 2016
console.log(addMonths(new Date(2017,0,1),-1).toString());
// Subtract 2 months from 31 Jan 2017 -> 30 Nov 2016
console.log(addMonths(new Date(2017,0,31),-2).toString());
// Add 2 months to 31 Dec 2016 -> 28 Feb 2017
console.log(addMonths(new Date(2016,11,31),2).toString());
Вищевказане рішення охоплює крайній випадок переходу на місяць із більшою кількістю днів, ніж місяць призначення. напр.
Якщо день місяця змінюється під час подання заявки setMonth
, ми знаємо, що ми перейшли у наступний місяць через різницю в тривалості місяця. У цьому випадку ми використовуємоsetDate(0)
для того, щоб повернутися до останнього дня попереднього місяця.
Примітка: ця версія цієї відповіді замінює попередню версію (нижче), яка не витончено обробляла різні місячні тривалості.
var x = 12; //or whatever offset
var CurrentDate = new Date();
console.log("Current date:", CurrentDate);
CurrentDate.setMonth(CurrentDate.getMonth() + x);
console.log("Date after " + x + " months:", CurrentDate);
Я використовую бібліотеку moment.js для маніпуляцій з датою та часом . Приклад коду для додання одного місяця:
var startDate = new Date(...);
var endDateMoment = moment(startDate); // moment(...) can also be used to parse dates in string format
endDateMoment.add(1, 'months');
Ця функція обробляє крайові корпуси і швидко:
function addMonthsUTC (date, count) {
if (date && count) {
var m, d = (date = new Date(+date)).getUTCDate()
date.setUTCMonth(date.getUTCMonth() + count, 1)
m = date.getUTCMonth()
date.setUTCDate(d)
if (date.getUTCMonth() !== m) date.setUTCDate(0)
}
return date
}
тест:
> d = new Date('2016-01-31T00:00:00Z');
Sat Jan 30 2016 18:00:00 GMT-0600 (CST)
> d = addMonthsUTC(d, 1);
Sun Feb 28 2016 18:00:00 GMT-0600 (CST)
> d = addMonthsUTC(d, 1);
Mon Mar 28 2016 18:00:00 GMT-0600 (CST)
> d.toISOString()
"2016-03-29T00:00:00.000Z"
Оновлення для дат, які не були UTC ,: (автор А.Хеткінс)
function addMonths (date, count) {
if (date && count) {
var m, d = (date = new Date(+date)).getDate()
date.setMonth(date.getMonth() + count, 1)
m = date.getMonth()
date.setDate(d)
if (date.getMonth() !== m) date.setDate(0)
}
return date
}
тест:
> d = new Date(2016,0,31);
Sun Jan 31 2016 00:00:00 GMT-0600 (CST)
> d = addMonths(d, 1);
Mon Feb 29 2016 00:00:00 GMT-0600 (CST)
> d = addMonths(d, 1);
Tue Mar 29 2016 00:00:00 GMT-0600 (CST)
> d.toISOString()
"2016-03-29T06:00:00.000Z"
Зважаючи на те, що жоден із цих відповідей не враховуватиме поточний рік, коли зміниться місяць, ви можете знайти одну, яку я зробив нижче, і яка повинна вирішувати:
Спосіб:
Date.prototype.addMonths = function (m) {
var d = new Date(this);
var years = Math.floor(m / 12);
var months = m - (years * 12);
if (years) d.setFullYear(d.getFullYear() + years);
if (months) d.setMonth(d.getMonth() + months);
return d;
}
Використання:
return new Date().addMonths(2);
Взято з відповідей @bmpsini та @Jazaret , але не поширюваних прототипів: використання простих функцій ( Чому розширення нативних об’єктів є поганою практикою? ):
function isLeapYear(year) {
return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
}
function getDaysInMonth(year, month) {
return [31, (isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
}
function addMonths(date, value) {
var d = new Date(date),
n = date.getDate();
d.setDate(1);
d.setMonth(d.getMonth() + value);
d.setDate(Math.min(n, getDaysInMonth(d.getFullYear(), d.getMonth())));
return d;
}
Використай це:
var nextMonth = addMonths(new Date(), 1);
З вищенаведених відповідей, єдиний, який обробляє крайові регістри (bmpasini's з бібліотеки datejs), має проблему:
var date = new Date("03/31/2015");
var newDate = date.addMonths(1);
console.log(newDate);
// VM223:4 Thu Apr 30 2015 00:00:00 GMT+0200 (CEST)
добре, але:
newDate.toISOString()
//"2015-04-29T22:00:00.000Z"
гірше:
var date = new Date("01/01/2015");
var newDate = date.addMonths(3);
console.log(newDate);
//VM208:4 Wed Apr 01 2015 00:00:00 GMT+0200 (CEST)
newDate.toISOString()
//"2015-03-31T22:00:00.000Z"
Це пов’язано з тим, що час не встановлено, і таким чином повертається до 00:00:00, який потім може виблискувати до попереднього дня через зміни часового поясу або економії часу або будь-якого іншого ...
Ось моє запропоноване рішення, яке не має цієї проблеми, а також, я думаю, є більш елегантним, оскільки воно не покладається на твердо кодовані значення.
/**
* @param isoDate {string} in ISO 8601 format e.g. 2015-12-31
* @param numberMonths {number} e.g. 1, 2, 3...
* @returns {string} in ISO 8601 format e.g. 2015-12-31
*/
function addMonths (isoDate, numberMonths) {
var dateObject = new Date(isoDate),
day = dateObject.getDate(); // returns day of the month number
// avoid date calculation errors
dateObject.setHours(20);
// add months and set date to last day of the correct month
dateObject.setMonth(dateObject.getMonth() + numberMonths + 1, 0);
// set day number to min of either the original one or last day of month
dateObject.setDate(Math.min(day, dateObject.getDate()));
return dateObject.toISOString().split('T')[0];
};
Блок успішно перевірений:
function assertEqual(a,b) {
return a === b;
}
console.log(
assertEqual(addMonths('2015-01-01', 1), '2015-02-01'),
assertEqual(addMonths('2015-01-01', 2), '2015-03-01'),
assertEqual(addMonths('2015-01-01', 3), '2015-04-01'),
assertEqual(addMonths('2015-01-01', 4), '2015-05-01'),
assertEqual(addMonths('2015-01-15', 1), '2015-02-15'),
assertEqual(addMonths('2015-01-31', 1), '2015-02-28'),
assertEqual(addMonths('2016-01-31', 1), '2016-02-29'),
assertEqual(addMonths('2015-01-01', 11), '2015-12-01'),
assertEqual(addMonths('2015-01-01', 12), '2016-01-01'),
assertEqual(addMonths('2015-01-01', 24), '2017-01-01'),
assertEqual(addMonths('2015-02-28', 12), '2016-02-28'),
assertEqual(addMonths('2015-03-01', 12), '2016-03-01'),
assertEqual(addMonths('2016-02-29', 12), '2017-02-28')
);
Як підкреслено більшість відповідей, ми могли використовувати метод setMonth () разом з getMonth () щоб додати певну кількість місяців до даної дати.
Приклад: (як згадував @ChadD у своїй відповіді.)
var x = 12; //or whatever offset var CurrentDate = new Date(); CurrentDate.setMonth(CurrentDate.getMonth() + x);
Але нам слід обережно використовувати це рішення, оскільки у нас виникнуть проблеми з крайніми корпусами.
Для вирішення крайових справ корисна відповідь, яка наведена на наступному посиланні.
https://stackoverflow.com/a/13633692/3668866
Просте рішення: 2678400000
це 31 день в мілісекундах
var oneMonthFromNow = new Date((+new Date) + 2678400000);
Оновлення:
Використовуйте ці дані для побудови власної функції:
2678400000
- 31 день2592000000
- 30 днів2505600000
- 29 днів2419200000
- 28 днівПросто додати до прийнятої відповіді та коментарів.
var x = 12; //or whatever offset
var CurrentDate = new Date();
//For the very rare cases like the end of a month
//eg. May 30th - 3 months will give you March instead of February
var date = CurrentDate.getDate();
CurrentDate.setDate(1);
CurrentDate.setMonth(CurrentDate.getMonth()+X);
CurrentDate.setDate(date);
Я написав це альтернативне рішення, яке добре працює для мене. Це корисно, коли ви хочете розрахувати кінець контракту. Наприклад, початок = 2016-01-15, місяці = 6, кінець = 2016-7-14 (тобто останній день - 1):
<script>
function daysInMonth(year, month)
{
return new Date(year, month + 1, 0).getDate();
}
function addMonths(date, months)
{
var target_month = date.getMonth() + months;
var year = date.getFullYear() + parseInt(target_month / 12);
var month = target_month % 12;
var day = date.getDate();
var last_day = daysInMonth(year, month);
if (day > last_day)
{
day = last_day;
}
var new_date = new Date(year, month, day);
return new_date;
}
var endDate = addMonths(startDate, months);
</script>
Приклади:
addMonths(new Date("2016-01-01"), 1); // 2016-01-31
addMonths(new Date("2016-01-01"), 2); // 2016-02-29 (2016 is a leap year)
addMonths(new Date("2016-01-01"), 13); // 2017-01-31
addMonths(new Date("2016-01-01"), 14); // 2017-02-28
Нижче наводиться приклад того, як обчислити майбутню дату на основі введення дати (članstvossignup_date) + доданих місяців (членськихмісяців) через поля форми.
Поле membershipsmonths має значення за замовчуванням 0
Тригерне посилання (може бути подією, що змінюється, додається до поля терміну членства):
<a href="#" onclick="calculateMshipExp()"; return false;">Calculate Expiry Date</a>
function calculateMshipExp() {
var calcval = null;
var start_date = document.getElementById("membershipssignup_date").value;
var term = document.getElementById("membershipsmonths").value; // Is text value
var set_start = start_date.split('/');
var day = set_start[0];
var month = (set_start[1] - 1); // January is 0 so August (8th month) is 7
var year = set_start[2];
var datetime = new Date(year, month, day);
var newmonth = (month + parseInt(term)); // Must convert term to integer
var newdate = datetime.setMonth(newmonth);
newdate = new Date(newdate);
//alert(newdate);
day = newdate.getDate();
month = newdate.getMonth() + 1;
year = newdate.getFullYear();
// This is British date format. See below for US.
calcval = (((day <= 9) ? "0" + day : day) + "/" + ((month <= 9) ? "0" + month : month) + "/" + year);
// mm/dd/yyyy
calcval = (((month <= 9) ? "0" + month : month) + "/" + ((day <= 9) ? "0" + day : day) + "/" + year);
// Displays the new date in a <span id="memexp">[Date]</span> // Note: Must contain a value to replace eg. [Date]
document.getElementById("memexp").firstChild.data = calcval;
// Stores the new date in a <input type="hidden" id="membershipsexpiry_date" value="" name="membershipsexpiry_date"> for submission to database table
document.getElementById("membershipsexpiry_date").value = calcval;
}
Як показано в багатьох представлених складних, потворних відповідях, "Дати і тайми" можуть бути кошмаром для програмістів, які використовують будь-яку мову. Мій підхід полягає в перетворенні дат і значень "delta t" в час епохи (в мс), виконання будь-якої арифметики, а потім перетворення в "людський час".
// Given a number of days, return a Date object
// that many days in the future.
function getFutureDate( days ) {
// Convert 'days' to milliseconds
var millies = 1000 * 60 * 60 * 24 * days;
// Get the current date/time
var todaysDate = new Date();
// Get 'todaysDate' as Epoch Time, then add 'days' number of mSecs to it
var futureMillies = todaysDate.getTime() + millies;
// Use the Epoch time of the targeted future date to create
// a new Date object, and then return it.
return new Date( futureMillies );
}
// Use case: get a Date that's 60 days from now.
var twoMonthsOut = getFutureDate( 60 );
Це було написано для дещо іншого випадку використання, але ви повинні мати можливість легко адаптувати його до відповідних завдань.
EDIT: Повне джерело тут !
Все це здається занадто складним, і я думаю, що він вступає в дискусію щодо того, що саме означає додавання "місяця". Це означає 30 днів? Чи означає це від 1-го до 1-го? З останнього дня до останнього?
Якщо останнє, то додавання місяця до 27 лютого приведе вас до 27 березня, але додавання місяця до 28 лютого приведе вас до 31 березня (за винятком високосних років, де він потрапить до 28 березня). Тоді віднімання місяця з 30 березня отримує ... 27 лютого? Хто знає...
Для тих, хто шукає простого рішення, просто додайте мілісекунди і будете готові.
function getDatePlusDays(dt, days) {
return new Date(dt.getTime() + (days * 86400000));
}
або
Date.prototype.addDays = function(days) {
this = new Date(this.getTime() + (days * 86400000));
};
d.setMonth(d.getMonth()+1)
? Тож це навіть не найпростіша ідея.
addDateMonate : function( pDatum, pAnzahlMonate )
{
if ( pDatum === undefined )
{
return undefined;
}
if ( pAnzahlMonate === undefined )
{
return pDatum;
}
var vv = new Date();
var jahr = pDatum.getFullYear();
var monat = pDatum.getMonth() + 1;
var tag = pDatum.getDate();
var add_monate_total = Math.abs( Number( pAnzahlMonate ) );
var add_jahre = Number( Math.floor( add_monate_total / 12.0 ) );
var add_monate_rest = Number( add_monate_total - ( add_jahre * 12.0 ) );
if ( Number( pAnzahlMonate ) > 0 )
{
jahr += add_jahre;
monat += add_monate_rest;
if ( monat > 12 )
{
jahr += 1;
monat -= 12;
}
}
else if ( Number( pAnzahlMonate ) < 0 )
{
jahr -= add_jahre;
monat -= add_monate_rest;
if ( monat <= 0 )
{
jahr = jahr - 1;
monat = 12 + monat;
}
}
if ( ( Number( monat ) === 2 ) && ( Number( tag ) === 29 ) )
{
if ( ( ( Number( jahr ) % 400 ) === 0 ) || ( ( Number( jahr ) % 100 ) > 0 ) && ( ( Number( jahr ) % 4 ) === 0 ) )
{
tag = 29;
}
else
{
tag = 28;
}
}
return new Date( jahr, monat - 1, tag );
}
testAddMonate : function( pDatum , pAnzahlMonate )
{
var datum_js = fkDatum.getDateAusTTMMJJJJ( pDatum );
var ergebnis = fkDatum.addDateMonate( datum_js, pAnzahlMonate );
app.log( "addDateMonate( \"" + pDatum + "\", " + pAnzahlMonate + " ) = \"" + fkDatum.getStringAusDate( ergebnis ) + "\"" );
},
test1 : function()
{
app.testAddMonate( "15.06.2010", 10 );
app.testAddMonate( "15.06.2010", -10 );
app.testAddMonate( "15.06.2010", 37 );
app.testAddMonate( "15.06.2010", -37 );
app.testAddMonate( "15.06.2010", 1234 );
app.testAddMonate( "15.06.2010", -1234 );
app.testAddMonate( "15.06.2010", 5620 );
app.testAddMonate( "15.06.2010", -5120 );
}
Іноді корисно створити дату одним оператором, як у параметрах BIRT
Я зробив 1 місяць тому:
new Date(new Date().setMonth(new Date().getMonth()-1));