Oblicz ostatni dzień miesiąca w JavaScript

277

Jeśli podasz 0jako dayValuew Date.setFullYear, otrzymasz ostatni dzień poprzedniego miesiąca:

d = new Date(); d.setFullYear(2008, 11, 0); //  Sun Nov 30 2008

W Mozilli istnieje odniesienie do tego zachowania . Czy jest to niezawodna funkcja przeglądarki, czy powinienem spojrzeć na alternatywne metody?

Rozpoznać
źródło
Nie masz na myśli ostatniego dnia określonego miesiąca? Jest 30 dni w listopadzie i 31 w październiku.
Chris Serra,
16
Miesiące liczone są w javascript od zera, więc 11 to grudzień
Greg
2
@TheCloudlessSky - wypróbuj w konsoli ... (2008,11,0) to zerowy dzień grudnia, a zatem ostatni dzień listopada
Ken
@Ken - Tak - nie zdawałem sobie sprawy, że było „0”:) ... było za wcześnie rano.
TheCloudlessSky,

Odpowiedzi:

424
var month = 0; // January
var d = new Date(2008, month + 1, 0);
alert(d); // last day in January

IE 6:                     Thu Jan 31 00:00:00 CST 2008
IE 7:                     Thu Jan 31 00:00:00 CST 2008
IE 8: Beta 2:             Thu Jan 31 00:00:00 CST 2008
Opera 8.54:               Thu, 31 Jan 2008 00:00:00 GMT-0600
Opera 9.27:               Thu, 31 Jan 2008 00:00:00 GMT-0600
Opera 9.60:               Thu Jan 31 2008 00:00:00 GMT-0600
Firefox 2.0.0.17:         Thu Jan 31 2008 00:00:00 GMT-0600 (Canada Central Standard Time)
Firefox 3.0.3:            Thu Jan 31 2008 00:00:00 GMT-0600 (Canada Central Standard Time)
Google Chrome 0.2.149.30: Thu Jan 31 2008 00:00:00 GMT-0600 (Canada Central Standard Time)
Safari for Windows 3.1.2: Thu Jan 31 2008 00:00:00 GMT-0600 (Canada Central Standard Time)

Różnice w wynikach wynikają z różnic we toString()wdrażaniu, a nie dlatego, że daty są różne.

Oczywiście fakt, że wyżej wymienione przeglądarki używają 0 jako ostatniego dnia poprzedniego miesiąca, nie oznacza, że ​​będą to robić dalej, lub że przeglądarki niewymienione na liście to zrobią, ale nadaje to wiarygodności przekonaniu, że powinno działać w ten sam sposób w każdej przeglądarce.

Grant Wagner
źródło
19
To wydaje się działać doskonale. Z ciekawości, czego używasz do uruchamiania javascript we wszystkich tych silnikach? Masz wszystko skonfigurowane lub jakieś narzędzie?
neonski
5
możesz użyć d.getDate (), aby uzyskać rzeczywisty dzień.
rynop
35
„to, że przeglądarki… używają 0 jako ostatniego dnia poprzedniego miesiąca, nie oznacza, że ​​będą to robić”. Tak, tak, są one wymagane przez ECMA-262.
RobG
3
Należy pamiętać, że używanie new Datejest o wiele wolniejsze niż w przypadku innych metod obliczeniowych, że nawet nie pojawia się na wykresie perf : jsperf.com/days-in-month-perf-test/6
Gone Coding
4
To nie działa dla mnie w Chrome 48.0.2564.116. Być może ten sposób przestał być „standardem”.
xarlymg89
77

Użyłbym daty pośredniej z pierwszym dniem następnego miesiąca i zwróciłbym datę z poprzedniego dnia:

