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

时间:2011-12-23 19:25:55

标签: javascript

如何使用javascript计算一年中的某一天,从1到366?例如:

  • 1月3日 3
  • 2月1日 32

26 个答案:

答案 0 :(得分:106)

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是3月26日到10月29日之间的日期时will fail上方的代码,而now的时间是凌晨1点(例如00:59:59)。这是因为代码没有考虑夏令时。你应该compensate

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

答案 1 :(得分:46)

这适用于所有国家/地区的夏令时变化("中午和#34;以上一个在澳大利亚不起作用):

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

答案 2 :(得分:17)

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

alert(new Date().dayOfYear())

答案 3 :(得分:9)

幸运的是,这个问题没有说明是否需要当前天的数量,为这个答案留出了空间。
还有一些答案(也在其他问题上)有闰年问题或使用Date-object。虽然javascript的Date object涵盖了1970年1月1日左右的大约285616年(100,000,000天),但我厌倦了不同浏览器中的各种意外日期inconsistencies(最明显的是0到99年)。我也很好奇如何计算它。

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

我修改了(对于javascript)short-circuit bitmask-modulo leapYear algorithm并提出了一个神奇的数字来执行偏移的逐位查找(不包括jan和feb,因此需要10 * 3位(30位小于31位,因此我们可以安全地在bitshift上保存另一个字符,而不是>>>)。

请注意,月份或日期均不得为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和{{ 1}}只是2位,然后是3位,我们可以存储所有12个月。由于加法可以比减法更快,我们添加偏移量(而不是从12*2=24中减去它)。为避免2月份的闰年决策分支,我们会动态修改该魔术查找号码。

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

额外:
注意,如果您只需要每月最多一天,请不要使用这一天的每月算法。在这种情况下,有一个更有效的算法(因为当月份是2月时我们只需要leepYear)我发布了回答这个问题:What is the best way to determine the number of days in a month with javascript?

答案 4 :(得分:4)

这是一种查找当年当天的简单方法,它应该说明闰年没有问题:

<强>使用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)(Javascript)或{{1}获得的(Google Apps脚本),从当天的第23个小时的毫秒开始,与new Date(new Date().getYear(), 0, 1, 0, 0, 0)一起找到。将当前日期设置为第23小时的目的是确保new Date().setHours(23)正确舍入年中的某一天。

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

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

答案 5 :(得分: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();
}

(是的,我实际上是在没有复制或粘贴的情况下做到了。如果有一种简单的方法我会生气)

答案 6 :(得分: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; 
}

(取自here

另见fiddle

答案 7 :(得分:3)

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

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

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

答案 8 :(得分:2)

Math.round((new date()。setHours(23) - new Date(new Date()。getFullYear(),0,1,0,0,0))/ 1000/86400);

进一步优化了答案。

此外,通过将setHours(23)或之后的两个零更改为另一个值,可以提供与另一个时区相关的日期。 例如,从欧洲检索位于美国的资源。

答案 9 :(得分:2)

我认为这更为直白:

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!

答案 10 :(得分:1)

如果使用moment.js,我们可以获取甚至设置一年中的哪一天。

moment().dayOfYear();
//for getting 

moment().dayOfYear(Number); 
//for setting 

moment.js 使用 this code 计算一年中的天

答案 11 :(得分:1)

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

这是我的解决方法

答案 12 :(得分: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);

答案 13 :(得分: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));

这样您就不必管理闰年和夏令时的细节。

答案 14 :(得分: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)

答案 15 :(得分:0)

我已经制作了一个可读且非常快速的技巧,以及处理具有不同时区的JS Date对象。

我在时区,DST,闰秒和闰年中包含了不少测试用例。

P.S。与UTC不同,ECMA-262忽略了闰秒。如果您要将其转换为使用真实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"
);

答案 16 :(得分:0)

这对于那些需要将一年中的日期作为字符串并具有jQuery UI的用户可能有用。

您可以使用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())

答案 17 :(得分:0)

也许可以帮助任何人

let day = (date => {
   return Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24)
})(new Date())

答案 18 :(得分: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");
})();

一年中各个月份的大小以及Le年的工作方式非常适合使我们的时间与太阳同步。哎呀,它是如此完美,以至于我们所做的只是adjust mere seconds here and there。我们当前的of年系统自February 24th, 1582起一直有效,并且在可预见的将来很可能会保持有效。

DST可能会随时更改。可能是从现在开始的20年后,某个国家/地区可能会将DST的时间偏移一整天或其他极端时间。几乎肯定不会发生一整天的DST一天,但是DST仍然是实时的,犹豫不决的。因此,除了非常快之外,上述解决方案还可以用于将来的验证。

上面的代码片段运行非常快。我的计算机在Chrome上可以在大约52毫秒内处理65536个日期。

答案 19 :(得分: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);

答案 20 :(得分:0)

这是一个避免麻烦的Date对象和时区问题的解决方案,它要求您输入的日期格式为“ yyyy-dd-mm”。如果要更改格式,请修改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)
    }
}

答案 21 :(得分:0)

具有完整说明的直接解决方案。

var dayOfYear = function(date) {
  const daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  const [yyyy, mm, dd] = date.split('-').map(Number);

  // Checks if February has 29 days
  const isLeap = (year) => new Date(year, 1, 29).getDate() === 29;

  // If it's a leap year, changes 28 to 29
  if (isLeap(yyyy)) daysInMonth[1] = 29;

  let daysBeforeMonth = 0;
  // Slice the array and exclude the current Month
  for (const i of daysInMonth.slice(0, mm - 1)) {
    daysBeforeMonth += i;
  }

  return daysBeforeMonth + dd;
};

console.log(dayOfYear('2020-1-3'));
console.log(dayOfYear('2020-2-1'));

答案 22 :(得分:0)

我编写了这两个 javascript 函数,它们返回一年中的某一天(1 月 1 日 = 1)。 两者都是闰年。

function dayOfTheYear() {
// for today
var M=[31,28,31,30,31,30,31,31,30,31,30,31]; var x=new Date(); var m=x.getMonth();
var y=x.getFullYear(); if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) {++M[1];}
var Y=0; for (var i=0;i<m;++i) {Y+=M[i];}
return Y+x.getDate();
}

function dayOfTheYear2(m,d,y) {
// for any day : m is 1 to 12, d is 1 to 31, y is a 4-digit year
var m,d,y; var M=[31,28,31,30,31,30,31,31,30,31,30,31];
if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0)) {++M[1];}
var Y=0; for (var i=0;i<m-1;++i) {Y+=M[i];}
return Y+d;
}

答案 23 :(得分:-1)

/ *使用本脚本* /

null

答案 24 :(得分:-1)

将数学与日期函数混合时,我总是很担心(它很容易错过一些闰年的其他细节)。说你有:

var d = new Date();

我建议使用以下内容,日期将保存在day

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

看不出有什么理由不能正常工作(我不会那么担心几次迭代,因为这不会被如此密集地使用)。

答案 25 :(得分:-2)

<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<p id='out'></p>
<script>
let todaysDate = new Date();
let thisYear = todaysDate.getFullYear();
let thisMonth = todaysDate.getMonth();
let thisDay = todaysDate.getDate();

let months = new Array(12);
months[0] = 31;
months[1] = 59;
months[2] = 90;
months[3] = 120;
months[4] = 151;
months[5] = 181;
months[6] = 212;
months[7] = 243;
months[8] = 273;
months[9] = 304;
months[10] = 334;
months[11] = 365;

let month = months[thisMonth-1]
let dayYear = month+thisDay
document.getElementById('out').innerHTML = dayYear;
</script>
</body>
</html>