Làm cách nào để sử dụng javascript để tính ngày trong năm, từ 1 - 366? Ví dụ:
- Ngày 3 tháng 1 nên là 3 .
- Ngày 1 tháng 2 phải là 32 .
Làm cách nào để sử dụng javascript để tính ngày trong năm, từ 1 - 366? Ví dụ:
Câu trả lời:
Sau chỉnh sửa của 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);
Chỉnh sửa: Đoạn mã trên sẽ không thành công khi nowmột ngày trong khoảng từ ngày 26 tháng 3 đến ngày 29 tháng 10 và nowthời gian trước 1 giờ sáng (ví dụ: 00:59:59). Điều này là do mã không tính đến thời gian tiết kiệm ánh sáng ban ngày. Bạn nên bù đắp cho điều này:
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);
Math.floorliên tục cho tôi kết quả ít hơn 1 ngày so với dự kiến sau một ngày nhất định trong tháng 4. Math.ceilđã hoạt động như mong đợi, nhưng tôi đã thấy rằng bạn nên sử dụng Math.roundthay vì một trong hai.
new Date(2014, 0, 1), chứ không phải new Date(2014, 0, 0)như bạn có ở đây. Đó là cố ý? Có lẽ đó là những gì giải thích cho việc một ngày nào đó new Date(2014, 0, 0)sẽ mất đi 12/31/2013.
.setUTCHoursvà Date.UTC()cho một giải pháp đáng tin cậy hơn.
ceilthay vì sử dụng floor, điều này sẽ cung cấp cho bạn một hệ thống đánh số trong đó ngày 1 tháng 1 = 1. Nếu bạn muốn ngày 1 tháng 1 = 0 (như floorbạn muốn), chỉ cần trừ 1 từ kết quả cuối cùng của bạn.
var diff = now - start + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
Tính năng này hoạt động trên các thay đổi của Giờ tiết kiệm ánh sáng ban ngày ở tất cả các quốc gia ("buổi trưa" ở trên không hoạt động ở Úc):
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;
};
getDay()cần được thay đổi thành getDate(). Cái trước trả về ngày trong tuần (0 = Chủ nhật..6 = Thứ Bảy), không phải ngày.
Tôi thấy rất thú vị là không ai cân nhắc sử dụng UTC vì nó không phải tuân theo DST. Do đó, tôi đề xuất như sau:
function daysIntoYear(date){
return (Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - Date.UTC(date.getFullYear(), 0, 0)) / 24 / 60 / 60 / 1000;
}
Bạn có thể kiểm tra nó bằng cách sau:
[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`));
Kết quả đầu ra cho năm nhuận 2016 (được xác minh bằng cách sử dụng 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
function doyToDate(doy, year) { return new Date(year, 0, doy); }
new Date(8640000000000000), vẫn nhỏ hơn Number.MAX_SAFE_INTEGER. xem câu trả lời này: stackoverflow.com/a/11526569/18511
Date.prototype.dayOfYear= function(){
var j1= new Date(this);
j1.setMonth(0, 0);
return Math.round((this-j1)/8.64e7);
}
alert(new Date().dayOfYear())
May mắn thay, câu hỏi này không xác định xem số của ngày hiện tại có được yêu cầu hay không, hãy để trống cho câu trả lời này.
Ngoài ra, một số câu trả lời (cũng cho các câu hỏi khác) có vấn đề về năm nhuận hoặc sử dụng đối tượng Ngày. Mặc dù javascript Date objectbao gồm khoảng 285616 năm (100.000.000 ngày) ở cả hai phía của ngày 1 tháng 1 năm 1970, tôi đã chán ngấy với tất cả các loại mâu thuẫn ngày không mong muốn trên các trình duyệt khác nhau (đáng chú ý nhất là năm 0 đến năm 99). Tôi cũng tò mò làm thế nào để tính toán nó.
Vì vậy, tôi đã viết một thuật toán đơn giản và trên hết, nhỏ để tính toán chính xác ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (điều khoản 4.3.2.1), do đó năm0 tồn tại và là năm nhuận và năm âm được hỗ trợ ) ngày trong năm dựa trên năm , tháng và ngày .
Lưu ý rằng trong AD/BCký hiệu, năm 0 AD / BC không tồn tại: thay vào đó năm 1 BClà năm nhuận! NẾU bạn cần tính toán ký hiệu BC thì chỉ cần trừ đi một năm của giá trị năm (nếu không dương) trước !!
Tôi đã sửa đổi (đối với javascript) thuật toán bitmask-modulo leapYear ngắn mạch và nghĩ ra một con số kỳ diệu để thực hiện tra cứu hiệu số một cách khôn ngoan (không bao gồm jan và feb, do đó cần 10 * 3 bit (30 bit nhỏ hơn 31 bit, vì vậy chúng tôi có thể an toàn lưu một ký tự khác trên bithift thay vì >>>)).
Lưu ý rằng không thể tháng hoặc ngày 0. Điều đó có nghĩa là nếu bạn cần phương trình này chỉ cho ngày hiện tại (cho nó ăn bằng cách sử dụng .getMonth()), bạn chỉ cần xóa --từ --m.
Lưu ý rằng điều này giả định một ngày hợp lệ (mặc dù kiểm tra lỗi chỉ là một số ký tự nhiều hơn).
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>
Đây là phiên bản có xác nhận phạm vi chính xác.
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>
Một lần nữa, một dòng, nhưng tôi chia nó thành 3 dòng để dễ đọc (và giải thích sau).
Dòng cuối cùng giống với hàm ở trên, tuy nhiên thuật toán leapYear (giống hệt) được chuyển sang phần ngắn mạch trước đó (trước phép tính số ngày), bởi vì nó cũng cần biết bao nhiêu ngày trong tháng trong một cho (nhuận) năm.
Dòng giữa tính toán số bù chính xác (cho số ngày tối đa) cho một tháng nhất định trong một năm nhất định (bước nhảy vọt) bằng cách sử dụng một số ma thuật khác: vì 31-28=3và 3chỉ là 2 bit, sau đó là 12*2=24bit, chúng ta có thể lưu trữ tất cả 12 tháng. Vì phép cộng có thể nhanh hơn phép trừ, chúng ta cộng phần bù (thay vì trừ 31). Để tránh phân nhánh quyết định năm nhuận cho tháng Hai, chúng tôi sửa đổi số tra cứu kỳ diệu đó ngay lập tức.
Điều đó để lại cho chúng ta dòng đầu tiên (khá rõ ràng): nó kiểm tra tháng và ngày đó có nằm trong giới hạn hợp lệ không và đảm bảo cho chúng ta falsegiá trị trả về trên lỗi phạm vi (lưu ý rằng hàm này cũng không thể trả về 0, vì 1 jan 0000 vẫn là ngày 1.), cung cấp dễ dàng kiểm tra lỗi: if(r=dayNo(/*y, m, d*/)){}.
Nếu được sử dụng theo cách này (trong đó tháng và ngày có thể không có 0), thì người ta có thể thay đổi --m>=0 && m<12thành m>0 && --m<12(lưu ký tự khác).
Lý do tôi nhập đoạn mã ở dạng hiện tại là đối với các giá trị tháng dựa trên 0, người ta chỉ cần xóa --từ --m.
Thêm:
Lưu ý, không sử dụng thuật toán ngày này mỗi tháng nếu bạn chỉ cần số ngày tối đa mỗi tháng. Trong trường hợp đó, có một thuật toán hiệu quả hơn (vì chúng ta chỉ cần leepYear khi tháng là tháng 2) Tôi đã đăng để trả lời câu hỏi này: Cách tốt nhất để xác định số ngày trong tháng bằng javascript là gì? .
Date.prototype.dayNo = function(){ var y = this.getFullYear(); var m = this.getMonth()+1; var d = this.getDate(); return --m*31-(m>1?(1054267675>>m*3-6&7)-(y&3||!(y%25)&&y&15?0:1):0)+d; };
+1từ this.getMonth()+1nếu bạn xóa --từ --m. CHỈNH SỬA Vì vậy, tôi sẽ làm (cho một thư viện):Date.prototype.dayNo = function(){ var y=this.getFullYear(), m=this.getMonth(); return m*31-(m>1?(1054267675>>m*3-6&7)-(y&3||!(y%25)&&y&15?0:1):0)+this.getDate(); };
2^31 - 2016vài năm nữa, js có lẽ sẽ hơi lỗi thời.
:)Nhưng cho đến lúc đó, ít nhất nó sẽ cho kết quả có thể đoán trước và nhất quán haha. CHỈNH SỬA , chỉ vì lý thuyết, bằng cách sử dụng thuật ngữ tất cả mô-đun thông thường chậm hơn cho năm nhuận, phạm vi có thể được mở rộng đến 2 ^ 53. Thuật toán tra cứu tháng không phải là yếu tố giới hạn.
Nếu bạn không muốn phát minh lại bánh xe, bạn có thể sử dụng thư viện date-fns (node.js) tuyệt vời :
var getDayOfYear = require('date-fns/get_day_of_year')
var dayOfYear = getDayOfYear(new Date(2017, 1, 1)) // 1st february => 32
Vâng, nếu tôi hiểu bạn một cách chính xác, bạn muốn 366 vào một năm nhuận, 365 ngược lại, phải không? Một năm là năm nhuận nếu nó chia hết cho 4 nhưng không chia hết cho 100 trừ khi nó cũng chia hết cho 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;
}
}
Trong trường hợp đó, tôi không nghĩ rằng có một phương pháp tích hợp sẵn; bạn sẽ cần làm điều này:
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();
}
(Vâng, tôi thực sự đã làm điều đó mà không cần sao chép hoặc dán. Nếu có một cách dễ dàng, tôi sẽ tức điên lên)
:)
Đây là một cách đơn giản để tìm ngày hiện tại trong năm và nó sẽ tính cho các năm nhuận mà không gặp vấn đề gì:
Javascript:
Math.round((new Date().setHours(23) - new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0))/1000/60/60/24);
Javascript trong Google Apps Script:
Math.round((new Date().setHours(23) - new Date(new Date().getYear(), 0, 1, 0, 0, 0))/1000/60/60/24);
Hành động chính của mã này là tìm số mili giây đã trôi qua trong năm hiện tại và sau đó chuyển đổi số này thành ngày. Có thể tìm số mili giây đã trôi qua trong năm hiện tại bằng cách trừ số mili giây của giây đầu tiên của ngày đầu tiên của năm hiện tại, lấy được bằng new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0)(Javascript) hoặc new Date(new Date().getYear(), 0, 1, 0, 0, 0)(Google Apps Script) từ mili giây của giờ thứ 23 của ngày hiện tại, được tìm thấy với new Date().setHours(23). Mục đích của việc đặt ngày hiện tại thành giờ thứ 23 là để đảm bảo rằng ngày trong năm được làm tròn một cách chính xác Math.round().
Khi bạn có số mili giây của năm hiện tại, thì bạn có thể chuyển thời gian này thành ngày bằng cách chia cho 1000 để chuyển mili giây thành giây, sau đó chia cho 60 để chuyển giây thành phút, sau đó chia cho 60 để chuyển phút thành giờ, và cuối cùng chia cho 24 để chuyển đổi giờ thành ngày.
Lưu ý: Bài đăng này đã được chỉnh sửa để giải thích sự khác biệt giữa JavaScript và JavaScript được triển khai trong Google Apps Script. Ngoài ra, nhiều ngữ cảnh hơn đã được thêm vào cho câu trả lời.
.setHoursphương pháp trên đối tượng ngày đầu tiên và chỉ định thời gian trong ngày với đối tượng ngày thứ hai, việc thay đổi 1 giờ so với giờ tiết kiệm ánh sáng ban ngày sẽ không ảnh hưởng đến thời gian của đối tượng Ngày được sử dụng trong phép tính này.
Tôi nghĩ điều này đơn giản hơn:
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!
Phương pháp này tính đến vấn đề múi giờ và thời gian tiết kiệm ánh sáng ban ngày
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;
}
(lấy từ đây )
Xem thêm trò chơi này
Math.round ((new Date (). SetHours (23) - new Date (new Date (). GetFullYear (), 0, 1, 0, 0, 0)) / 1000/86400);
tối ưu hóa hơn nữa câu trả lời.
Hơn nữa, bằng cách thay đổi setHours (23) hoặc số không cuối cùng nhưng hai số 0 sau đó thành một giá trị khác có thể cung cấp ngày trong năm liên quan đến múi giờ khác. Ví dụ, để lấy từ Châu Âu một tài nguyên nằm ở Châu Mỹ.
Math.floor((Date.now() - Date.parse(new Date().getFullYear(), 0, 0)) / 86400000)
đây là giải pháp của tôi
Tôi đã tạo một cái có thể đọc được và sẽ thực hiện thủ thuật rất nhanh chóng, cũng như xử lý các đối tượng JS Date có múi giờ khác nhau.
Tôi đã bao gồm khá nhiều trường hợp thử nghiệm cho múi giờ, DST, giây nhuận và năm nhuận.
PS ECMA-262 bỏ qua giây nhuận, không giống như UTC. Nếu bạn định chuyển đổi ngôn ngữ này sang ngôn ngữ sử dụng UTC thực, bạn chỉ cần thêm 1 vào 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"
);
Tôi muốn cung cấp một giải pháp thực hiện các phép tính cộng các ngày cho mỗi tháng trước:
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));
Bằng cách này, bạn không phải quản lý các chi tiết của năm nhuận và tiết kiệm ánh sáng ban ngày.
Một giải pháp thay thế bằng cách sử dụng dấu thời gian UTC. Cũng như những người khác đã lưu ý rằng ngày cho biết ngày 1 một tháng là 1 thay vì 0. Tuy nhiên, tháng bắt đầu bằng 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);
Bạn có thể chuyển tham số là số ngày trong setDatehàm:
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)
Điều này có thể hữu ích cho những người cần ngày trong năm dưới dạng chuỗi và có sẵn giao diện người dùng jQuery.
Bạn có thể sử dụng jQuery UI Datepicker:
day_of_year_string = $.datepicker.formatDate("o", new Date())
Bên dưới nó hoạt động theo cách tương tự như một số câu trả lời đã được đề cập ( (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())
Đối với những người trong chúng ta, những người muốn có một giải pháp thay thế nhanh chóng.
(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");
})();
Kích thước của các tháng trong năm và cách hoạt động của Leap Years hoàn toàn phù hợp để giữ cho thời gian của chúng ta luôn đúng với mặt trời. Heck, nó hoạt động hoàn hảo đến nỗi tất cả những gì chúng ta từng làm chỉ là điều chỉnh vài giây ở đây và ở đó . Hệ thống năm nhuận hiện tại của chúng tôi đã có hiệu lực kể từ ngày 24 tháng 2 năm 1582 và có thể sẽ vẫn có hiệu lực trong tương lai gần.
DST, tuy nhiên, rất có thể thay đổi. Có thể là 20 năm kể từ bây giờ, một số quốc gia có thể bù đắp thời gian bằng cả ngày hoặc một số cực đoan khác đối với DST. Cả một ngày DST gần như chắc chắn sẽ không bao giờ xảy ra, nhưng DST vẫn rất nóng vội và thiếu quyết đoán. Vì vậy, giải pháp trên là bằng chứng trong tương lai ngoài việc rất nhanh.
Đoạn mã trên chạy rất nhanh. Máy tính của tôi có thể xử lý 65536 ngày trong ~ 52 mili giây trên Chrome.
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);
Đây là một giải pháp tránh các vấn đề rắc rối về đối tượng Ngày và múi giờ, yêu cầu ngày nhập của bạn phải ở định dạng "yyyy-dd-mm". Nếu bạn muốn thay đổi định dạng, hãy sửa đổi hàm 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)
}
}
Tôi luôn lo lắng khi trộn các phép toán với các hàm ngày tháng (rất dễ bỏ sót một số chi tiết khác của năm nhuận). Giả sử bạn có:
var d = new Date();
Tôi sẽ đề xuất sử dụng như sau, ngày sẽ được lưu trong day:
for(var day = d.getDate(); d.getMonth(); day += d.getDate())
d.setDate(0);
Không thể thấy bất kỳ lý do nào tại sao điều này sẽ không hoạt động tốt (và tôi sẽ không quá lo lắng về một vài lần lặp lại vì điều này sẽ không được sử dụng nhiều).
/ * SỬ DỤNG SCRIPT NÀY * /
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");
var days = new Date().getFullYear() % 4 == 0 ? 366 : 365;