int_d = new Date(2008, 11+1,1);
d = new Date(int_d - 1);
karlipoppins
źródło
Zgodnie ze specyfikacją ECMAScript korzystanie z konstruktora „Date”, jak wskazałeś, jest prawidłowe. Postępując zgodnie z algorytmem określonym przez funkcję „MakeDay”, powinien dobrze poradzić sobie z tym problemem.
Pablo Cabrera
1
to najlepsze rozwiązanie IMO. Próbowałem zaakceptować odpowiedź, ale ma błąd podczas pobierania ostatniego z bieżącego miesiąca. Zwraca dzisiejszą datę. Nie jestem jednak pewien, dlaczego tak się dzieje.
Gogol
1
Nie mogę naprawić błędu. Daje mi to prawidłową datę we wszystkich przeglądarkach:today = new Date(); new Date(today.getFullYear(), today.getMonth()+1, 0).toString();
orad
Spowoduje to utworzenie obiektu Date dla ostatniego dnia miesiąca z czasem ustawionym na ostatnią milisekundę (tj. 23: 59: 59.999). Lepiej po prostu użyć metody w PO i zapisać dodatkowy krok i obiekt Data.
RobG
@RobG: zgadzam się! choć moje rozwiązanie może być łatwiejsze do zrozumienia, ponieważ moim zdaniem koncepcja używania 0 dla ostatniego dnia miesiąca wydaje się nieco nieporadna.
karlipoppins
72

Uważam to za najlepsze rozwiązanie dla mnie. Pozwól obiektowi Data go obliczyć.

var today = new Date();
var lastDayOfMonth = new Date(today.getFullYear(), today.getMonth()+1, 0);

Ustawienie parametru dnia na 0 oznacza jeden dzień mniej niż pierwszy dzień miesiąca, który jest ostatnim dniem poprzedniego miesiąca.

orad
źródło
1
W porządku, zauważyłem, że wybrana odpowiedź sugeruje to samo. Jest to najszybszy i najbardziej niezawodny sposób i działa niezależnie od rodzaju kalendarza. Na przykład, jeśli Date zaimplementował coś innego niż kalendarz gregoriański, nadal działałby. Zobacz intldate.codeplex.com, aby zobaczyć przykład innej niż gregoriańska implementacji obiektu Date.
orad
1
@orad: Uważaj na twierdzenie, że coś jest „najszybsze”, ponieważ ta metoda jest rzeczywiście znacznie wolniejsza niż niektóre alternatywy. Używanie new Datejest o wiele wolniejsze, nawet nie pojawia się na wykresie perf : jsperf.com/days-in-month-perf-test/6
Gone Coding
@TrueBlueAussie OK. Założyłem, że jest szybszy, ponieważ jest rodzimy. Ale masz rację, to nie jest szybkie. Dzięki za testowanie tego. W każdym razie to rozwiązanie działa dla mnie najlepiej, ponieważ jest zwięzłe i czytelne i w przeciwieństwie do wszystkich innych rozwiązań nie jest związane z kalendarzem gregoriańskim.
orad
„w przeciwieństwie do wszystkich innych rozwiązań nie jest związany z kalendarzem gregoriańskim” !!! Ten algorytm zwraca takie same wartości jak moje dla lat 1-4000. jsfiddle.net/2973x9m3/3 Jak twierdzisz, jaki dodatkowy zakres dat będzie obsługiwał ( przydałby się )? :)
Gone Coding
1
Natywna data JS korzysta tylko z kalendarza gregoriańskiego. Ale możesz wyśmiewać to za pomocą innej implementacji, aby uzyskać inne typy kalendarzy. Na przykład patrz IntlDate . Jeśli masz selektor daty, który używa obiektów Date do tworzenia widoków miesięcznych, nie ma znaczenia, z której implementacji Date (natywnej lub próbnej) korzysta, pod warunkiem, że mają ten sam interfejs. Tak więc korzystanie ze wspólnego interfejsu pozwala przełączać się między różnymi typami kalendarzy bez konieczności sprawdzania, ile dni w miesiącu przypada na każdy kalendarz.
orad
25

W kategoriach komputerowych, new Date()a regular expressionrozwiązania są powolne! Jeśli chcesz superszybkiego (i super-kryptycznego) jedno-liniowego, wypróbuj ten (zakładając, że mma Jan=1format). Próbuję różnych zmian kodu, aby uzyskać najlepszą wydajność.

Moja aktualna najszybsza wersja:

Po przeanalizowaniu tego powiązanego pytania Sprawdź rok przestępny za pomocą operatorów bitowych (niesamowita prędkość) i odkryłem, co reprezentuje magiczna liczba 25 i 15, wymyśliłem tę zoptymalizowaną hybrydę odpowiedzi:

