Как использовать javascript для расчета дня года, от 1 до 366? Например:
- Январь 3 должен быть 3.
- 1 февраля должен быть 32.
Как использовать javascript для расчета дня года, от 1 до 366? Например:
После редактирования 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);
Это работает во время перехода на летнее время во всех странах ( "полдень" выше не работает в Австралии):
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;
};
Я нахожу очень интересным, что никто не рассматривал возможность использования 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
Date.prototype.dayOfYear= function(){
var j1= new Date(this);
j1.setMonth(0, 0);
return Math.round((this-j1)/8.64e7);
}
alert(new Date().dayOfYear())
К счастью, этот вопрос не указывает, требуется ли номер текущего дня, оставляя место для этого ответа.
Также некоторые ответы (также по другим вопросам) имели проблемы в високовом возрасте или использовали объект 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>
Хорошо, если я правильно вас понимаю, вы хотите 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();
}
(Да, я действительно сделал это без копирования или вставки. Если будет легкий путь, я буду сумасшедшим)
Это простой способ найти текущий день в году, и он должен учитывать високосные годы без проблем:
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. Кроме того, для ответа было добавлено больше контекста.
Если вы не хотите изобретать колесо, вы можете использовать отличный date-fns (node.js ):
var getDayOfYear = require('date-fns/get_day_of_year')
var dayOfYear = getDayOfYear(new Date(2017, 1, 1)) // 1st february => 32
Этот метод учитывает проблему с часовым поясом и летнее время.
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
Math.round((новая дата(). setHours (23) - новая дата (новая дата(). getFullYear(), 0, 1, 0, 0, 0))/1000/86400);
дополнительно оптимизирует ответ.
Кроме того, путем изменения setHours (23) или последнего, но два нуля позже на другое значение может обеспечить день-год, связанный с другим часовым поясом. Например, чтобы получить из Европы ресурс, расположенный в Америке.
Я думаю, что это более просто:
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!
Math.floor((Date.now() - Date.parse(new Date().getFullYear(), 0, 0)) / 86400000)
это мое решение
Я сделал тот, который читается, и очень быстро выполнит трюк, а также обработает объекты 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"
);
Я хотел бы предложить решение, которое делает расчеты, добавляя дни за каждый предыдущий месяц:
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));
Альтернатива с использованием меток времени 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);
Вы можете передать параметр как число даты в функции 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)
Это может быть полезно для тех, кому нужен день года в виде строки и доступный пользовательский интерфейс 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())
Для тех из нас, кто хочет быстрое альтернативное решение.
(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");
})();
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);
Меня всегда волнует, когда вы смешиваете математику с функциями даты (так легко пропустить некоторые високосный год, другие детали). Скажите, что у вас есть:
var d = new Date();
Я бы предложил использовать следующие, дни будут сохранены в day
:
for(var day = d.getDate(); d.getMonth(); day += d.getDate())
d.setDate(0);
Невозможно увидеть причину, по которой это не сработало бы очень хорошо (и меня бы так не беспокоило несколько итераций, так как это не будет использоваться так интенсивно).
/* ИСПОЛЬЗУЙТЕ ЭТО 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");