Javascript 计算一年中的哪一天 (1 - 366)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8619879/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 06:45:58  来源:igfitidea点击:

Javascript calculate the day of the year (1 - 366)

javascript

提问by Alex Turpin

How do I use javascript to calculate the day of the year, from 1 - 366? For example:

如何使用 javascript 从 1 - 366 计算一年中的哪一天?例如:

  • January 3should be 3.
  • February 1should be 32.
  • 1月3日应该是3
  • 2 月 1 日应该是32

回答by Alex Turpin

Following OP's edit:

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

Edit: The code above will failwhen nowis 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 compensatefor this:

编辑:上面的代码会失败时,now是3月26日和10月29日之间的日期now的时间是凌晨1点之前(如零时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);

回答by Joe Orost

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

回答by user2501097

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

我觉得很有趣,没有人考虑使用 UTC,因为它不受 DST 的约束。因此,我提出以下建议:

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

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

回答by kennebec

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

alert(new Date().dayOfYear())

回答by GitaarLAB

Luckily this question doesn't specify if the number of the currentday 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 objectcovers approximately 285616 years (100,000,000 days) on either side of January 1 1970, I was fed up with all kinds of unexpected date inconsistenciesacross different browsers (most notably year 0 to 99). I was also curious how to calculate it.

幸运的是,如果数量这个问题没有指定当前需要一天,留有余地这个答案。
还有一些答案(也在其他问题上)有闰年问题或使用了日期对象。尽管 javascriptDate object涵盖了 1970 年 1 月 1 日左右的大约 285616 年(100,000,000 天),但我厌倦了不同浏览器(最显着的是 0 到 99 年)的各种意外日期不一致。我也很好奇如何计算。

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

所以我写了一个简单且最重要的算法来计算正确的Proleptic Gregorian/ Astronomical / ISO 8601:2004 (clause 4.3.2.1),所以年份0存在并且是闰年并且支持负年)一年中的某一天基于
请注意,在AD/BC符号中,0 AD/BC 年不存在:相反,年份1 BC是闰年!如果您需要考虑 BC 表示法,那么只需先减去(否则为正)年份值的一年!!

I modified (for javascript) the short-circuit bitmask-modulo leapYear algorithmand 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 >>>)).

我修改了(对于javascript)短路位掩码模leapYear算法并提出了一个幻数来按位查找偏移量(不包括jan和feb,因此需要10 * 3位(30位小于31 位,因此我们可以安全地在位移位上保存另一个字符而不是>>>))。

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

请注意,月或日都不是0。这意味着,如果你需要这个公式只为当前日期(用喂养它.getMonth()),你只需要删除----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 correctrange-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).

同样,一行,但我将其分成 3 行以提高可读性(以及以下解释)。

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.

最后一行与上面的函数相同,但是(相同的)leapYear 算法移到了前面的短路部分(在天数计算之前),因为它还需要知道一个月有多少天给定(闰)年。

The middle line calculates the correct offsetnumber (for max number of days) for a given month in a given (leap)year using another magic number: since 31-28=3and 3is just 2 bits, then 12*2=24bits, 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.

中间行使用另一个幻数计算给定(闰)年中给定月份的正确偏移量(最大天数):因为31-28=33只是 2 位,那么12*2=24位,我们可以存储所有 12 个月。由于加法比减法更快,我们添加偏移量(而不是从 中减去31)。为了避免 2 月份出现闰年决策分支,我们动态修改了这个神奇的查找数。

That leaves us with the (pretty obvious) first line: it checks that month and date are within valid bounds and ensures us with a falsereturn 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<12to 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.

这给我们留下了(非常明显的)第一行:它检查月份和日期是否在有效范围内,并确保我们false在范围错误时返回值(注意这个函数也不应该能够返回 0,因为 1 jan 0000仍然是第 1 天。),提供简单的错误检查:if(r=dayNo(/*y, m, d*/)){}
如果以这种方式使用(其中月份和日期可能不是0),则可以更改--m>=0 && m<12m>0 && --m<12(保存另一个字符)。
我以当前形式输入代码段的原因是,对于基于 0 的月份值,只需--要从--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?.

额外:
请注意,如果您只需要每月最大天数,请不要使用这一天的每月算法。在这种情况下,有一个更有效的算法(因为我们只需要 leepYear 当月份是二月时)我发布作为回答这个问题:使用 javascript 确定一个月中天数的最佳方法是什么?.

回答by Amaury Liet

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

如果你不想重新发明轮子,你可以使用优秀的date-fns(node.js) 库:

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

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

回答by Liz Page-Gould

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

这是一种查找一年中当前日期的简单方法,它应该可以毫无问题地考虑闰年:

Javascript:

Javascript:

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

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:

Google Apps 脚本中的 Javascript:

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

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().

此代码的主要操作是查找当前年份经过的毫秒数,然后将此数字转换为天数。可以通过从毫秒中减去当前年份的第一天的第一秒的毫秒数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()

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.

一旦你有了当前年份的毫秒数,那么你可以通过除以 1000 将毫秒转换为秒,然后除以 60 将秒转换为分钟,然后除以 60 将分钟转换为小时,将这个时间转换为天,最后除以 24 将小时转换为天。

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.

注意:本文经过编辑以说明 JavaScript 和在 Google Apps Script 中实现的 JavaScript 之间的差异。此外,为答案添加了更多上下文。

回答by Ry-

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:

好吧,如果我理解正确的话,你希望闰年是 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;
    }
}


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)

(是的,我实际上没有复制或粘贴就这样做了。如果有一个简单的方法,我会生气的)

回答by Sean

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!

回答by Andriy F.

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

另见这个小提琴