Ich suche nach der einfachsten und saubersten Möglichkeit, einem JavaScript-Datum X Monate hinzuzufügen.
Ich würde lieber nicht mit dem Rollover des Jahres umgehen oder meine eigene Funktion schreiben müssen .
Ist etwas eingebaut, das dies kann?
Ich suche nach der einfachsten und saubersten Möglichkeit, einem JavaScript-Datum X Monate hinzuzufügen.
Ich würde lieber nicht mit dem Rollover des Jahres umgehen oder meine eigene Funktion schreiben müssen .
Ist etwas eingebaut, das dies kann?
Antworten:
Die folgende Funktion fügt einem Datum in JavaScript ( Quelle ) Monate hinzu . Dabei werden Jahresüberschreitungen und unterschiedliche Monatslängen berücksichtigt:
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());
Die obige Lösung deckt den Randfall des Verschiebens von einem Monat mit einer größeren Anzahl von Tagen als dem Zielmonat ab. z.B.
Wenn sich der Tag des Monats bei der Bewerbung ändert setMonth
, wissen wir, dass wir aufgrund einer unterschiedlichen Monatslänge in den folgenden Monat übergelaufen sind. In diesem Fall kehren wir setDate(0)
zum letzten Tag des Vormonats zurück.
Hinweis: Diese Version dieser Antwort ersetzt eine frühere Version (unten), die unterschiedliche Monatslängen nicht ordnungsgemäß verarbeitet hat.
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);
Ich verwende die Bibliothek moment.js für Manipulationen von Datum und Uhrzeit . Beispielcode zum Hinzufügen eines Monats:
var startDate = new Date(...);
var endDateMoment = moment(startDate); // moment(...) can also be used to parse dates in string format
endDateMoment.add(1, 'months');
Diese Funktion behandelt Randfälle und ist schnell:
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
}
Prüfung:
> 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"
Update für Nicht-UTC-Daten: (von A.Hatchkins)
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
}
Prüfung:
> 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"
Da keine dieser Antworten das aktuelle Jahr berücksichtigt, in dem sich der Monat ändert, finden Sie eine, die ich unten erstellt habe und die damit umgehen sollte:
Die Methode:
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;
}
Verwendung:
return new Date().addMonths(2);
Entnommen aus den Antworten von @bmpsini und @Jazaret , aber ohne Erweiterung von Prototypen: Verwenden einfacher Funktionen ( Warum ist das Erweitern nativer Objekte eine schlechte Praxis? ):
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;
}
Benutze es:
var nextMonth = addMonths(new Date(), 1);
Aus den obigen Antworten geht hervor, dass der einzige, der die Randfälle behandelt (bmpasini aus der datejs-Bibliothek), ein Problem hat:
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)
OK aber:
newDate.toISOString()
//"2015-04-29T22:00:00.000Z"
schlechter :
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"
Dies liegt daran, dass die Zeit nicht eingestellt ist und somit auf 00:00:00 zurückgesetzt wird, was aufgrund von Zeitzonen- oder zeitsparenden Änderungen oder was auch immer zu Störungen am Vortag führen kann ...
Hier ist meine vorgeschlagene Lösung, die dieses Problem nicht hat und meiner Meinung nach auch insofern eleganter ist, als sie nicht auf fest codierten Werten beruht.
/**
* @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];
};
Gerät erfolgreich getestet mit:
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')
);
Wie die meisten Antworten hervorhoben, könnten wir die setMonth () -Methode zusammen mit der getMonth () -Methode verwenden, um einem bestimmten Datum eine bestimmte Anzahl von Monaten hinzuzufügen.
Beispiel: (wie von @ChadD in seiner Antwort erwähnt.)
var x = 12; //or whatever offset var CurrentDate = new Date(); CurrentDate.setMonth(CurrentDate.getMonth() + x);
Wir sollten diese Lösung jedoch sorgfältig verwenden, da wir Probleme mit Randfällen bekommen.
Um Randfälle zu behandeln, ist die Antwort unter folgendem Link hilfreich.
https://stackoverflow.com/a/13633692/3668866
Einfache Lösung: 2678400000
31 Tage in Millisekunden
var oneMonthFromNow = new Date((+new Date) + 2678400000);
Aktualisieren:
Verwenden Sie diese Daten, um unsere eigene Funktion aufzubauen:
2678400000
- 31 Tage2592000000
- 30 Tage2505600000
- 29 Tage2419200000
- 28 TageNur um die akzeptierte Antwort und die Kommentare zu ergänzen.
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);
Ich habe diese alternative Lösung geschrieben, die für mich gut funktioniert. Dies ist nützlich, wenn Sie das Ende eines Vertrags berechnen möchten. Beispiel: Start = 15.01.2016, Monate = 6, Ende = 14.07.2016 (dh letzter Tag - 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>
Beispiele:
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
Im Folgenden finden Sie ein Beispiel für die Berechnung eines zukünftigen Datums basierend auf der Datumseingabe (Mitgliedschaftssignup_Datum) + hinzugefügten Monaten (Mitgliedschaftsmonate) über Formularfelder.
Das Feld für Mitgliedschaftsmonate hat den Standardwert 0
Trigger-Link (kann ein Onchange-Ereignis sein, das an das Feld für den Mitgliedsbegriff angehängt ist):
<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;
}
Wie viele der komplizierten, hässlichen Antworten zeigen, können Datum und Uhrzeit für Programmierer, die jede Sprache verwenden, ein Albtraum sein. Mein Ansatz besteht darin, Datumsangaben und Delta-t-Werte in Epochenzeit (in ms) umzuwandeln, eine beliebige Arithmetik durchzuführen und dann wieder in "menschliche Zeit" umzuwandeln.
// 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 );
Dies wurde für einen etwas anderen Anwendungsfall geschrieben, aber Sie sollten es leicht für verwandte Aufgaben anpassen können.
EDIT: Vollständige Quelle hier !
All dies scheint viel zu kompliziert und ich denke, es kommt zu einer Debatte darüber, was genau das Hinzufügen von "einem Monat" bedeutet. Bedeutet das 30 Tage? Bedeutet das vom 1. bis zum 1.? Vom letzten bis zum letzten Tag?
Wenn letzteres der Fall ist, führt das Hinzufügen eines Monats zum 27. Februar zum 27. März, das Hinzufügen eines Monats zum 28. Februar zum 31. März (außer in Schaltjahren, in denen Sie zum 28. März gelangen). Wenn Sie dann einen Monat vom 30. März abziehen, erhalten Sie ... 27. Februar? Wer weiß...
Wenn Sie nach einer einfachen Lösung suchen, fügen Sie einfach Millisekunden hinzu und fertig.
function getDatePlusDays(dt, days) {
return new Date(dt.getTime() + (days * 86400000));
}
oder
Date.prototype.addDays = function(days) {
this = new Date(this.getTime() + (days * 86400000));
};
d.setMonth(d.getMonth()+1)
? Das ist also nicht einmal die einfachste Idee.
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 );
}
Manchmal nützlich, um ein Datum von einem Operator zu erstellen, wie in BIRT-Parametern
Ich habe 1 Monat zurück gemacht mit:
new Date(new Date().setMonth(new Date().getMonth()-1));