JavaScript oblicza dzień w roku (1 - 366)


119

Jak za pomocą JavaScript obliczyć dzień w roku od 1 do 366? Na przykład:

  • 3 stycznia powinien być 3 .
  • 1 lutego powinien być 32 .

4
var days = new Date().getFullYear() % 4 == 0 ? 366 : 365;
Alex Turpin,

Ale naprawdę nie jestem pewien, co masz na myśli. Chcesz tylko liczbę dni w roku? Albo między dwiema randkami?
Alex Turpin,

16
fyi @ xeon06, obliczanie roku przestępnego jest nieco bardziej skomplikowane niż modyfikowanie o 4. patrz: algorytm roku przestępnego
Matt Felzani

4
@ Xeon06: To prawda tylko w większości przypadków. Z Wikipedii : Lata podzielne równo przez 100 nie są latami przestępnymi, chyba że są one również podzielne równo przez 400, w którym to przypadku są to lata przestępne.
Cameron

No cóż, poprawiono mnie. Wydaje się, że @minitech ma właściwą odpowiedź.
Alex Turpin

Odpowiedzi:


138

Następująca edycja OP:

var now = new Date();
var start = new Date(now.getFullYear(), 0, 0);
var diff = now - start;
var oneDay = 1000 * 60 * 60 * 24;
var day = Math.floor(diff / oneDay);
console.log('Day of year: ' + day);

Edycja: powyższy kod nie powiedzie się, jeśli nowjest data między 26 marca a 29 października now, a godzina przypada przed 1 w nocy (np. 00:59:59). Wynika to z faktu, że kod nie uwzględnia czasu letniego. Powinieneś to zrekompensować :

