169

How do I use JavaScript to calculate the day of the year, from 1 - 366?

For example:

  • January 3 should be 3.
  • February 1 should be 32.
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
  • 4
    `var days = new Date().getFullYear() % 4 == 0 ? 366 : 365;` – Alex Turpin Dec 23 '11 at 19:27
  • But really I'm not sure what you mean. You just want the number of days in the year? Or between two dates? – Alex Turpin Dec 23 '11 at 19:28
  • 26
    fyi @xeon06, leap year calculation is a bit more complicated than mod'ing by 4. see: [leap year algorithm](http://en.wikipedia.org/wiki/Leap_year#Algorithm) – Matt Felzani Dec 23 '11 at 19:29
  • 5
    @Xeon06: That's correct only most of the time. From [Wikipedia](http://en.wikipedia.org/wiki/Leap_year): Years that are evenly divisible by 100 are not leap years, unless they are also evenly divisible by 400, in which case they *are* leap years. – Cameron Dec 23 '11 at 19:30
  • Ah well I stand corrected. @minitech seems to have the right answer then. – Alex Turpin Dec 23 '11 at 19:31
  • Sorry Xeon06, I want to get year-to-date. –  Dec 23 '11 at 19:33
  • I can't believe there is not an existing function on the Date object for this. – dmikester1 Apr 13 '20 at 18:37

28 Answers28

195

Following OP's edit:

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);

Edit: The code above will fail when now is a date in between march 26th and October 29th andnow's time is before 1AM (eg 00:59:59). This is due to the code not taking daylight savings time into account. You should compensate for this:

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);
Koen Peters
  • 12,798
  • 6
  • 36
  • 59
Alex Turpin
  • 46,743
  • 23
  • 113
  • 145
  • 5
    `Math.floor` consistently gave me a result of 1 day less than expected after a certain day in April. `Math.ceil` worked as expected, but I have seen it be advised that you use `Math.round` instead of either. – baacke Jan 15 '14 at 17:45
  • 5
    The day component is base-1. i.e. to represent January 1st of this year, you'd use `new Date(2014, 0, 1)`, and not `new Date(2014, 0, 0)` as you have here. Is that intentional? Perhaps that's what accounts for being off by one day as `new Date(2014, 0, 0)` will return `12/31/2013`. – Kirk Woll Feb 14 '14 at 00:58
  • @Alex Turpin: when you don't specify a time, it takes the default (00:00) and it returns one day less. So, for example: `new Date(Aug 13 2014 01:00)` will return 225, but `new Date(Aug 13 2014)` will return 224. – T30 Aug 13 '14 at 12:57
  • @Alex Turpin: I'm very confused: the 'bug' explained in the last comment happens only with date > `March 30`.... (This 'threshold' date could change, depending on the year - I've tested 2014). How can this happen?? – T30 Aug 13 '14 at 13:19
  • @T30 Are you sure this isn't a timezone issue? Can you post some http://jsfiddle.net code highlighting the issue? – Alex Turpin Aug 14 '14 at 16:03
  • @AlexTurpin [**this**](http://jsfiddle.net/r6afgk5f/) is a simple fiddle showing the behaviour described above – T30 Aug 18 '14 at 16:32
  • @T30 This method isn't the most reliable it seems. I would suggest looking into a library such as [Moment.JS](http://momentjs.com/) to do this kind of calculations. – Alex Turpin Aug 18 '14 at 21:01
  • 2
    Maybe use [`.setUTCHours`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date/setUTCHours) and [`Date.UTC()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date/UTC) for a more reliable solution. – Noyo Oct 13 '14 at 14:03
  • 6
    @AlexTurpin, @T30: I know this is a bit old, but if you were wondering... the problem is caused because of Daylight Savings Time starting in March. This is because when you take the difference of a midnight of a date before DST and midnight of a date after DST you will not have a number of milliseconds evenly divisible by 1000 * 60 * 60 * 24 (it will be exactly one hour off). The easiest solution is to use `ceil` rather than `floor`, this will give you a numbering system where Jan 1st = 1. If you want Jan 1st = 0 (as `floor` would give you), just subtract 1 from your final result. – Warren R. Nov 04 '14 at 00:37
  • 1
    The math will fail (off by one) when now and start are across a DST boundary. @joe-orost has a better (and faster) solution below. – Shyam Habarakada Dec 11 '14 at 18:42
  • 2
    To take timezones and daylight savings into account, change line 3 to: `var diff = now - start + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;` – Marlon Apr 13 '15 at 12:16
  • I'd say don't use floor or ceil, you should get a whole number if the math is right, but I guess you could use round if you're paranoid about precision. Also, take into account DST as mentioned above. Finally, `+ 1` at the end for a one-based result. Assuming `d` is your `Date` object: `Math.round(((d - new Date(d.getFullYear(), 0, 1)) / 1000 / 60 / 60 / 24) + (((new Date(d.getFullYear(), 0, 1).getTimezoneOffset() - d.getTimezoneOffset())) / (60 * 24)))`. – Bryan Matthews Dec 18 '15 at 21:44
  • I attempted to edit this answer because I'm getting the following result: https://www.dropbox.com/s/yy31auvekpip7l5/Screenshot%202016-08-07%2016.13.26.png?dl=0 – Cory Robinson Aug 07 '16 at 23:14
  • 1
    thanks for writing `1000 * 60 * 60 * 24` and not `86400000` – Udo G Jul 01 '19 at 08:08
  • @KirkWoll Ya, it uses 31Dec so DOM starts at 1 and not at 0. var start = new Date(now.getFullYear(), 0, 0); is the same thing as var start2 = new Date(now.getFullYear()-1, 11, 31); – user3015682 Jul 12 '19 at 05:15
  • Do not use this. The solution by @user2501097 is much more elegant and robust. – enanone Nov 28 '20 at 18:20
  • How could this be done in typescript (substracting Date from Date generates an error TS2363). – Sam Mar 17 '21 at 14:53
  • 1
    @Sam try with `.valueOf()` for both – Alex Turpin Mar 18 '21 at 15:19
78

I find it very interesting that no one considered using UTC since it is not subject to DST. Therefore, I propose the following:

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

You can test it with the following:

[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`));

