Javascript вычисляет день года (1 - 366)

119

Как использовать javascript для вычисления дня в году от 1 до 366? Например:

  • 3 января должно быть 3 .
  • 1 февраля должно быть 32 .
Кирк Уолл
источник
4
var days = new Date().getFullYear() % 4 == 0 ? 366 : 365;
Alex Turpin
Но на самом деле я не совсем понимаю, о чем вы. Вам просто нужно количество дней в году? Или между двумя свиданиями?
Alex Turpin
16
fyi @ xeon06, расчет високосного года немного сложнее, чем модификация на 4. см .: алгоритм високосного года
Мэтт Фелзани
4
@ Xeon06: Это верно только в большинстве случаев. Из Википедии : Годы, которые без остатка делятся на 100, не являются високосными, если только они не делятся без остатка на 400, и в этом случае они являются високосными годами.
Кэмерон
Ну что ж, я исправлюсь. Значит, у @minitech есть правильный ответ.
Alex Turpin

Ответы:

138

После редактирования 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);

Изменить: приведенный выше код завершится ошибкой, если nowдата находится между 26 марта и 29 октября и nowвремя до 1 часа ночи (например, 00:59:59). Это связано с тем, что код не учитывает летнее время. Вы должны это компенсировать :

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.floorстабильно давал мне результат на 1 день меньше, чем ожидалось после определенного дня в апреле. Math.ceilработал, как ожидалось, но я видел, что вам рекомендуется использовать Math.roundвместо них.
baacke
3
Суточная составляющая равна основанию 1. т.е. для обозначения 1 января этого года вы должны использовать new Date(2014, 0, 1), а не new Date(2014, 0, 0)как здесь. Это намеренно? Возможно, это то, что составляет один день, когда new Date(2014, 0, 0)вернется 12/31/2013.
Кирк Уолл,
1
Может использовать .setUTCHoursи Date.UTC()для более надежного решения.
Нойо
6
@AlexTurpin, @ T30: Я знаю, что это немного устарело, но если вам интересно ... проблема вызвана переходом на летнее время, начиная с марта. Это связано с тем, что, когда вы берете разницу между полуночью даты перед летним временем и полуночью даты после летнего времени, у вас не будет числа миллисекунд, делимых на 1000 * 60 * 60 * 24 (это будет ровно один час). , Самое простое решение - использовать ceilвместо floor, это даст вам систему нумерации, в которой 1 января = 1. Если вы хотите, чтобы 1 января = 0 ( floorчто и даст вам), просто вычтите 1 из окончательного результата.
Уоррен Р.
2
Чтобы учесть часовые пояса и переход на летнее время, измените строку 3 на: var diff = now - start + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
Марлон,
46

Это работает при переходе на летнее время во всех странах (указанное выше «полдень» не работает в Австралии):

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
Согласитесь, что в принятом ответе есть ошибки, связанные с переходом на летнее время. Вышеупомянутое решение лучше и быстрее. Вот его вариант, который я тестировал на jsPerf jsperf.com/date-getdayofyear-perf
Шьям Хабаракада
@ShyamHabarakada: код в вашем тесте не работает, его getDay()нужно изменить на getDate(). Первый возвращает день недели (0 = воскресенье..6 = суббота), а не день.
CodeManX
32

Мне очень интересно, что никто не рассматривал возможность использования UTC, поскольку он не подлежит переходу на летнее время. Поэтому предлагаю следующее:

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

Вы можете проверить это следующим образом:

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

Какие результаты для високосного 2016 года (проверено с помощью 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
источник
Это может привести к переполнению, потому что количество миллисекунд слишком велико.
knt5784
@ knt5784 Математика может быть переполнена, но его пример показывает, что наибольшее возможное реальное значение работает нормально, так что с этим все будет в порядке, если только не возникнет проблема браузера с целочисленным переполнением.
Per Fagrell
Мне лично нравится такой подход. Гораздо более чистый (и очень умный!) Способ избежать проблем с переходом на летнее время. Если кому-то интересно, как конвертировать из DOY в прошлое, это намного проще. По сути, вы просто создаете дату января DOYth. Например, 59 января === 28 февраля. Високосный день обрабатывается нормально. function doyToDate(doy, year) { return new Date(year, 0, doy); }
Кип
@ knt5784 С этим кодом нет риска миллисекундного переполнения, по крайней мере, в течение следующих 200000 лет. Самая большая дата, поддерживаемая Date, - new Date(8640000000000000)это все еще меньше Number.MAX_SAFE_INTEGER. см. этот ответ: stackoverflow.com/a/11526569/18511
Кип
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())
Kennebec
источник
3
Это не пропустит lint ... Изменение объекта, который вам не принадлежит, особенно глобального. Это также не сработает на планетах с экстремальным наклоном, где летнее время превышает 12 часов. Но более реалистично, если вы пишете код для браузера, который позволяет изменять часовой пояс объекта Date, часовым поясом j1 может быть Австралия, а этим часовым поясом может быть Аляска, нарушая округление.
Рэй Фосс,
11