var now = new Date();
var start = new Date(now.getFullYear(), 0, 0);
var diff = (now - start) + ((start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000);
var oneDay = 1000 * 60 * 60 * 24;
var day = Math.floor(diff / oneDay);
console.log('Day of year: ' + day);


5
Math.floorkonsekwentnie dawał mi wynik o 1 dzień mniej niż oczekiwano po pewnym kwietniowym dniu. Math.ceildziałało zgodnie z oczekiwaniami, ale widziałem, że zaleca się użycie Math.roundzamiast jednego z nich.
baacke

3
Składnik dnia to podstawa-1. tj. aby reprezentować 1 stycznia tego roku, użyjesz new Date(2014, 0, 1), a nie new Date(2014, 0, 0)tak, jak tutaj. Czy to zamierzone? Być może to właśnie wyjaśnia, że ​​jeden dzień jest wolny, co new Date(2014, 0, 0)wróci 12/31/2013.
Kirk Woll,

1
Może użyj .setUTCHoursi Date.UTC()dla bardziej niezawodnego rozwiązania.
Noyo

6
@AlexTurpin, @ T30: Wiem, że to trochę stare, ale jeśli się zastanawiałeś ... problem jest spowodowany tym, że czas letni zaczyna się w marcu. Dzieje się tak, ponieważ kiedy weźmiesz różnicę między północą w dniu przed czasem letnim a północą w dniu po czasie letnim, nie będziesz mieć liczby milisekund równo podzielnej przez 1000 * 60 * 60 * 24 (będzie to dokładnie jedna godzina przerwy) . Najłatwiejszym rozwiązaniem jest użycie ceilzamiast floor, to da ci system numeracji, w którym 1 stycznia = 1. Jeśli chcesz, aby 1 stycznia = 0 (jak floorbyś dał), po prostu odejmij 1 od końcowego wyniku.
Warren R.

2
Aby wziąć pod uwagę strefy czasowe i czas letni, zmień wiersz 3 na: var diff = now - start + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
Marlon

46

Działa to niezależnie od zmian czasu letniego we wszystkich krajach (opcja „południe” powyżej nie działa w Australii):

Date.prototype.isLeapYear = function() {
    var year = this.getFullYear();
    if((year & 3) != 0) return false;
    return ((year % 100) != 0 || (year % 400) == 0);
};

// Get Day of Year
Date.prototype.getDOY = function() {
    var dayCount = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
    var mn = this.getMonth();
    var dn = this.getDate();
    var dayOfYear = dayCount[mn] + dn;
    if(mn > 1 && this.isLeapYear()) dayOfYear++;
    return dayOfYear;
};

1
Zgadzam się, że w zaakceptowanej odpowiedzi są błędy związane z czasem letnim. Powyższe rozwiązanie jest lepsze i szybsze. Oto jego odmiana, którą przetestowałem na jsPerf jsperf.com/date-getdayofyear-perf
Shyam Habarakada,

@ShyamHabarakada: kod w twoim benchmarku jest uszkodzony, getDay()należy go zmienić na getDate(). Ta pierwsza zwraca dzień tygodnia (0 = niedziela..6 = sobota), a nie dzień.
CodeManX

32

Uważam za bardzo interesujące, że nikt nie rozważał używania UTC, ponieważ nie podlega on DST. Dlatego proponuję co następuje:

function daysIntoYear(date){
    return (Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - Date.UTC(date.getFullYear(), 0, 0)) / 24 / 60 / 60 / 1000;
}

Możesz to przetestować, wykonując następujące czynności:

[new Date(2016,0,1), new Date(2016,1,1), new Date(2016,2,1), new Date(2016,5,1), new Date(2016,11,31)]
    .forEach(d => 
        console.log(`${d.toLocaleDateString()} is ${daysIntoYear(d)} days into the year`));

Jakie dane wyjściowe za rok przestępny 2016 (zweryfikowano na stronie http://www.epochconverter.com/days/2016 ):

1/1/2016 is 1 days into the year
2/1/2016 is 32 days into the year
3/1/2016 is 61 days into the year
6/1/2016 is 153 days into the year
12/31/2016 is 366 days into the year

Może to spowodować przepełnienie, ponieważ liczba milisekund jest zbyt duża.
knt5784

@ knt5784 Matematyka może się przepełniać, ale jego przykład pokazuje największą możliwą wartość rzeczywistą, więc powinieneś być w porządku z tym, chyba że występuje problem z przeglądarką z przepełnieniem całkowitych.
Per Fagrell

Osobiście podoba mi się to podejście. Znacznie czystszy (i bardzo sprytny!) Sposób na uniknięcie problemów z czasem letnim. Jeśli ktoś się zastanawia, jak przekonwertować z DOY do tej pory, jest to znacznie prostsze. Zasadniczo po prostu tworzysz datę stycznia DOY. Na przykład 59 stycznia === 28 lutego. Dzień przestępny jest obsługiwany dobrze. function doyToDate(doy, year) { return new Date(year, 0, doy); }
Kip

@ knt5784 Nie ma ryzyka przepełnienia milisekund z tym kodem, przynajmniej nie przez następne 200 000 lat. Największa data obsługiwana przez Date to new Date(8640000000000000), która wciąż jest mniejsza niż Number.MAX_SAFE_INTEGER. zobacz odpowiedź: stackoverflow.com/a/11526569/18511
Kip

18
Date.prototype.dayOfYear= function(){
    var j1= new Date(this);
    j1.setMonth(0, 0);
    return Math.round((this-j1)/8.64e7);
}

alert(new Date().dayOfYear())

3
To nie przejdzie kłaczków ... Modyfikowanie obiektu, który nie jest twój, szczególnie globalnego. To również zawiodłoby na planetach o ekstremalnym nachyleniu, gdzie czas letni przekracza 12 godzin. Ale bardziej realistycznie, jeśli kodujesz przeglądarkę, która umożliwia zmianę strefy czasowej obiektu Date, strefą czasową j1 może być Australia, a strefą czasową może być Alaska, co przerywa zaokrąglanie.
Ray Foss

11

Na szczęście to pytanie nie określa, czy wymagany jest numer bieżącego dnia, pozostawiając miejsce na tę odpowiedź.
Również niektóre odpowiedzi (również na inne pytania) zawierały problemy z rokiem przestępnym lub wykorzystywały obiekt Date. Chociaż javascript Date objectobejmuje około 285616 lat (100 000 000 dni) po obu stronach 1 stycznia 1970 r., Miałem dość wszelkiego rodzaju nieoczekiwanych niespójności dat w różnych przeglądarkach (zwłaszcza w latach od 0 do 99). Byłem też ciekawy, jak to obliczyć.

Napisałem więc prosty i przede wszystkim mały algorytm do obliczania prawidłowego ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (punkt 4.3.2.1), więc rok0 istnieje i jest rokiem przestępnym, a lata ujemne są obsługiwane ) dzień roku na podstawie roku , miesiąca i dnia .
Zauważ, że w AD/BCnotacji rok 0 AD / BC nie istnieje: zamiast tego rok 1 BCjest rokiem przestępnym! JEŚLI musisz uwzględnić notację BC, po prostu odejmij najpierw jeden rok (w przeciwnym razie dodatniej) wartości roku !!

Zmodyfikowałem (dla javascript) algorytm zwarcia bitmask-modulo leapYear i wymyśliłem magiczną liczbę, aby wykonać bitowe wyszukiwanie przesunięć (które wykluczają jan i feb, a zatem potrzebuję 10 * 3 bitów (30 bitów to mniej niż 31 bitów, dzięki czemu możemy bezpiecznie zapisać inny znak na przesunięciu bitu zamiast >>>)).

Pamiętaj, że nie może być ani miesiąc ani dzień 0. Oznacza to, że jeśli potrzebujesz tego równania tylko na bieżący dzień (karmienie go za pomocą .getMonth()), wystarczy usunąć --from --m.

Zauważ, że zakłada to prawidłową datę (chociaż sprawdzanie błędów to tylko kilka znaków więcej).

function dayNo(y,m,d){
  return --m*31-(m>1?(1054267675>>m*3-6&7)-(y&3||!(y%25)&&y&15?0:1):0)+d;
}
<!-- some examples for the snippet -->
<input type=text value="(-)Y-M-D" onblur="
  var d=this.value.match(/(-?\d+)[^\d]+(\d\d?)[^\d]+(\d\d?)/)||[];
  this.nextSibling.innerHTML=' Day: ' + dayNo(+d[1], +d[2], +d[3]);
" /><span></span>

<br><hr><br>

<button onclick="
  var d=new Date();
  this.nextSibling.innerHTML=dayNo(d.getFullYear(), d.getMonth()+1, d.getDate()) + ' Day(s)';
">get current dayno:</button><span></span>


Oto wersja z poprawną walidacją zakresu.

function dayNo(y,m,d){
  return --m>=0 && m<12 && d>0 && d<29+(  
           4*(y=y&3||!(y%25)&&y&15?0:1)+15662003>>m*2&3  
         ) && m*31-(m>1?(1054267675>>m*3-6&7)-y:0)+d;
}
<!-- some examples for the snippet -->
<input type=text value="(-)Y-M-D" onblur="
  var d=this.value.match(/(-?\d+)[^\d]+(\d\d?)[^\d]+(\d\d?)/)||[];
  this.nextSibling.innerHTML=' Day: ' + dayNo(+d[1], +d[2], +d[3]);
" /><span></span>

Znowu jedna linia, ale podzieliłem ją na 3 linie dla większej czytelności (i po wyjaśnieniu).

Ostatni wiersz jest identyczny z powyższą funkcją, jednak (identyczny) algorytm roku przestępnego zostaje przeniesiony do poprzedniej sekcji zwarciowej (przed obliczeniem numeru dnia), ponieważ trzeba również wiedzieć, ile dni w miesiącu ma dany rok (przestępny).

Środkowa linia oblicza poprawną liczbę przesunięcia (dla maksymalnej liczby dni) dla danego miesiąca w danym (przestępnym) roku przy użyciu innej magicznej liczby: ponieważ 31-28=3i 3wynosi tylko 2 bity, to 12*2=24bity, możemy przechowywać wszystkie 12 miesięcy. Ponieważ dodawanie może być szybsze niż odejmowanie, dodajemy przesunięcie (zamiast odejmować 31). Aby uniknąć gałęzi decyzyjnej roku przestępnego w lutym, modyfikujemy tę magiczną liczbę wyszukiwania w locie.

To pozostawia nam (dość oczywistą) pierwszą linię: sprawdza, czy miesiąc i data mieszczą się w prawidłowych granicach i zapewnia nam falsezwrot wartości w przypadku błędu zakresu (zwróć uwagę, że ta funkcja również nie powinna być w stanie zwrócić 0, ponieważ 1 stycznia 0000 jest jeszcze dzień 1.), zapewniając łatwy sprawdzanie błędów: if(r=dayNo(/*y, m, d*/)){}.
Jeśli jest używany w ten sposób (gdzie miesiąc i dzień mogą nie występować 0), można zmienić --m>=0 && m<12na m>0 && --m<12(zapisując kolejny znak).
Powodem, dla którego wpisałem fragment w jego aktualnej formie, jest to, że dla wartości miesiąca opartych na 0 wystarczy usunąć --from --m.

Dodatkowo:
Uwaga, nie używaj algorytmu tego dnia na miesiąc, jeśli potrzebujesz tylko maksymalnej liczby dni w miesiącu. W takim przypadku istnieje bardziej wydajny algorytm (ponieważ potrzebujemy leepYear tylko wtedy, gdy miesiąc jest luty) jako odpowiedź na pytanie: Jaki jest najlepszy sposób określenia liczby dni w miesiącu za pomocą javascript? .


1
Wrzuciłem to do funkcji daty, aby ułatwić korzystanie z niej. Niespójności dotyczące daty () nadal stanowią problem, ale używam lat 2015+, więc mam nadzieję, że są spójne. Biedny JSHint zginął próbując zweryfikować twój kod hahah. Date.prototype.dayNo = function(){ var y = this.getFullYear(); var m = this.getMonth()+1; var d = this.getDate(); return --m*31-(m>1?(1054267675>>m*3-6&7)-(y&3||!(y%25)&&y&15?0:1):0)+d; };
freshvolk

Cieszę się, że Ci się podobało. Ten algorytm jest w pełni testowany przez 2 ^ 31-1 lat (imponujące 2147483647, to jest> 7500 razy więcej niż zakres obiektu daty w JavaScript) po obu stronach 0. ( Może działać dla 2 ^ 32, ale nie testowałem tego jeszcze). Ponadto, można ponownie przeczytać moją odpowiedź: można golić się +1z this.getMonth()+1jeśli usunąć --z --m. EDYCJA Tak więc zrobiłbym (dla biblioteki):Date.prototype.dayNo = function(){ var y=this.getFullYear(), m=this.getMonth(); return m*31-(m>1?(1054267675>>m*3-6&7)-(y&3||!(y%25)&&y&15?0:1):0)+this.getDate(); };
GitaarLAB

Właściwie to właśnie to zrobiłem, kiedy na to patrzyłem! Zdałem sobie sprawę, że dodaję jeden, a potem natychmiast go odejmuję. Myślę, że zanim dojdziemy do 2^31 - 2016lat, js prawdopodobnie będzie trochę przestarzały.
freshvolk

@Freshvolk: lol, dlatego nigdy nie testowałem go powyżej 2 ^ 31 :)Ale do tego czasu da przynajmniej przewidywalne i spójne wyniki haha. EDYTUJ , tylko dla teorii, używając wolniejszego konwencjonalnego algorytmu all-modulo dla leapyear, zakres można rozszerzyć do 2 ^ 53. Algorytm wyszukiwania miesiąca nie jest czynnikiem ograniczającym.
GitaarLAB