Which outputs for the leap year 2016 (verified using 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
user2501097
  • 1,011
  • 8
  • 4
  • This might overflow because the number of millisecond is too big. – knt5784 Jun 26 '19 at 21:57
  • @knt5784 The math might be able to overflow, but his example shows the largest possible real-world value working fine so you should be ok using this unless there's a browser based issue with integer overflow. – Per Fagrell Nov 02 '19 at 10:24
  • 2
    I personally like this approach. Much cleaner (and very clever!) way to avoid DST issues. If anyone is wondering how to convert from DOY back to date, it is much simpler. Basically, you just create a date of January DOYth. For example, January 59th === Feb 28. Leap day is handled fine. `function doyToDate(doy, year) { return new Date(year, 0, doy); }` – Kip Feb 22 '20 at 16:29
  • 2
    @knt5784 There's no risk of millisecond overflow with this code, at least not for another 200,000 years. The largest date supported by Date is `new Date(8640000000000000)`, which is still less than `Number.MAX_SAFE_INTEGER`. see this answer: https://stackoverflow.com/a/11526569/18511 – Kip Aug 04 '20 at 16:35
  • 4
    This should be marked as the correct answer – enanone Nov 28 '20 at 18:19
  • This is a great answer, but does any one else get confused when people stack up their divisions operators like ```x / 24 / 60 / 60 / 1000``` – dooderson Oct 07 '21 at 20:48
  • @dooderson No confusion. I always do this myself, because it makes very clear what you divide to, e.g. in this case, hours in a day (24), then minutes in an hour (60), then seconds in a minute (60), then milliseconds in a second (1000). More confusion could arise if you'd divide to 86 400 000, since if you didn't work with dates and times for a while, you'd have no idea what it means or where it comes from. Frankly, it makes no sense to use such numbers when you already know all their divisors, it's like using ~7854 for the area of a circle when you already know R=50, PI and Area=PI*R^2. – Yin Cognyto May 24 '22 at 20:30
  • To each his own but, at times I'd agree `const msDiff = Date.UTC(...) - Date.UTC(...);` then `const dayMilliseconds = 1000 * 60 * 60 * 24;` and then `return msDiff / dayMilliseconds;` can increase readability later. But that's really just getting into opinions. – AlienWithPizza Sep 02 '22 at 02:07
67

This works across Daylight Savings Time changes in all countries (the "noon" one above doesn't work in Australia):

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;
};
Joe Orost
  • 878
  • 7
  • 12
  • 1
    Agree that there are daylight savings related bugs in the accepted answer. The above solution is better and is faster. Here is a variation of it I tested on jsPerf http://jsperf.com/date-getdayofyear-perf – Shyam Habarakada Dec 11 '14 at 18:39
  • @ShyamHabarakada: the code in your benchmark is broken, `getDay()` needs to be changed to `getDate()`. The former returns the day of the week (0=Sunday..6=Saturday), not the day. – CodeManX Aug 30 '15 at 03:27
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())
insertusernamehere
  • 23,204
  • 9
  • 87
  • 126
