Javascript tính toán ngày trong năm (1 - 366)


118

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 .

4
var days = new Date().getFullYear() % 4 == 0 ? 366 : 365;
Alex Turpin

Nhưng thực sự tôi không chắc bạn muốn nói gì. Bạn chỉ muốn số ngày trong năm? Hoặc giữa hai ngày?
Alex Turpin

16
fyi @ xeon06, tính toán năm nhuận phức tạp hơn một chút so với cách tính bằng 4. Xem: thuật toán năm nhuận
Matt Felzani

4
@ Xeon06: Điều đó chỉ đúng trong hầu hết thời gian. Theo Wikipedia : Những năm chia hết cho 100 không phải là năm nhuận, trừ khi chúng cũng chia hết cho 400, trong trường hợp đó chúng năm nhuận.
Cameron

À, tôi đứng sửa lại. @minitech dường như có câu trả lời đúng khi đó.
Alex Turpin

Câu trả lời:


137

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


5
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.
baacke

3
Thành phần ban ngày là base-1. tức là đại diện cho ngày 1 tháng 1 năm nay, bạn sẽ sử dụng 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.
Kirk Woll

1
Có thể sử dụng .setUTCHoursDate.UTC()cho một giải pháp đáng tin cậy hơn.
Noyo

6
@AlexTurpin, @ T30: Tôi biết điều này hơi cũ, nhưng nếu bạn đang thắc mắc ... thì vấn đề là do Giờ tiết kiệm ánh sáng ban ngày bắt đầu vào tháng Ba. Điều này là do khi bạn lấy chênh lệch giữa nửa đêm của ngày trước DST và nửa đêm của ngày sau DST, bạn sẽ không có số mili giây chia đều cho 1000 * 60 * 60 * 24 (nó sẽ tắt đúng một giờ) . Giải pháp đơn giản nhất là sử dụng 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.
Warren R.

2
Để tính toán các múi giờ và tiết kiệm ánh sáng ban ngày, hãy thay đổi dòng 3 thành: var diff = now - start + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
Marlon

46

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

1
Đồng ý rằng có những lỗi liên quan đến tiết kiệm ánh sáng ban ngày trong câu trả lời được chấp nhận. Giải pháp trên là tốt hơn và nhanh hơn. Đây là một biến thể của nó mà tôi đã thử nghiệm trên jsPerf jsperf.com/date-getdayofyear-perf
Shyam Habarakada

@ShyamHabarakada: mã trong điểm chuẩn của bạn bị hỏng, 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.
CodeManX

32

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

Điều này có thể tràn vì số phần nghìn giây quá lớn.
knt5784

@ knt5784 Phép toán có thể bị tràn, nhưng ví dụ của anh ấy cho thấy giá trị thực lớn nhất có thể hoạt động tốt, vì vậy bạn có thể yên tâm sử dụng điều này trừ khi có vấn đề dựa trên trình duyệt với tràn số nguyên.
Per Fagrell

Cá nhân tôi thích cách tiếp cận này. Cách sạch hơn nhiều (và rất thông minh!) Để tránh các vấn đề DST. Nếu ai đang thắc mắc cách chuyển đổi từ DOY trở lại đây thì đơn giản hơn nhiều. Về cơ bản, bạn chỉ cần tạo một ngày tháng Giêng. Ví dụ: ngày 59 tháng 1 === 28 tháng 2. Ngày nhuận được xử lý tốt. function doyToDate(doy, year) { return new Date(year, 0, doy); }
Kip

@ knt5784 Không có nguy cơ bị tràn phần nghìn giây với mã này, ít nhất là không trong 200.000 năm nữa. Ngày lớn nhất được Date hỗ trợ là 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
Kip

18
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
Điều này sẽ không vượt qua lint ... Sửa đổi một đối tượng không phải của bạn, đặc biệt là đối tượng toàn cầu. Điều này cũng sẽ không thành công ở các hành tinh có độ nghiêng cực cao, nơi thời gian tiết kiệm ánh sáng ban ngày hơn 12 giờ. Nhưng thực tế hơn, nếu bạn đang viết mã cho một trình duyệt cho phép thay đổi múi giờ của đối tượng Date, múi giờ của j1 có thể là Úc và múi giờ này có thể là Alaska, phá vỡ quy luật làm tròn.
Ray Foss

11

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ángngà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ố 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=33chỉ 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ì? .