5

Jeśli nie chcesz wymyślać koła na nowo, możesz skorzystać z doskonałej biblioteki date-fns (node.js):

var getDayOfYear = require('date-fns/get_day_of_year')

var dayOfYear = getDayOfYear(new Date(2017, 1, 1)) // 1st february => 32

4

Cóż, jeśli dobrze cię rozumiem, chcesz 366 w roku przestępnym, 365 w przeciwnym razie, prawda? Rok jest rokiem przestępnym, jeśli jest podzielny równo przez 4, ale nie przez 100, chyba że jest również podzielny przez 400:

function daysInYear(year) {
    if(year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) {
        // Leap year
        return 366;
    } else {
        // Not a leap year
        return 365;
    }
}

Edytuj po aktualizacji:

W takim przypadku nie sądzę, że istnieje wbudowana metoda; musisz to zrobić:

function daysInFebruary(year) {
    if(year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) {
        // Leap year
        return 29;
    } else {
        // Not a leap year
        return 28;
    }
}

function dateToDay(date) {
    var feb = daysInFebruary(date.getFullYear());
    var aggregateMonths = [0, // January
                           31, // February
                           31 + feb, // March
                           31 + feb + 31, // April
                           31 + feb + 31 + 30, // May
                           31 + feb + 31 + 30 + 31, // June
                           31 + feb + 31 + 30 + 31 + 30, // July
                           31 + feb + 31 + 30 + 31 + 30 + 31, // August
                           31 + feb + 31 + 30 + 31 + 30 + 31 + 31, // September
                           31 + feb + 31 + 30 + 31 + 30 + 31 + 31 + 30, // October
                           31 + feb + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, // November
                           31 + feb + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, // December
                         ];
    return aggregateMonths[date.getMonth()] + date.getDate();
}