К счастью, в этом вопросе не указывается, требуется ли номер текущего дня, оставляя место для этого ответа.
Также в некоторых ответах (также на другие вопросы) были проблемы с високосным годом или использовался объект Date. Хотя javascript Date objectохватывает примерно 285616 лет (100000000 дней) по обе стороны от 1 января 1970 года, мне надоели всевозможные неожиданные несоответствия дат в разных браузерах (особенно с 0 по 99 год). Мне также было любопытно, как это рассчитать.

Поэтому я написал простой и, прежде всего, небольшой алгоритм для вычисления правильного ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (пункт 4.3.2.1), поэтому год0 существует и является високосным, и поддерживаются отрицательные годы ) дня года. по году , месяцу и дню .
Обратите внимание, что в AD/BCнотации год 0 AD / BC не существует: вместо этого год 1 BCявляется високосным! ЕСЛИ вам нужно учесть нотацию BC, тогда просто сначала вычтите один год из (в противном случае положительного) годового значения !!

Я изменил (для javascript) алгоритм короткого замыкания битовой маски по модулю leapYear и придумал магическое число для побитового поиска смещений (которое исключает jan и feb, поэтому требуется 10 * 3 бит (30 бит меньше, чем 31 бит, поэтому мы можем спокойно сохранить другой символ при битовом сдвиге вместо >>>)).

Обратите внимание, что ни месяц, ни день не могут быть 0. Это означает, что если вам нужно это уравнение только на текущий день (кормление с помощью .getMonth()), вам просто нужно удалить --из --m.

Обратите внимание, это предполагает действительную дату (хотя для проверки ошибок требуется всего лишь несколько символов).

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>


Вот версия с правильной проверкой диапазона.

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>

Опять же, одна строка, но я разделил ее на 3 строки для удобства чтения (и следующих пояснений).

Последняя строка идентична приведенной выше функции, однако (идентичный) алгоритм leapYear перемещен в предыдущий раздел короткого замыкания (перед вычислением числа дней), потому что также необходимо знать, сколько дней в месяце имеет данный (високосный) год.

Средняя строка вычисляет правильное число смещения (для максимального количества дней) для данного месяца в данном (високосном) году с использованием другого магического числа: поскольку 31-28=3и 3составляет всего 2 бита, то 12*2=24биты, мы можем сохранить все 12 месяцев. Поскольку сложение может быть быстрее, чем вычитание, мы добавляем смещение (вместо того, чтобы вычитать его 31). Чтобы избежать ветки принятия решения о високосном году для февраля, мы изменяем это волшебное число поиска на лету.

Это оставляет нам (довольно очевидную) первую строку: она проверяет, находятся ли месяц и дата в допустимых пределах, и гарантирует нам falseвозвращаемое значение при ошибке диапазона (обратите внимание, что эта функция также не должна возвращать 0, потому что 1 января 0000 еще день 1.), обеспечивая легкие проверки ошибок: if(r=dayNo(/*y, m, d*/)){}.
Если использовать этот способ (где месяц и день могут не быть 0), то можно изменить --m>=0 && m<12на m>0 && --m<12(сохранение другого символа).
Причина, по которой я набрал фрагмент в его текущей форме, заключается в том, что для значений месяца, отсчитываемых от 0, нужно просто удалить --из --m.

Дополнительно:
обратите внимание, не используйте алгоритм этого дня в месяц, если вам нужно только максимальное количество дней в месяц. В этом случае есть более эффективный алгоритм (потому что leepYear нам нужен только тогда, когда месяц - февраль), который я опубликовал в качестве ответа на этот вопрос: Как лучше всего определить количество дней в месяце с помощью javascript? ,