1
Tôi đã ném nó vào một hàm ngày tháng để dễ sử dụng. Sự không nhất quán của Granted the Date () vẫn là một vấn đề, nhưng tôi đang sử dụng các năm 2015+ nên tôi hy vọng chúng nhất quán. JSHint tội nghiệp đã chết khi cố gắng xác thực mã của bạn hahah. 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; };
Freshvolk

Rất vui vì bạn thích nó. Thuật ngữ này được kiểm tra đầy đủ trong 2 ^ 31-1 năm (con số khổng lồ là 2147483647, tức là> 7500 lần phạm vi ngày-đối tượng của javascript) ở cả hai phía của 0. (Nó có thể hoạt động trong 2 ^ 32, nhưng tôi chưa kiểm tra điều đó chưa). Ngoài ra, bạn có thể đọc lại câu trả lời của tôi: bạn có thể cạo +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(); };
GitaarLAB

Tôi thực sự chỉ làm điều đó khi tôi đang nhìn vào nó! Tôi nhận ra mình đã cộng một rồi trừ đi ngay lập tức. Tôi nghĩ rằng vào thời điểm chúng ta đến 2^31 - 2016vài năm nữa, js có lẽ sẽ hơi lỗi thời.
Freshvolk

@Freshvolk: lol, đó là lý do tại sao tôi chưa bao giờ thử nghiệm nó vượt quá 2 ^ 31 :)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.
GitaarLAB

5

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

4

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

Chỉnh sửa sau khi cập nhật:

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)


Cách dễ dàng của tôi chỉ đang sử dụng ma thuật số 1054267675 và gọi nó là một ngày, tôi cách để lười biếng để gõ tất cả những gì:)
GitaarLAB

4

Đâ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.


Bạn có thể vui lòng giải thích một chút hơn là chỉ nói rằng nó đang hoạt động?
Stephen Reindl

Đúng! Tôi xin lỗi vì đã không cung cấp thêm chi tiết ngay từ đầu. Biểu thức bên trong câu lệnh "Math.round" tìm số mili giây trong năm hiện tại bằng cách lấy mili giây của ngày cuối cùng của ngày hiện tại trong năm trừ đi ngày đầu tiên của năm. Sau đó, số mili giây được chia cho 1000 để chuyển đổi thành giây, 60 để chuyển đổi thành phút, 60 để chuyển đổi thành giờ và 24 để chuyển đổi thành ngày. Biểu thức được bao bọc trong một hàm "Math.round ()" để nó làm tròn thành một số nguyên cho ngày trong năm.
Liz Page-Gould

Tôi cũng nên nói thêm rằng giải pháp này về cơ bản giống như giải pháp "được chấp nhận", ngoại trừ nó thực hiện mọi thứ trong một dòng mã.
Liz Page-Gould

Làm thế nào để tài khoản này tiết kiệm thời gian ban ngày? Điều đó sẽ không ném nó đi một chút?
Dan Oswalt

Không, thời gian tiết kiệm ánh sáng ban ngày sẽ không ảnh hưởng đến tính toán này, bởi vì thời gian tiết kiệm ánh sáng ban ngày có độ phân giải của giờ và mã này đang tính toán số ngày trong năm. Hơn nữa, vì tôi đã sử dụng .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.
Liz Page-Gould

4

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!

3

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


Điều này hơi kém hiệu quả, nhưng nó hoạt động hoàn hảo. Bạn chỉ có thể lấy thời gian của các đối tượng và setDate thay đổi ngày thành ngày 1. Cả hai đều được hỗ trợ hoàn hảo. Ý tưởng là bạn sẽ không di chuyển quanh các múi giờ. Điều này cũng giả định rằng thời gian tiết kiệm ánh sáng ban ngày là dưới 12 giờ ... đó là một giả định an toàn trên trái đất.
Ray Foss

2

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ỹ.


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

đây là giải pháp của tôi


Tôi sử dụng ngày 31 tháng 12 của năm trước để đặt 01 tháng 1 = DOY 01. Ngoài ra, tôi thấy ngày 10 tháng 3 có DOY giống như ngày 11 tháng 3 vì một cái là 69 và cái kia 69,9 gì đó, cả hai đều tăng sàn thành 69. Thay vào đó, thực hiện Math.round đã sửa lỗi này . Tôi tin rằng ngày 10 tháng 3 hoặc ngày 11 tháng 3 là công tắc thời gian tiết kiệm ánh sáng ban ngày khiến ngày 11 tháng 3 không hoàn toàn là 70
DOY

0

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


0

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.


0

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

0

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)

0

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

0

Đố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.


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


0

Đâ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)
    }
}

-1

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


-1

/ * 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");
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.