(Tak, faktycznie zrobiłem to bez kopiowania ani wklejania. Jeśli istnieje łatwy sposób, oszaleję)


Mój łatwy sposób to po prostu użycie magicznej liczby 1054267675 i nazwanie go dniem, jestem :)
zbyt

4

Jest to prosty sposób na znalezienie bieżącego dnia w roku i powinien bez problemu uwzględniać lata przestępne:

JavaScript:

Math.round((new Date().setHours(23) - new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0))/1000/60/60/24);

JavaScript w Google Apps Script:

Math.round((new Date().setHours(23) - new Date(new Date().getYear(), 0, 1, 0, 0, 0))/1000/60/60/24);

Podstawowym działaniem tego kodu jest znalezienie liczby milisekund, które upłynęły w bieżącym roku, a następnie przeliczenie tej liczby na dni. Liczbę milisekund, które upłynęły w bieżącym roku, można znaleźć, odejmując liczbę milisekund pierwszej sekundy pierwszego dnia bieżącego roku, którą uzyskuje się za pomocą new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0)(Javascript) lub new Date(new Date().getYear(), 0, 1, 0, 0, 0)(Google Apps Script), od milisekund 23 godziny bieżącego dnia, które znaleziono z new Date().setHours(23). Ustawienie bieżącej daty na 23. godzinę ma na celu zapewnienie prawidłowego zaokrąglenia dnia w roku o Math.round().