GitaarLAB
источник
1
Я закинул его в функцию даты для удобства использования. Конечно, несоответствия Date () все еще остаются проблемой, но я использую 2015+, поэтому надеюсь, что они согласованы. Бедный JSHint умер, пытаясь проверить ваш код, ха-ха. 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 02 фев.15,
Рада что тебе понравилось. Этот алгоритм полностью протестирован в течение 2 ^ 31-1 лет (колоссальные 2147483647, что> 7500 раз превышает диапазон объекта даты javascript) с обеих сторон от 0. (Он может работать для 2 ^ 32, но я не тестировал это все же). Кроме того , вы можете прочитать мой ответ снова: вы можете сбрить +1от , this.getMonth()+1если вы удалите --из --m. ИЗМЕНИТЬ Итак, я бы сделал (для библиотеки):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
Я действительно так и сделал, когда смотрел на это! Я понял, что добавляю единицу, а затем сразу вычитаю ее. Я думаю, что к тому времени, когда мы дойдем до этого 2^31 - 2016года, js, вероятно, немного устареет.
freshvolk
@Freshvolk: lol, вот почему я никогда не тестировал его выше 2 ^ 31. :)Но до тех пор он будет давать по крайней мере предсказуемые и последовательные результаты, ха-ха. РЕДАКТИРОВАТЬ , просто ради теории, используя более медленный обычный алгоритм с полным модулем для високосного года, диапазон можно расширить до 2 ^ 53. Алгоритм поиска по месяцам не является ограничивающим фактором.
GitaarLAB
5

Если вы не хотите заново изобретать колесо, вы можете использовать отличную библиотеку 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

Ну, если я вас правильно понял, вы хотите 366 в високосный год, 365 в противном случае, не так ли? Год считается високосным, если он делится без остатка на 4, но не на 100, если он также не делится на 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;
    }
}

Редактировать после обновления:

В этом случае я не думаю, что есть встроенный метод; вам нужно будет сделать это:

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

(Да, я действительно сделал это без копирования и вставки. Если есть простой способ, я буду зол)

Ry-
источник
Мой простой способ - просто использовать магический номер 1054267675 и назвать его днем, мне лень набирать все это:)
GitaarLAB
4

Это простой способ найти текущий день в году, и он должен без проблем учитывать високосные годы:

Javascript:

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

Javascript в Google Apps Script:

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

Основное действие этого кода - найти количество миллисекунд, прошедших в текущем году, а затем преобразовать это число в дни. Количество миллисекунд, прошедших в текущем году, можно найти, вычтя количество миллисекунд первой секунды первого дня текущего года, полученное с помощью new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0)(Javascript) или new Date(new Date().getYear(), 0, 1, 0, 0, 0)(Google Apps Script), из миллисекунд. 23 часа текущих суток, который был найден с new Date().setHours(23). Целью установки текущей даты на 23-й час является обеспечение правильного округления дня года на Math.round().

Когда у вас есть количество миллисекунд текущего года, вы можете преобразовать это время в дни, разделив на 1000, чтобы преобразовать миллисекунды в секунды, затем разделив на 60, чтобы преобразовать секунды в минуты, затем разделив на 60, чтобы преобразовать минуты в часы, и, наконец, деление на 24 для преобразования часов в дни.

Примечание. Этот пост был отредактирован, чтобы учесть различия между JavaScript и JavaScript, реализованными в Google Apps Script. Кроме того, для ответа был добавлен дополнительный контекст.

Лиз Пейдж-Гулд
источник
Не могли бы вы объяснить немного больше, чем просто сказать, что это работает?
Стивен Рейндл,
Да! Я прошу прощения за то, что не предоставил более подробную информацию. Выражение внутри оператора «Math.round» находит количество миллисекунд в текущем году, вычитая первый день года из миллисекунд последнего часа текущего дня года. Затем количество миллисекунд делится на 1000 для преобразования в секунды, 60 для преобразования в минуты, 60 для преобразования в часы и 24 для преобразования в дни. Выражение заключено в функцию «Math.round ()», так что оно округляется до целого числа для дня года.
Лиз Пейдж-Гулд
Я должен также добавить, что это решение по сути то же самое, что и «принятое» решение, за исключением того, что оно делает все в одной строке кода.
Лиз Пейдж-Гулд
Как это учитывает переход на летнее время? Разве это не сбило бы его с толку?
Дэн Освальт
Нет, переход на летнее время не повлияет на этот расчет, поскольку летнее время имеет разрешение в часах, а этот код вычисляет количество дней в году. Более того, поскольку я использовал этот .setHoursметод для первого объекта даты и указал время дня для второго объекта даты, изменение летнего времени на 1 час не повлияет на время объектов Date, используемых в этом вычислении.
Лиз Пейдж-Гулд
4

Я думаю, что это проще:

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