kennebec
  • 102,654
  • 32
  • 106
  • 127
  • 3
    This would not pass lint... Modifying an object that is not yours, specially a global one. This would also fail in planets with extreme tilt where daylight savings time is over 12 hours. But more realistically, if you are coding for a browser that allows changing the Date object's timezone, j1's timezone could be Australia and this's timezone could be Alaska, breaking the rounding. – Ray Foss Mar 10 '16 at 15:30
16

Luckily this question doesn't specify if the number of the current day is required, leaving room for this answer.
Also some answers (also on other questions) had leap-year problems or used the Date-object. Although javascript's Date object covers approximately 285616 years (100,000,000 days) on either side of January 1 1970, I was fed up with all kinds of unexpected date inconsistencies across different browsers (most notably year 0 to 99). I was also curious how to calculate it.

So I wrote a simple and above all, small algorithm to calculate the correct (Proleptic Gregorian / Astronomical / ISO 8601:2004 (clause 4.3.2.1), so year 0 exists and is a leap year and negative years are supported) day of the year based on year, month and day.
Note that in AD/BC notation, year 0 AD/BC does not exist: instead year 1 BC is the leap-year! IF you need to account for BC notation then simply subtract one year of the (otherwise positive) year-value first!!

I modified (for javascript) the short-circuit bitmask-modulo leapYear algorithm and came up with a magic number to do a bit-wise lookup of offsets (that excludes jan and feb, thus needing 10 * 3 bits (30 bits is less than 31 bits, so we can safely save another character on the bitshift instead of >>>)).

Note that neither month or day may be 0. That means that if you need this equation just for the current day (feeding it using .getMonth()) you just need to remove the -- from --m.

Note this assumes a valid date (although error-checking is just some characters more).

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>

Here is the version with correct range-validation.

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>

Again, one line, but I split it into 3 lines for readability (and following explanation).

The last line is identical to the function above, however the (identical) leapYear algorithm is moved to a previous short-circuit section (before the day-number calculation), because it is also needed to know how much days a month has in a given (leap) year.

The middle line calculates the correct offset number (for max number of days) for a given month in a given (leap)year using another magic number: since 31-28=3 and 3 is just 2 bits, then 12*2=24 bits, we can store all 12 months. Since addition can be faster then subtraction, we add the offset (instead of subtract it from 31). To avoid a leap-year decision-branch for February, we modify that magic lookup-number on the fly.

That leaves us with the (pretty obvious) first line: it checks that month and date are within valid bounds and ensures us with a false return value on range error (note that this function also should not be able to return 0, because 1 jan 0000 is still day 1.), providing easy error-checking: if(r=dayNo(/*y, m, d*/)){}.
If used this way (where month and day may not be 0), then one can change --m>=0 && m<12 to m>0 && --m<12 (saving another char).
The reason I typed the snippet in it's current form is that for 0-based month values, one just needs to remove the -- from --m.

Extra:
Note, don't use this day's per month algorithm if you need just max day's per month. In that case there is a more efficient algorithm (because we only need leepYear when the month is February) I posted as answer this question: What is the best way to determine the number of days in a month with javascript?.

Community
  • 1
  • 1