Gdy masz już liczbę milisekund bieżącego roku, możesz przekonwertować ten czas na dni, dzieląc przez 1000, aby zamienić milisekundy na sekundy, a następnie dzieląc przez 60, aby zamienić sekundy na minuty, a następnie przez 60, aby zamienić minuty na godziny, i na koniec dzieląc przez 24, aby zamienić godziny na dni.

Uwaga: ten post został zredagowany w celu uwzględnienia różnic między JavaScriptem a JavaScriptem zaimplementowanym w Google Apps Script. Do odpowiedzi dodano również szerszy kontekst.


Czy możesz wyjaśnić trochę więcej niż tylko powiedzenie, że działa?
Stephen Reindl

Tak! Przepraszam, że przede wszystkim nie podałem więcej szczegółów. Wyrażenie w instrukcji „Math.round” znajduje liczbę milisekund w bieżącym roku, odejmując pierwszy dzień roku od milisekund ostatniej godziny bieżącego dnia roku. Liczba milisekund jest następnie dzielona przez 1000 w celu konwersji na sekundy, 60 w celu konwersji na minuty, 60 w celu konwersji na godziny i 24 w celu konwersji na dni. Wyrażenie jest opakowane w funkcję „Math.round ()”, dzięki czemu zaokrągla do liczby całkowitej określającej dzień roku.
Liz Page-Gould

Powinienem też dodać, że to rozwiązanie jest zasadniczo takie samo jak rozwiązanie „zaakceptowane”, z wyjątkiem tego, że robi wszystko w jednej linii kodu.
Liz Page-Gould

Jak to wpływa na czas letni? Czy to by tego trochę nie zepsuło?
Dan Oswalt

Nie, czas letni nie wpłynie na te obliczenia, ponieważ czas letni ma rozdzielczość godzin, a ten kod oblicza liczbę dni w roku. Ponadto, ponieważ zastosowałem .setHoursmetodę na pierwszym obiekcie daty i określiłem porę dnia w drugim obiekcie daty, zmiana o 1 godzinę od czasu letniego nie wpłynie na czasy obiektów Date użytych w tych obliczeniach.
Liz Page-Gould

4

Myślę, że jest to prostsze:

var date365 = 0;

var currentDate = new Date();
var currentYear = currentDate.getFullYear();
var currentMonth = currentDate.getMonth(); 
var currentDay = currentDate.getDate(); 

var monthLength = [31,28,31,30,31,30,31,31,30,31,30,31];

var leapYear = new Date(currentYear, 1, 29); 
if (leapYear.getDate() == 29) { // If it's a leap year, changes 28 to 29
    monthLength[1] = 29;
}

for ( i=0; i < currentMonth; i++ ) { 
    date365 = date365 + monthLength[i];
}
date365 = date365 + currentDay; // Done!

3

Ta metoda bierze pod uwagę kwestię strefy czasowej i czasu letniego

function dayofyear(d) {   // d is a Date object
    var yn = d.getFullYear();
    var mn = d.getMonth();
    var dn = d.getDate();
    var d1 = new Date(yn,0,1,12,0,0); // noon on Jan. 1
    var d2 = new Date(yn,mn,dn,12,0,0); // noon on input date
    var ddiff = Math.round((d2-d1)/864e5);
    return ddiff+1; 
}

(wzięte stąd )

Zobacz też to skrzypce


Jest to trochę nieefektywne, ale działa doskonale. Możesz po prostu uzyskać czas dla obiektów i ustawićDate zmienić datę na dzień 1. Oba są doskonale obsługiwane. Chodzi o to, że nie będziesz się poruszać po strefach czasowych. Zakłada się również, że czas letni to mniej niż 12 godzin ... co jest bezpiecznym założeniem na Ziemi.
Ray Foss