function getDaysInMonth(m, y) {
    return m===2 ? y & 3 || !(y%25) && y & 15 ? 28 : 29 : 30 + (m+(m>>3)&1);
}

Biorąc pod uwagę przesunięcie bitów, to oczywiście zakłada, że obie parametry mi yparametry są liczbami całkowitymi, ponieważ przekazywanie liczb jako ciągów spowoduje dziwne wyniki.

JSFiddle: http://jsfiddle.net/TrueBlueAussie/H89X3/22/

Wyniki JSPerf: http://jsperf.com/days-in-month-head-to-head/5

Z jakiegoś powodu (m+(m>>3)&1)jest bardziej wydajny niż (5546>>m&1)w prawie wszystkich przeglądarkach.

Jedyną prawdziwą konkurencją dla prędkości jest @GitaarLab, więc stworzyłem JSPerf head-to-head do przetestowania na: http://jsperf.com/days-in-month-head-to-head/5


Działa w oparciu o moją odpowiedź na rok przestępny tutaj: javascript, aby znaleźć rok przestępny tę odpowiedź tutaj Sprawdzanie roku przestępnego za pomocą operatorów bitowych (niesamowita prędkość), a także następującą logikę binarną.

Szybka lekcja w miesiącach binarnych:

Jeśli interpretujesz indeks żądanych miesięcy (Jan = 1) w systemie binarnym , zauważysz, że miesiące z 31 dniami mają albo bit 3 skasowany i bit ustawiony 0, albo bit 3 ustawiony i bit 0 czysty.

Jan = 1  = 0001 : 31 days
Feb = 2  = 0010
Mar = 3  = 0011 : 31 days
Apr = 4  = 0100
May = 5  = 0101 : 31 days
Jun = 6  = 0110
Jul = 7  = 0111 : 31 days
Aug = 8  = 1000 : 31 days
Sep = 9  = 1001
Oct = 10 = 1010 : 31 days
Nov = 11 = 1011
Dec = 12 = 1100 : 31 days

Oznacza to, że możesz przesunąć wartość o 3 miejsca za pomocą >> 3, XOR bitów z oryginałem ^ mi sprawdzić, czy wynikiem jest 1lub 0 w pozycji bitu 0 za pomocą & 1. Uwaga: Okazuje się, że +jest nieco szybszy niż XOR ( ^) i (m >> 3) + mdaje ten sam wynik w bicie 0.

Wyniki JSPerf : http://jsperf.com/days-in-month-perf-test/6

Gone Coding
źródło
1
@GitaarLAB: Masz już wzmiankę, a jak już wiesz, nigdy nie była dokładnie taka sama jak twoja. Stopniowa aktualizacja pozostałych algorytmów nie jest tym samym, co „oryginalny algo”. Włożyłem również wiele wysiłku w tę odpowiedź: P
Gone Coding
@TrueBlueAussie: Chciałem tylko wskazać przyszłym czytelnikom nasz skarb więcej informacji (połączyłem obie nasze odpowiedzi, aby każdy, kogo to obchodzi, lub który chciałby spróbować, mógł przejrzeć naszą historię edycji, aby zobaczyć, kiedy zrobiliśmy co i dlaczego ). Wciąż czule pamiętam nasz cały dzień zawodów! :)Pierwsza opublikowana przeze mnie wersja odpowiedzi zawierała niepotrzebny zestaw nawiasów, które zostały usunięte (za co ci przypisałem), abyśmy mogli się ogolić i skończyć z tym. Wciąż jestem wdzięczny za ten zabawny dzień, zdrowie!
GitaarLAB,
1
Proszę wspomnieć o tym, ya mzmienne muszą być liczbą całkowitą, a nie ciągiem! Powoduje to błędne obliczenia, na przykład dla lutego zwraca 30. Musiałem użyć parseInt()funkcji, aby to działało.
zamiast
21

Mój kolega natknął się na następujące, co może być łatwiejszym rozwiązaniem

function daysInMonth(iMonth, iYear)
{
    return 32 - new Date(iYear, iMonth, 32).getDate();
}

skradziony z http://snippets.dzone.com/posts/show/2099

lebreeze
źródło
2
Nigel zmodyfikował to, aby uzyskać jeszcze bardziej zwięzłe rozwiązanie. Zobacz jego post.
orad
Miesiąc liczony jest od zera, tj. Jan = 0. To samo co getMonth ().
Moos
16