GitaarLAB
  • 14,536
  • 11
  • 60
  • 80
  • 1
    I threw it into a date function for ease of use. Granted the Date() inconsistencies are still an issue, but I'm using years 2015+ so I hope they are consistent. Poor JSHint died trying to validate your code 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 Feb 02 '15 at 20:36
  • Glad you liked it. This algo is fully tested for 2^31-1 years (a whopping 2147483647, that's >7500 times the range of javascript's date-object) on both sides of 0. (It *might* work for 2^32, but I have not tested that yet). Also, you might read my answer again: you can shave off `+1` from `this.getMonth()+1` if you remove the `--` from `--m`. **EDIT** So, I would do (for a library): `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 Feb 02 '15 at 21:09
  • I actually just did that when I was looking at it! I realized I was adding one then subtracting it immediately. I think that by the time we get to `2^31 - 2016` years from now js will probably be a little outdated. – freshvolk Feb 02 '15 at 21:12
  • @Freshvolk: lol, which is why I never tested it beyond 2^31 `:)` But until then, it will at least give predictable and consistent results haha. **EDIT**, just for theory's sake, using the slower conventional all-modulo algo for leapyear, the range can be extended to 2^53. The month-lookup algo is not the limiting factor. – GitaarLAB Feb 02 '15 at 21:27
8

This is my solution:

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

Demo:

const getDateOfYear = (date) =>
  Math.floor((date.getTime() - new Date(date.getFullYear(), 0, 0)) / 864e5);

const dayOfYear = getDateOfYear(new Date());

console.log(dayOfYear);
Play_it
  • 109
  • 1
  • 12
  • I use Dec 31 of the previous year to make Jan 01 = DOY 01. Also I found March 10 has the same DOY as March 11 because one was 69 and the other 69.9 something, both flooring to 69. Doing Math.round instead fixed this. I believe either March 10 or March 11 is the daylight saving time switch which causes March 11 to not quite be DOY 70. – user3015682 Aug 23 '19 at 04:51
7

If used moment.js, we can get or even set the day of the year.

moment().dayOfYear();
//for getting 

moment().dayOfYear(Number); 
//for setting 

moment.js is using this code for day of year calculation

vusan
  • 5,221
  • 4
  • 46
  • 81
6

If you don't want to re-invent the wheel, you can use the excellent date-fns (node.js) library:

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

var dayOfYear = getDayOfYear(new Date(2017, 1, 1)) // 1st february => 32
Amaury Liet
  • 10,196
  • 3
  • 18
  • 24
  • 1
    This library has 200 functions and lots of chained dependencies, so it's a bad idea to add all this bulk and risk to solve this one problem, especially in a web app that needs extra steps to handle all that node module bloat. – Keith Feb 09 '22 at 08:23
5

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);
user7331530
  • 815
  • 1
  • 12
  • 21
4

This is a simple way to find the current day in the year, and it should account for leap years without a problem:

Javascript:

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

Javascript in Google Apps Script:

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

The primary action of this code is to find the number of milliseconds that have elapsed in the current year and then convert this number into days. The number of milliseconds that have elapsed in the current year can be found by subtracting the number of milliseconds of the first second of the first day of the current year, which is obtained with new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0) (Javascript) or new Date(new Date().getYear(), 0, 1, 0, 0, 0) (Google Apps Script), from the milliseconds of the 23rd hour of the current day, which was found with new Date().setHours(23). The purpose of setting the current date to the 23rd hour is to ensure that the day of year is rounded correctly by Math.round().

Once you have the number of milliseconds of the current year, then you can convert this time into days by dividing by 1000 to convert milliseconds to seconds, then dividing by 60 to convert seconds to minutes, then dividing by 60 to convert minutes to hours, and finally dividing by 24 to convert hours to days.

Note: This post was edited to account for differences between JavaScript and JavaScript implemented in Google Apps Script. Also, more context was added for the answer.

Liz Page-Gould
  • 186
  • 1
  • 5
  • Can you please explain a little bit more than just saying it's working? – Stephen Reindl Mar 07 '15 at 19:51
  • Yes! I am sorry for not providing more detail in the first place. The expression inside the "Math.round" statement finds the number of milliseconds in the current year by subtracting the first day of the year from the milliseconds of the last hour of the current day of the year. The number of milliseconds is then divided by 1000 to convert to seconds, 60 to convert to minutes, 60 to convert to hours, and 24 to convert to days. The expression is wrapped within a "Math.round()" function so that it rounds to an integer for the day of year. – Liz Page-Gould Mar 07 '15 at 20:13
  • I should also add that this solution is essentially the same as the "accepted" solution, except it does everything in one line of code. – Liz Page-Gould Mar 07 '15 at 20:45
  • How does this account for daylight savings time? Wouldn't that throw it off a bit? – Dan Oswalt Mar 07 '15 at 22:34
  • No, daylight savings time would not affect this calculation, because daylight savings time has the resolution of hours and this code is calculating the number of days in the year. Moreover, because I used the `.setHours` method on the first date object and specified the time of day with the second date object, a change of 1 hour from daylight savings time will not affect the times of the Date objects used in this calculation. – Liz Page-Gould Mar 08 '15 at 14:45
4

I think this is more straightforward:

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!
Sean
  • 105
  • 6
4

Well, if I understand you correctly, you want 366 on a leap year, 365 otherwise, right? A year is a leap year if it's evenly divisible by 4 but not by 100 unless it's also divisible by 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;
    }
}

Edit after update:

In that case, I don't think there's a built-in method; you'll need to do this:

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();
}

(Yes, I actually did that without copying or pasting. If there's an easy way I'll be mad)

Community
  • 1
  • 1
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • My easy way is just using magic number [1054267675](http://stackoverflow.com/a/27790471/588079) and call it a day, I'm way to lazy to type all that `:)` – GitaarLAB Jan 06 '15 at 02:25
3

This method takes into account timezone issue and daylight saving time

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; 
}

(took from here)

See also this fiddle

Andriy F.
  • 2,467
  • 1
  • 25
  • 23
  • This is a bit inefficient, but it works perfectly. You could just get time the objects and setDate change the date to day 1. Both of which are perfectly supported. The idea is you wont be moving around timezones. This also assumes that daylight savings time is less than 12 hours... which is a safe assumption on earth. – Ray Foss Mar 10 '16 at 15:55
2

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

further optimizes the answer.

Moreover, by changing setHours(23) or the last-but-two zero later on to another value may provide day-of-year related to another timezone. For example, to retrieve from Europe a resource located in America.

1

I would like to provide a solution that does calculations adding the days for each previous month:

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));

This way you don't have to manage the details of leap years and daylight saving.

manix
  • 11
  • 2
1

This might be useful to those who need the day of the year as a string and have jQuery UI available.

You can use jQuery UI Datepicker:

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

Underneath it works the same way as some of the answers already mentioned ((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())
Adrian G.
  • 301
  • 3
  • 5
1

maybe help anybody

let day = (date => {
   return Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24)
})(new Date())
0

I've made one that's readable and will do the trick very quickly, as well as handle JS Date objects with disparate time zones.

I've included quite a few test cases for time zones, DST, leap seconds and Leap years.

P.S. ECMA-262 ignores leap seconds, unlike UTC. If you were to convert this to a language that uses real UTC, you could just add 1 to 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"
);
Ray Foss
  • 3,649
  • 3
  • 30
  • 31
0

A alternative using UTC timestamps. Also as others noted the day indicating 1st a month is 1 rather than 0. The month starts at 0 however.

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

You can pass parameter as date number in setDate function:

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)
Ilyas karim
  • 4,592
  • 4
  • 33
  • 47
0

For those among us who want a fast alternative solution.

(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");
})();

The size of the months of the year and the way that Leap Years work fits perfectly into keeping our time on track with the sun. Heck, it works so perfectly that all we ever do is just adjust mere seconds here and there. Our current system of leap years has been in effect since February 24th, 1582, and will likely stay in effect for the foreseeable future.

DST, however, is very subject to change. It may be that 20 years from now, some country may offset time by a whole day or some other extreme for DST. A whole DST day will almost certainly never happen, but DST is still nevertheless very up-in-the-air and indecisive. Thus, the above solution is future proof in addition to being very very fast.

The above code snippet runs very fast. My computer can process 65536 dates in ~52ms on Chrome.

Jack G
  • 4,553
  • 2
  • 41
  • 50
0

This is a solution that avoids the troublesome Date object and timezone issues, it requires that your input date be in the format "yyyy-dd-mm". If you want to change the format, then modify date_str_to_parts function:

    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)
    }
}
0

A straightforward solution with complete explanation.

var dayOfYear = function(date) {
  const daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  const [yyyy, mm, dd] = date.split('-').map(Number);

  // Checks if February has 29 days
  const isLeap = (year) => new Date(year, 1, 29).getDate() === 29;

  // If it's a leap year, changes 28 to 29
  if (isLeap(yyyy)) daysInMonth[1] = 29;

  let daysBeforeMonth = 0;
  // Slice the array and exclude the current Month
  for (const i of daysInMonth.slice(0, mm - 1)) {
    daysBeforeMonth += i;
  }

  return daysBeforeMonth + dd;
};

console.log(dayOfYear('2020-1-3'));
console.log(dayOfYear('2020-2-1'));
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
0

I wrote these two javascript functions which return the day of the year (Jan 1 = 1). Both of them account for leap years.

function dayOfTheYear() {
// for today
var M=[31,28,31,30,31,30,31,31,30,31,30,31]; var x=new Date(); var m=x.getMonth();
var y=x.getFullYear(); if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) {++M[1];}
var Y=0; for (var i=0;i<m;++i) {Y+=M[i];}
return Y+x.getDate();
}

function dayOfTheYear2(m,d,y) {
// for any day : m is 1 to 12, d is 1 to 31, y is a 4-digit year
var m,d,y; var M=[31,28,31,30,31,30,31,31,30,31,30,31];
if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) {++M[1];}
var Y=0; for (var i=0;i<m-1;++i) {Y+=M[i];}
return Y+d;
}
0

One Line:

Array.from(new Array(new Date().getMonth()), (x, i) => i).reduce((c, p, idx, array)=>{
            let returnValue =  c + new Date(new Date().getFullYear(), p, 0).getDate();
            if(idx == array.length -1){
                returnValue = returnValue + new Date().getDate();
            }
            return returnValue;
        }, 0)
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 08 '21 at 16:53
0

I needed a reliable (leap year and time zone resistant) algorithm for an application that makes heavy use of this feature, I found some algorithm written in the 90s and found that there is still no such efficient and stable solution here:

function dayOfYear1 (date) {
    const year = date.getFullYear();
    const month = date.getMonth()+1;
    const day = date.getDate();

    const N1 = Math.floor(275 * month / 9);
    const N2 = Math.floor((month + 9) / 12);
    const N3 = (1 + Math.floor((year - 4 * Math.floor(year / 4) + 2) / 3));
    const N = N1 - (N2 * N3) + day - 30;
    return N;
}

Algorithm works correctly in leap years, it does not depend on time zones with Date() and on top of that it is more efficient than any of the lower ones:

function dayOfYear2 (date) {
    const monthsDays = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
    const year = date.getFullYear();
    const month = date.getMonth();
    const day = date.getDate();
    let N = monthsDays[month] + day;
    if ( month>1 && year%4==0 ) 
        N++;
    return N;
}


function dayOfYear3 (date) {
    const yearDate = new Date(date.getFullYear(), 0, 0);
    const timeZoneDiff = yearDate.getTimezoneOffset() - date.getTimezoneOffset();
    const N = Math.floor(((date - yearDate )/1000/60 + timeZoneDiff)/60/24);
    return N;
}

All of them are correct and work under the conditions mentioned above. Performance comparison in 100k loop:

dayOfYear1 - 15 ms

dayOfYear2 - 17 ms

dayOfYear3 - 80 ms

Pasztecik
  • 1
  • 2
0

An oneliner answer would be as below:

const today = new Date();
const dayOfYear = Math.floor((today - new Date(today.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24);
console.log(dayOfYear);
Dibyendu Mitra Roy
  • 1,604
  • 22
  • 20
-2

It always get's me worried when mixing maths with date functions (it's so easy to miss some leap year other detail). Say you have:

var d = new Date();

I would suggest using the following, days will be saved in day:

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

Can't see any reason why this wouldn't work just fine (and I wouldn't be so worried about the few iterations since this will not be used so intensively).

  • This is a super slow way of doing things. Not to mention you're taking advantage of the variable hoisting that allows you to use `day` outside of the loop scope, which is considered bad. – Cristian Jan 20 '22 at 13:38