2

Math.round ((new Date (). SetHours (23) - new Date (new Date (). GetFullYear (), 0, 1, 0, 0, 0)) / 1000/86400);

dodatkowo optymalizuje odpowiedź.

Ponadto, zmieniając setHours (23) lub przedostatnie dwa zera później na inną wartość, można podać dzień roku związany z inną strefą czasową. Na przykład, aby pobrać z Europy zasób znajdujący się w Ameryce.


1
Math.floor((Date.now() - Date.parse(new Date().getFullYear(), 0, 0)) / 86400000)

to jest moje rozwiązanie


Używam 31 grudnia poprzedniego roku, aby zrobić 01 stycznia = DOY 01. Również odkryłem, że 10 marca ma taki sam DOY jak 11 marca, ponieważ jeden miał 69, a drugi 69,9 coś, obie podłogi to 69. Wykonanie Math.round zamiast tego naprawiło . Uważam, że albo 10 marca, albo 11 marca to zmiana czasu letniego, co powoduje, że 11 marca nie jest całkiem DOY 70.
user3015682

0

Stworzyłem taki, który jest czytelny i bardzo szybko załatwi sprawę, a także obsłuży obiekty JS Date z różnymi strefami czasowymi.

Dołączyłem sporo przypadków testowych dla stref czasowych, czasu letniego, sekund przestępnych i lat przestępnych.

PS ECMA-262 ignoruje sekundy przestępne, w przeciwieństwie do UTC. Jeśli miałbyś przekonwertować to na język, który używa prawdziwego UTC, możesz po prostu dodać 1 do oneDay.

// returns 1 - 366
findDayOfYear = function (date) {
  var oneDay = 1000 * 60 * 60 * 24; // A day in milliseconds
  var og = {                        // Saving original data
    ts: date.getTime(),
    dom: date.getDate(),            // We don't need to save hours/minutes because DST is never at 12am.
    month: date.getMonth()
  }
  date.setDate(1);                  // Sets Date of the Month to the 1st.
  date.setMonth(0);                 // Months are zero based in JS's Date object
  var start_ts = date.getTime();    // New Year's Midnight JS Timestamp
  var diff = og.ts - start_ts;

  date.setDate(og.dom);             // Revert back to original date object
  date.setMonth(og.month);          // This method does preserve timezone
  return Math.round(diff / oneDay) + 1; // Deals with DST globally. Ceil fails in Australia. Floor Fails in US.
}

// Tests
var pre_start_dst = new Date(2016, 2, 12);
var on_start_dst = new Date(2016, 2, 13);
var post_start_dst = new Date(2016, 2, 14);

var pre_end_dst_date = new Date(2016, 10, 5);
var on_end_dst_date = new Date(2016, 10, 6);
var post_end_dst_date = new Date(2016, 10, 7);

var pre_leap_second = new Date(2015, 5, 29);
var on_leap_second = new Date(2015, 5, 30);
var post_leap_second = new Date(2015, 6, 1);

// 2012 was a leap year with a leap second in june 30th
var leap_second_december31_premidnight = new Date(2012, 11, 31, 23, 59, 59, 999);

var january1 = new Date(2016, 0, 1);
var january31 = new Date(2016, 0, 31);

var december31 = new Date(2015, 11, 31);
var leap_december31 = new Date(2016, 11, 31);

alert( ""
  + "\nPre Start DST: " + findDayOfYear(pre_start_dst) + " === 72"
  + "\nOn Start DST: " + findDayOfYear(on_start_dst) + " === 73"
  + "\nPost Start DST: " + findDayOfYear(post_start_dst) + " === 74"
      
  + "\nPre Leap Second: " + findDayOfYear(pre_leap_second) + " === 180"
  + "\nOn Leap Second: " + findDayOfYear(on_leap_second) + " === 181"
  + "\nPost Leap Second: " + findDayOfYear(post_leap_second) + " === 182"
      
  + "\nPre End DST: " + findDayOfYear(pre_end_dst_date) + " === 310"
  + "\nOn End DST: " + findDayOfYear(on_end_dst_date) + " === 311"
  + "\nPost End DST: " + findDayOfYear(post_end_dst_date) + " === 312"
      
  + "\nJanuary 1st: " + findDayOfYear(january1) + " === 1"
  + "\nJanuary 31st: " + findDayOfYear(january31) + " === 31"
  + "\nNormal December 31st: " + findDayOfYear(december31) + " === 365"
  + "\nLeap December 31st: " + findDayOfYear(leap_december31) + " === 366"
  + "\nLast Second of Double Leap: " + findDayOfYear(leap_second_december31_premidnight) + " === 366"
);