Niewielka modyfikacja rozwiązania dostarczonego przez Lebreeze :

function daysInMonth(iMonth, iYear)
{
    return new Date(iYear, iMonth, 0).getDate();
}
Nigel
źródło
Powinno to return new Date(iYear, 1 + iMonth, 0).getDate();być równoważne rozwiązaniu @ lebreeze.
Moos
6

Niedawno musiałem zrobić coś podobnego, oto co wymyśliłem:

/**
* Returns a date set to the begining of the month
* 
* @param {Date} myDate 
* @returns {Date}
*/
function beginningOfMonth(myDate){    
  let date = new Date(myDate);
  date.setDate(1)
  date.setHours(0);
  date.setMinutes(0);
  date.setSeconds(0);   
  return date;     
}

/**
 * Returns a date set to the end of the month
 * 
 * @param {Date} myDate 
 * @returns {Date}
 */
function endOfMonth(myDate){
  let date = new Date(myDate);
  date.setMonth(date.getMonth() +1)
  date.setDate(0);
  date.setHours(23);
  date.setMinutes(59);
  date.setSeconds(59);
  return date;
}

Podaj datę, a zwróci datę ustawioną na początek miesiąca lub na koniec miesiąca.

Ta begninngOfMonthfunkcja jest dość oczywista, ale w tej endOfMonthfunkcji zwiększam miesiąc do następnego, a następnie używamsetDate(0) cofnąć dzień do ostatniego dnia poprzedniego miesiąca, który jest częścią specyfikacja setDate:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setDate https://www.w3schools.com/jsref/jsref_setdate.asp

Następnie ustawiam godzinę / minuty / sekundy na koniec dnia, więc jeśli używasz jakiegoś interfejsu API, który oczekuje zakresu dat, będziesz w stanie uchwycić całość tego ostatniego dnia. Ta część może wykraczać poza to, o co prosi oryginalny post, ale może pomóc komuś innemu szukając podobnego rozwiązania.

Edycja: Możesz także przejść o wiele więcej i ustawić milisekundy, setMilliseconds()jeśli chcesz być bardziej precyzyjny.

Eric
źródło
4

Spróbuj tego.

lastDateofTheMonth = new Date(year, month, 0)

przykład:

new Date(2012, 8, 0)

wynik:

Date {Fri Aug 31 2012 00:00:00 GMT+0900 (Tokyo Standard Time)}
artykuły artystyczne
źródło
5
Pamiętaj jednak, że miesiące liczone są od zera, więc przejście na „8”, ponieważ tak naprawdę jest wrzesień, a nie sierpień.
Steve J
3

To działa dla mnie. Zapewni ostatni dzień danego roku i miesiąca:

var d = new Date(2012,02,0);
var n = d.getDate();
alert(n);
Kreeverp
źródło
1
uważaj na 0 przed „2”, to będzie interpretowane jako ósemkowe.
Walfrat
1

Ten działa ładnie:

Date.prototype.setToLastDateInMonth = function () {

    this.setDate(1);
    this.setMonth(this.getMonth() + 1);
    this.setDate(this.getDate() - 1);

    return this;
}
Josue
źródło
1

To da ci bieżący miesiąc pierwszy i ostatni dzień.

Jeśli chcesz zmienić „rok”, usuń d.getFullYear () i ustaw swój rok.

Jeśli chcesz zmienić „miesiąc”, usuń d.getMonth () i ustaw rok.

var d = new Date();
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
var fistDayOfMonth = days[(new Date(d.getFullYear(), d.getMonth(), 1).getDay())];
	var LastDayOfMonth = days[(new Date(d.getFullYear(), d.getMonth() + 1, 0).getDay())]; 
console.log("First Day :" + fistDayOfMonth); 
console.log("Last Day:" + LastDayOfMonth);
alert("First Day :" + fistDayOfMonth); 
alert("Last Day:" + LastDayOfMonth);

Himanshu kukreja
źródło
1

Spróbuj tego:

function _getEndOfMonth(time_stamp) {
    let time = new Date(time_stamp * 1000);
    let month = time.getMonth() + 1;
    let year = time.getFullYear();
    let day = time.getDate();
    switch (month) {
        case 1:
        case 3:
        case 5:
        case 7:
        case 8:
        case 10:
        case 12:
            day = 31;
            break;
        case 4:
        case 6:
        case 9:
        case 11:
            day = 30;
            break;
        case 2:
            if (_leapyear(year))
                day = 29;
            else
                day = 28;
            break
    }
    let m = moment(`${year}-${month}-${day}`, 'YYYY-MM-DD')
    return m.unix() + constants.DAY - 1;
}

function _leapyear(year) {
    return (year % 100 === 0) ? (year % 400 === 0) : (year % 4 === 0);
}
Yatin Darmwal
źródło
1

Poniższa funkcja podaje ostatni dzień miesiąca:

function getLstDayOfMonFnc(date) {
  return new Date(date.getFullYear(), date.getMonth(), 0).getDate()
}

console.log(getLstDayOfMonFnc(new Date(2016, 2, 15))) // Output : 29
console.log(getLstDayOfMonFnc(new Date(2017, 2, 15))) // Output : 28
console.log(getLstDayOfMonFnc(new Date(2017, 11, 15))) // Output : 30
console.log(getLstDayOfMonFnc(new Date(2017, 12, 15))) // Output : 31

Podobnie możemy uzyskać pierwszy dzień miesiąca:

function getFstDayOfMonFnc(date) {
  return new Date(date.getFullYear(), date.getMonth(), 1).getDate()
}

console.log(getFstDayOfMonFnc(new Date(2016, 2, 15))) // Output : 1

Sujay ONZ
źródło
0
function getLastDay(y, m) {
   return 30 + (m <= 7 ? ((m % 2) ? 1 : 0) : (!(m % 2) ? 1 : 0)) - (m == 2) - (m == 2 && y % 4 != 0 || !(y % 100 == 0 && y % 400 == 0)); 
}
Ashish
źródło
0
const today = new Date();

let beginDate = new Date();

let endDate = new Date();

// fist date of montg

beginDate = new Date(

  `${today.getFullYear()}-${today.getMonth() + 1}-01 00:00:00`

);

// end date of month 

// set next Month first Date

endDate = new Date(

  `${today.getFullYear()}-${today.getMonth() + 2}-01 :23:59:59`

);

// deducting 1 day

endDate.setDate(0);
rozetka
źródło
0

ustaw miesiąc, którego potrzebujesz, a następnie ustaw dzień na zero, więc miesiąc zacznij od 1 - 31 w funkcji daty, a następnie uzyskaj ostatni dzień ^^

var last = new Date(new Date(new Date().setMonth(7)).setDate(0)).getDate();
console.log(last);

Ahmed Samra
źródło
0

Oto odpowiedź, która zachowuje czas GMT i datę początkową

var date = new Date();

var first_date = new Date(date); //Make a copy of the date we want the first and last days from
first_date.setUTCDate(1); //Set the day as the first of the month

var last_date = new Date(first_date); //Make a copy of the calculated first day
last_date.setUTCMonth(last_date.getUTCMonth() + 1); //Add a month
last_date.setUTCDate(0); //Set the date to 0, this goes to the last day of the previous month

console.log(first_date.toJSON().substring(0, 10), last_date.toJSON().substring(0, 10)); //Log the dates with the format yyyy-mm-dd

Tofandel
źródło
0

Wiem, że to tylko kwestia semantyki, ale ostatecznie użyłem tego w tej formie.

var lastDay = new Date(new Date(2008, 11+1,1) - 1).getDate();
console.log(lastDay);

Ponieważ funkcje są rozwiązywane z argumentu wewnętrznego, na zewnątrz działa tak samo.

Następnie możesz po prostu zastąpić rok i miesiąc / rok wymaganymi szczegółami, niezależnie od tego, czy pochodzą one z bieżącej daty. Lub konkretnego miesiąca / roku.

Rudi Strydom
źródło
0

Jeśli potrzebujesz dokładnego końca miesiąca w milisekundach (na przykład znacznik czasu):

d = new Date()
console.log(d.toString())
d.setDate(1)
d.setHours(23, 59, 59, 999)
d.setMonth(d.getMonth() + 1)
d.setDate(d.getDate() - 1)
console.log(d.toString())

Gungnir
źródło