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

如何使用JavaScript来计算一年中的一天,从1 – 366? 例如:

  • 1月3日应该是3
  • 2月1日应该是32

在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; }; 
 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对象。 尽pipejavascript的Date object覆盖了1970年1月1日左右大约285616年(100,000,000天),但是我却厌倦了不同浏览器(最值得注意的是0到99年)的各种意想不到的date不一致 。 我也很好奇如何计算它。

所以我写了一个简单的,最重要的, algorithm来计算正确的 ( 普雷格 公历 /天文学/ ISO 8601:2004(第4.3.2.1条),所以第0存在,是一个闰年和负年 )年份基于
请注意,在AD/BC记法中,0年/公元BC不存在:相反, 1 BC是闰年! 如果你需要考虑公元前记数法,那么简单地减去(否则为正数)一年的第一年!

我修改了(对于JavaScript) 短路位掩码模闰年algorithm,并提出了一个神奇的数字进行位偏移查找偏移量 (不包括jan和feb,因此需要10 * 3位(30位小于31位,所以我们可以安全地将另一个字符保存在位移而不是>>> ))。

请注意,无论月份还是date都不是0 。 这意味着如果你只需要这个方程式(使用.getMonth()给它),你只需要移除-- from --m

注意这假定一个有效的date(虽然错误检查只是更多的字符)。

 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="(-)YMD" 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整除,除非它可以被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(); } 

(是的,我真的没有复制或粘贴,如果有一个简单的方法,我会发疯)

这是一个简单的方法来find今年的当天,它应该占闰年没有问题:

使用Javascript:

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

Google Apps脚本中的Javascript:

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)获得的当前第一天的第一秒的毫秒数减去当前年已过去的毫秒数new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0) 0,1,0,0,0 new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0) (Javascript)或new Date(new Date().getYear(), 0, 1, 0, 0, 0) (Google Apps脚本),从第23小时的毫秒new Date().setHours(23)find当前new Date().setHours(23) 。 将当前date设置为第23小时的目的是为了确保Math.round()正确地舍入一年中的某一天。

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

注意:本文被编辑以解决在Google Apps脚本中实现的JavaScript和JavaScript之间的差异。 此外,更多的上下文被添加为答案。

此方法考虑到时区问题和夏令时

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

(从这里拿)

另见这个小提琴

设置小时(23) – 新date(新date()。getFullYear(),0,1,0,0,0))/ 1000/86400);

进一步优化答案。

而且,通过改变setHours(23)或稍后的两个零值可以提供与另一个时区相关的每日年度。 例如,从欧洲检索位于美国的资源。

我觉得很有趣,没有人考虑使用UTC,因为它不受DST的限制。 所以我build议如下:

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

你可以用下面的方法testing它:

 [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进行validation):;

 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 

我已经做了一个可读的,并会很快做到这一点,以及处理不同时区的JSdate对象。

我已经为时区,夏令时,闰秒和闰年包括了不lesstesting案例。

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

我想提供一个解决scheme,计算每个上个月的日子:

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

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

 var getDayOfYear = require('date-fns/get_day_of_year') var dayOfYear = getDayOfYear(new Date(2017, 1, 1)) // 1st february => 32 

使用UTC时间戳的替代方法。 另外如其他人指出的那样,指示一个月的第一天的date是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); 

/ *使用这个脚本* /

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

把math和date函数混合在一起时,总是让我担心(很容易错过一些闰年的其他细节)。 假设你有:

 var d = new Date(); 

我会build议使用以下,天将被保存在day

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

看不出任何理由为什么这样做不好(我不会那么担心,因为这不会被如此深入地使用)。