0

Chciałbym przedstawić rozwiązanie, które wykonuje obliczenia, dodając dni z każdego poprzedniego miesiąca:

function getDayOfYear(date) {
    var month = date.getMonth();
    var year = date.getFullYear();
    var days = date.getDate();
    for (var i = 0; i < month; i++) {
        days += new Date(year, i+1, 0).getDate();
    }
    return days;
}
var input = new Date(2017, 7, 5);
console.log(input);
console.log(getDayOfYear(input));

W ten sposób nie musisz zarządzać szczegółami lat przestępnych i czasu letniego.


0

Alternatywa wykorzystująca znaczniki czasu UTC. Również, jak zauważyli inni, dzień wskazujący jako pierwszy miesiąc to 1 zamiast 0. Miesiąc zaczyna się jednak od 0.

var now = Date.now();
var year =  new Date().getUTCFullYear();
var year_start = Date.UTC(year, 0, 1);
var day_length_in_ms = 1000*60*60*24;
var day_number = Math.floor((now - year_start)/day_length_in_ms)
console.log("Day of year " + day_number);

0

Możesz przekazać parametr jako numer daty w setDatefunkcji:

var targetDate = new Date();
targetDate.setDate(1);

// Now we can see the expected date as: Mon Jan 01 2018 01:43:24
console.log(targetDate);

targetDate.setDate(365);

// You can see: Mon Dec 31 2018 01:44:47
console.log(targetDate)

0

Może to być przydatne dla tych, którzy potrzebują dnia roku jako ciągu znaków i mają dostępny interfejs użytkownika jQuery.

Możesz użyć jQuery UI Datepicker:

day_of_year_string = $.datepicker.formatDate("o", new Date())

Pod spodem działa tak samo, jak niektóre z już wymienionych odpowiedzi ( (date_ms - first_date_of_year_ms) / ms_per_day):

function getDayOfTheYearFromDate(d) {
    return Math.round((new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime() 
- new Date(d.getFullYear(), 0, 0).getTime()) / 86400000);
}

day_of_year_int = getDayOfTheYearFromDate(new Date())

0

Dla tych z nas, którzy chcą szybkiego alternatywnego rozwiązania.

(function(){"use strict";
function daysIntoTheYear(dateInput){
    var fullYear = dateInput.getFullYear()|0;
	// "Leap Years are any year that can be exactly divided by 4 (2012, 2016, etc)
 	//	except if it can be exactly divided by 100, then it isn't (2100, 2200, etc)
 	//		except if it can be exactly divided by 400, then it is (2000, 2400)"
	// (https://www.mathsisfun.com/leap-years.html).
    var isLeapYear = ((fullYear & 3) | (fullYear/100 & 3)) === 0 ? 1 : 0;
	// (fullYear & 3) = (fullYear % 4), but faster
    //Alternative:var isLeapYear=(new Date(currentYear,1,29,12)).getDate()===29?1:0
    var fullMonth = dateInput.getMonth()|0;
    return ((
        // Calculate the day of the year in the Gregorian calendar
        // The code below works based upon the facts of signed right shifts
        //    • (x) >> n: shifts n and fills in the n highest bits with 0s 
        //    • (-x) >> n: shifts n and fills in the n highest bits with 1s
        // (This assumes that x is a positive integer)
        (31 & ((-fullMonth) >> 4)) + // January // (-11)>>4 = -1
        ((28 + isLeapYear) & ((1-fullMonth) >> 4)) + // February
        (31 & ((2-fullMonth) >> 4)) + // March
        (30 & ((3-fullMonth) >> 4)) + // April
        (31 & ((4-fullMonth) >> 4)) + // May
        (30 & ((5-fullMonth) >> 4)) + // June
        (31 & ((6-fullMonth) >> 4)) + // July
        (31 & ((7-fullMonth) >> 4)) + // August
        (30 & ((8-fullMonth) >> 4)) + // September
        (31 & ((9-fullMonth) >> 4)) + // October
        (30 & ((10-fullMonth) >> 4)) + // November
        // There are no months past December: the year rolls into the next.
        // Thus, fullMonth is 0-based, so it will never be 12 in Javascript

        (dateInput.getDate()|0) // get day of the month

    )&0xffff);
}
// Demonstration:
var date = new Date(2100, 0, 1)
for (var i=0; i<12; i=i+1|0, date.setMonth(date.getMonth()+1|0))
    console.log(date.getMonth()+":\tday "+daysIntoTheYear(date)+"\t"+date);
date = new Date(1900, 0, 1);
for (var i=0; i<12; i=i+1|0, date.setMonth(date.getMonth()+1|0))
    console.log(date.getMonth()+":\tday "+daysIntoTheYear(date)+"\t"+date);

// Performance Benchmark:
console.time("Speed of processing 65536 dates");
for (var i=0,month=date.getMonth()|0; i<65536; i=i+1|0)
    date.setMonth(month=month+1+(daysIntoTheYear(date)|0)|0);
console.timeEnd("Speed of processing 65536 dates");
})();