Этот метод учитывает проблему с часовым поясом и летнее время.

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

(взял отсюда )

См. Также эту скрипку

Андрей Ф.
источник
Это немного неэффективно, но работает отлично. Вы можете просто получить время для объектов, а setDate изменить дату на день 1. И то, и другое прекрасно поддерживается. Идея в том, что вы не будете перемещаться по часовым поясам. Это также предполагает, что летнее время составляет менее 12 часов ... что является безопасным предположением на Земле.
Рэй Фосс
2

Math.round ((new Date (). SetHours (23) - новая Дата (new Date (). GetFullYear (), 0, 1, 0, 0, 0)) / 1000/86400);

дополнительно оптимизирует ответ.

Более того, изменив setHours (23) или предпоследний ноль позже на другое значение, можно получить день года, связанный с другим часовым поясом. Например, чтобы получить из Европы ресурс, расположенный в Америке.

Массимо Росио
источник
1
Math.floor((Date.now() - Date.parse(new Date().getFullYear(), 0, 0)) / 86400000)

это мое решение

Сыграй
источник
Я использую 31 декабря прошлого года, чтобы сделать 01 января = 01 DOY. Также я обнаружил, что 10 марта имеет тот же DOY, что и 11 марта, потому что один был 69, а другой - 69,9, оба равны 69. Вместо этого с помощью Math.round это исправлено , Я считаю, что 10 или 11 марта - это переход на летнее время, из-за чего 11 марта не совсем соответствует 70 DOY.
user3015682
0

Я сделал один из них, который можно читать и он очень быстро справится с задачей, а также обработает объекты JS Date с разными часовыми поясами.

Я включил довольно много тестовых примеров для часовых поясов, летнего времени, дополнительных секунд и високосных лет.

PS ECMA-262 игнорирует дополнительные секунды, в отличие от UTC. Если бы вы преобразовали это в язык, использующий реальный UTC, вы могли бы просто добавить 1 к 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

Я хотел бы предоставить решение, которое выполняет вычисления, добавляя дни для каждого предыдущего месяца:

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

Таким образом, вам не нужно управлять деталями високосных лет и летнего времени.

Manix
источник
0

Альтернатива с использованием меток времени в формате UTC. Также, как отмечали другие, день, обозначающий 1-й месяц, равен 1, а не 0. Однако месяц начинается с 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);
emctwoo
источник
0

Вы можете передать параметр как номер даты в setDateфункции:

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

Это может быть полезно для тех, кому нужен день года в виде строки и доступен пользовательский интерфейс jQuery.

Вы можете использовать jQuery UI Datepicker:

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

Ниже он работает так же, как некоторые из уже упомянутых ответов ( (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

Для тех из нас, кто хочет быстрое альтернативное решение.

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

Размер месяцев в году и то, как работают високосные годы, идеально подходят для того, чтобы наше время соответствовало солнечным. Черт возьми, это работает так идеально, что все, что мы когда-либо делаем, это просто настраиваем за несколько секунд здесь и там . Наша нынешняя система високосных лет действует с 24 февраля 1582 г. года и, вероятно, останется в силе в обозримом будущем.

Однако летнее время очень подвержено изменениям. Может случиться так, что через 20 лет какая-то страна может компенсировать время на целый день или какое-то другое экстремальное время для перехода на летнее время. Целого дня летнего времени почти наверняка никогда не произойдет, но, тем не менее, летнее время все еще очень актуально и нерешительно. Таким образом, вышеуказанное решение является перспективным в дополнение к тому, что оно очень и очень быстрое.

Приведенный выше фрагмент кода выполняется очень быстро. Мой компьютер может обработать 65536 дат за ~ 52 мс в 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);

user7331530
источник
0

Это решение, которое позволяет избежать неприятных проблем с объектом Date и часовым поясом, оно требует, чтобы дата ввода была в формате «гггг-дд-мм». Если вы хотите изменить формат, измените функцию 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

Меня всегда беспокоит смешивание математики с функциями даты (так легко упустить какой-то високосный год и другие детали). Скажите, что у вас есть:

var d = new Date();

Я бы предложил использовать следующее, дни будут сохранены в day:

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

Не вижу причин, по которым это не будет работать нормально (и я бы не стал так беспокоиться о нескольких итерациях, поскольку это не будет использоваться так интенсивно).

Мартин Экблом
источник
-1

/ * ИСПОЛЬЗУЙТЕ ЭТОТ СКРИПТ * /

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");
Панкадж Ядав
источник