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

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

  • Январь 3 должен быть 3.
  • 1 февраля должен быть 32.

Ответ 1

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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

alert(new Date().dayOfYear())

Ответ 5

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

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

Я изменил (для javascript) алгоритм короткого замыкания с битовой маской - modulo 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>

Ответ 6

Хорошо, если я правильно вас понимаю, вы хотите 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();
}

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

Ответ 7

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

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. Кроме того, для ответа было добавлено больше контекста.

Ответ 8

Если вы не хотите изобретать колесо, вы можете использовать отличный date-fns (node.js ):

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

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

Ответ 9

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

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

(взято из здесь)

См. также fiddle

Ответ 10

Math.round((новая дата(). setHours (23) - новая дата (новая дата(). getFullYear(), 0, 1, 0, 0, 0))/1000/86400);

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

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

Ответ 11

Я думаю, что это более просто:

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 a leap year, changes 28 to 29
    monthLength[1] = 29;
}

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

Ответ 12

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

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

Ответ 13

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

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

P.S. 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 Date object
  var start_ts = date.getTime();    // New Year 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"
);

Ответ 14

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

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

Ответ 15

Альтернатива с использованием меток времени 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);

Ответ 16

Вы можете передать параметр как число даты в функции 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)

Ответ 17

Это может быть полезно для тех, кому нужен день года в виде строки и доступный пользовательский интерфейс 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())

Ответ 18

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

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

Ответ 19

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

Ответ 20

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

var d = new Date();

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

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

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

Ответ 21

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

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