Rozmiar miesięcy w roku i sposób, w jaki działają lata przestępne, doskonale wpisują się w utrzymywanie naszego czasu zgodnie ze słońcem. Do licha, działa tak doskonale, że wszystko, co robimy, to po prostu dostosowujemy tylko kilka sekund tu i tam . Nasz obecny system lat przestępnych obowiązuje od 24 lutego 1582 roku i prawdopodobnie pozostanie w mocy w dającej się przewidzieć przyszłości.

Czas letni może się jednak bardzo zmienić. Może się zdarzyć, że za 20 lat jakiś kraj może przesunąć czas o cały dzień lub inną skrajność dla czasu letniego. Cały dzień czasu letniego prawie na pewno nigdy się nie wydarzy, ale mimo to czas letni jest nadal bardzo aktywny i niezdecydowany. Dlatego powyższe rozwiązanie jest przyszłościowe, a ponadto jest bardzo szybkie.

Powyższy fragment kodu działa bardzo szybko. Mój komputer może przetwarzać 65536 dat w ~ 52 ms w przeglądarce Chrome.


0

const dayOfYear = date => {
    const myDate = new Date(date);
    const year = myDate.getFullYear();
    const firstJan = new Date(year, 0, 1);
    const differenceInMillieSeconds = myDate - firstJan;
    return (differenceInMillieSeconds / (1000 * 60 * 60 * 24) + 1);
};

const result = dayOfYear("2019-2-01");
console.log(result);


0

Jest to rozwiązanie, które pozwala uniknąć kłopotliwych problemów z obiektem Date i strefą czasową, wymaga, aby data wejściowa była w formacie „rrrr-dd-mm”. Jeśli chcesz zmienić format, zmodyfikuj funkcję date_str_to_parts:

    function get_day_of_year(str_date){
    var date_parts = date_str_to_parts(str_date);
    var is_leap = (date_parts.year%4)==0;
    var acct_for_leap = (is_leap && date_parts.month>2);
    var day_of_year = 0;

    var ary_months = [
        0,
        31, //jan
        28, //feb(non leap)
        31, //march
        30, //april
        31, //may
        30, //june
        31, //july
        31, //aug
        30, //sep
        31, //oct
        30, //nov   
        31  //dec
        ];


    for(var i=1; i < date_parts.month; i++){
        day_of_year += ary_months[i];
    }

    day_of_year += date_parts.date;

    if( acct_for_leap ) day_of_year+=1;

    return day_of_year;

}

function date_str_to_parts(str_date){
    return {
        "year":parseInt(str_date.substr(0,4),10),
        "month":parseInt(str_date.substr(5,2),10),
        "date":parseInt(str_date.substr(8,2),10)
    }
}

-1

Zawsze się martwię, gdy mieszam matematykę z funkcjami daty (tak łatwo jest przegapić jakiś rok przestępny i inne szczegóły). Powiedz, że masz:

var d = new Date();

Sugerowałbym użycie następujących, dni zostaną zapisane w day:

for(var day = d.getDate(); d.getMonth(); day += d.getDate())
    d.setDate(0);

Nie widzę powodu, dla którego to nie działałoby dobrze (i nie martwiłbym się tak kilkoma iteracjami, ponieważ nie będzie to używane tak intensywnie).


-1

/ * UŻYJ TEGO SKRYPTU * /

var today = new Date();
var first = new Date(today.getFullYear(), 0, 1);
var theDay = Math.round(((today - first) / 1000 / 60 / 60 / 24) + .5, 0);
alert("Today is the " + theDay + (theDay == 1 ? "st" : (theDay == 2 ? "nd" : (theDay == 3 ? "rd" : "th"))) + " day of the year");
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.