Javascript menghitung hari dalam setahun (1 - 366)

119

Bagaimana cara menggunakan javascript untuk menghitung hari dalam setahun, dari 1 - 366? Sebagai contoh:

  • 3 Jan harus 3 .
  • 1 Februari seharusnya 32 tahun .
Kirk Woll
sumber
4
var days = new Date().getFullYear() % 4 == 0 ? 366 : 365;
Alex Turpin
Tapi sungguh saya tidak yakin apa yang Anda maksud. Anda hanya ingin jumlah hari dalam setahun? Atau di antara dua kencan?
Alex Turpin
16
fyi @ xeon06, perhitungan tahun kabisat sedikit lebih rumit daripada memodifikasi 4. lihat: algoritma tahun kabisat
Matt Felzani
4
@ Xeon06: Itu benar hanya untuk sebagian besar waktu. Dari Wikipedia : Tahun-tahun yang habis dibagi 100 bukanlah tahun kabisat, kecuali mereka juga habis dibagi 400, dalam hal ini tahun kabisat.
Cameron
Ah baiklah saya berdiri dikoreksi. @minitech sepertinya punya jawaban yang benar kalau begitu.
Alex Turpin

Jawaban:

138

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

Sunting: Kode di atas akan gagal jika nowtanggal antara 26 Maret dan 29 Oktober dan nowwaktu sebelum 1AM (mis. 00:59:59). Hal ini karena kode tidak memperhitungkan waktu musim panas. Anda harus mengkompensasi ini:

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

Alex Turpin
sumber
5
Math.floorsecara konsisten memberi saya hasil 1 hari lebih sedikit dari yang diharapkan setelah hari tertentu di bulan April. Math.ceilbekerja seperti yang diharapkan, tetapi saya telah melihat disarankan agar Anda menggunakan Math.rounddaripada keduanya.
baacke
3
Komponen hari adalah basis-1. yaitu untuk mewakili 1 Januari tahun ini, Anda akan menggunakan new Date(2014, 0, 1), dan bukan new Date(2014, 0, 0)seperti yang Anda miliki di sini. Apakah itu disengaja? Mungkin itulah yang menyebabkan libur satu hari dan new Date(2014, 0, 0)akan kembali 12/31/2013.
Kirk Woll
1
Mungkin gunakan .setUTCHoursdan Date.UTC()untuk solusi yang lebih andal.
Noyo
6
@AlexTurpin, @ T30: Saya tahu ini agak lama, tetapi jika Anda bertanya-tanya ... masalahnya disebabkan karena Waktu Musim Panas mulai bulan Maret. Ini karena ketika Anda mengambil selisih tengah malam dari tanggal sebelum DST dan tengah malam dari tanggal setelah DST, Anda tidak akan memiliki sejumlah milidetik yang habis dibagi 1000 * 60 * 60 * 24 (itu akan menjadi tepat satu jam off) . Solusi termudah adalah dengan menggunakan ceildaripada floor, ini akan memberi Anda sistem penomoran di mana 1 Jan = 1. Jika Anda ingin 1 Jan = 0 (seperti yang floorakan Anda berikan), kurangi 1 dari hasil akhir Anda.
Warren R.
2
Untuk memperhitungkan zona waktu dan pergeseran waktu siang hari, ubah baris 3 ke: var diff = now - start + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
Marlon
46

Ini berfungsi di seluruh perubahan Waktu Musim Panas di semua negara ("siang" di atas tidak berfungsi di 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;
};
Joe Orost
sumber
1
Setuju bahwa ada bug terkait penghematan siang hari dalam jawaban yang diterima. Solusi di atas lebih baik dan lebih cepat. Berikut ini variasinya yang saya uji di jsPerf jsperf.com/date-getdayofyear-perf
Shyam Habarakada
@ShyamHabarakada: kode di tolok ukur Anda rusak, getDay()perlu diubah menjadi getDate(). Yang pertama mengembalikan hari dalam seminggu (0 = Sunday..6 = Sabtu), bukan hari.
CodeManX
32

Saya merasa sangat menarik bahwa tidak ada yang mempertimbangkan untuk menggunakan UTC karena tidak tunduk pada DST. Oleh karena itu, saya mengusulkan yang berikut:

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

Anda dapat mengujinya dengan yang berikut:

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

Keluaran mana untuk tahun kabisat 2016 (diverifikasi menggunakan 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
pengguna2501097
sumber
Ini mungkin meluap karena jumlah milidetiknya terlalu besar.
knt5784
@ knt5784 Matematikanya mungkin dapat meluap, tetapi contohnya menunjukkan kemungkinan nilai dunia nyata terbesar yang berfungsi dengan baik sehingga Anda tidak masalah menggunakan ini kecuali jika ada masalah berbasis browser dengan bilangan bulat overflow.
Per Fagrell
Saya pribadi menyukai pendekatan ini. Cara yang jauh lebih bersih (dan sangat pintar!) Untuk menghindari masalah DST. Jika ada yang bertanya-tanya bagaimana cara mengonversi dari DOY ke masa lalu, itu jauh lebih sederhana. Pada dasarnya Anda baru saja membuat tanggal DOYth Januari. Misalnya, 59 Januari === 28 Feb. Hari kabisat ditangani dengan baik. function doyToDate(doy, year) { return new Date(year, 0, doy); }
Kip
@ knt5784 Tidak ada risiko luapan milidetik dengan kode ini, setidaknya tidak selama 200.000 tahun lagi. Tanggal terbesar yang didukung oleh Tanggal adalah new Date(8640000000000000), yang masih kurang dari Number.MAX_SAFE_INTEGER. lihat jawaban ini: 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())
kennebec
sumber
3
Ini tidak akan melewatkan lint ... Memodifikasi objek yang bukan milik Anda, khususnya yang global. Ini juga akan gagal di planet dengan kemiringan ekstrem di mana waktu musim panas lebih dari 12 jam. Tetapi yang lebih realistis, jika Anda membuat kode untuk browser yang memungkinkan pengubahan zona waktu objek Tanggal, zona waktu j1 bisa jadi Australia dan zona waktu ini bisa jadi Alaska, melanggar pembulatan.
Ray Foss
11

Untungnya pertanyaan ini tidak menentukan jika jumlah yang saat ini hari diperlukan, meninggalkan ruang untuk jawaban ini.
Juga beberapa jawaban (juga pada pertanyaan lain) memiliki masalah tahun kabisat atau menggunakan objek Tanggal. Meskipun javascript Date objectmencakup kira-kira 285616 tahun (100.000.000 hari) di kedua sisi tanggal 1 Januari 1970, saya muak dengan semua jenis inkonsistensi tanggal yang tidak terduga di berbagai browser (terutama tahun 0 hingga 99). Saya juga penasaran bagaimana cara menghitungnya.

Jadi saya menulis yang sederhana dan di atas segalanya, algoritma kecil untuk menghitung hari yang benar ( Proleptic Gregorian / Astronomical / ISO 8601: 2004 (klausul 4.3.2.1), jadi tahun0 ada dan merupakan tahun kabisat dan tahun negatif didukung ) hari dalam setahun berdasarkan tahun , bulan dan hari .
Perhatikan bahwa dalam AD/BCnotasi, tahun 0 M / SM tidak ada: sebagai gantinya tahun 1 BCadalah tahun kabisat! JIKA Anda perlu menghitung notasi BC maka kurangi satu tahun dari nilai tahun (jika tidak positif) dulu !!

Saya memodifikasi (untuk javascript) algoritma bitmask-modulo leapYear sirkuit pendek dan menghasilkan angka ajaib untuk melakukan pencarian offset bit-bijaksana (yang tidak termasuk jan dan feb, sehingga membutuhkan 10 * 3 bit (30 bit kurang dari 31 bit, jadi kita dapat dengan aman menyimpan karakter lain di bitshift alih-alih >>>)).

Perhatikan bahwa tidak ada bulan atau hari yang mungkin 0. Itu berarti bahwa jika Anda perlu persamaan ini hanya untuk saat hari (makan menggunakan .getMonth()) Anda hanya perlu untuk menghapus --dari --m.

Perhatikan bahwa ini mengasumsikan tanggal yang valid (meskipun pengecekan kesalahan hanya beberapa karakter lagi).

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>


Ini adalah versi dengan validasi rentang yang benar .

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>

Sekali lagi, satu baris, tetapi saya membaginya menjadi 3 baris agar mudah dibaca (dan penjelasan berikut).

Baris terakhir identik dengan fungsi di atas, namun algoritma leapYear (identik) dipindahkan ke bagian hubung singkat sebelumnya (sebelum penghitungan angka hari), karena diperlukan juga untuk mengetahui berapa hari dalam sebulan dalam diberikan tahun (kabisat).

Garis tengah menghitung jumlah offset yang benar (untuk jumlah hari maksimum) untuk bulan tertentu dalam tahun (kabisat) tertentu menggunakan angka ajaib lain: karena 31-28=3dan 3hanya 2 bit, maka 12*2=24bit, kita dapat menyimpan semua 12 bulan. Karena penjumlahan bisa lebih cepat daripada pengurangan, kami menambahkan offset (bukan menguranginya 31). Untuk menghindari cabang keputusan tahun kabisat untuk bulan Februari, kami memodifikasi nomor pencarian ajaib itu dengan cepat.

Itu membuat kita dengan baris pertama (cukup jelas): ia memeriksa bahwa bulan dan tanggal berada dalam batas yang valid dan memastikan kita dengan falsenilai yang dikembalikan pada kesalahan rentang (perhatikan bahwa fungsi ini juga tidak dapat mengembalikan 0, karena 1 jan 0000 masih hari 1.), menyediakan mudah pengecekan error: if(r=dayNo(/*y, m, d*/)){}.
Jika digunakan dengan cara ini (di mana bulan dan hari mungkin tidak 0), maka seseorang dapat mengubahnya --m>=0 && m<12menjadi m>0 && --m<12(menyimpan karakter lain).
Alasan saya mengetik potongan dalam bentuknya saat ini adalah karena untuk nilai bulan berbasis 0, seseorang hanya perlu menghapus --dari --m.

Ekstra:
Catatan, jangan gunakan algoritme hari per bulan ini jika Anda hanya membutuhkan maksimal hari per bulan. Dalam hal ini ada algoritma yang lebih efisien (karena kita hanya perlu leepTahun ketika bulan Februari) saya posting sebagai jawaban pertanyaan ini: Apa cara terbaik untuk menentukan jumlah hari dalam sebulan dengan javascript? .

GitaarLAB
sumber
1
Saya memasukkannya ke dalam fungsi tanggal untuk kemudahan penggunaan. Memang tanggal () inkonsistensi masih menjadi masalah, tapi saya menggunakan tahun 2015+ jadi saya harap mereka konsisten. JSHint yang malang mati saat mencoba memvalidasi kode Anda 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
Senang kamu menyukainya. Algo ini sepenuhnya diuji selama 2 ^ 31-1 tahun (kekalahan 2147483647, itu> 7500 kali rentang objek tanggal javascript) di kedua sisi 0. (Ini mungkin berfungsi untuk 2 ^ 32, tetapi saya belum mengujinya namun). Juga, Anda mungkin membaca jawaban saya lagi: Anda bisa mencukur habis +1dari this.getMonth()+1jika Anda menghapus --dari --m. EDIT Jadi, saya akan melakukan (untuk perpustakaan):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
Saya sebenarnya baru saja melakukan itu ketika saya melihatnya! Saya menyadari bahwa saya menambahkan satu lalu menguranginya segera. Saya pikir pada saat kita mencapai 2^31 - 2016tahun - tahun dari sekarang js mungkin akan sedikit ketinggalan jaman.
freshvolk
@Freshvolk: lol, itulah mengapa saya tidak pernah mengujinya melebihi 2 ^ 31 :)Tapi sampai saat itu, setidaknya akan memberikan hasil yang dapat diprediksi dan konsisten haha. EDIT , hanya demi teori, menggunakan algo all-modulo konvensional yang lebih lambat untuk leapyear, kisaran dapat diperpanjang hingga 2 ^ 53. Algo pencarian bulan bukanlah faktor pembatas.
GitaarLAB
5

Jika Anda tidak ingin menemukan kembali roda, Anda dapat menggunakan pustaka tanggal-fns (node.js) yang sangat baik:

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

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

Nah, jika saya mengerti Anda dengan benar, Anda menginginkan 366 pada tahun kabisat, 365 sebaliknya, bukan? Setahun adalah tahun kabisat jika habis dibagi 4 tetapi tidak habis dibagi 100 kecuali habis dibagi 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 setelah pembaruan:

Dalam hal ini, menurut saya tidak ada metode bawaan; Anda harus melakukan ini:

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

(Ya, saya benar-benar melakukannya tanpa menyalin atau menempel. Jika ada cara mudah saya akan marah)

Ry-
sumber
Cara mudah saya hanya menggunakan nomor ajaib 1054267675 dan menyebutnya sehari, cara saya malas mengetik semua itu:)
GitaarLAB
4

Ini adalah cara sederhana untuk menemukan hari saat ini dalam satu tahun, dan harus memperhitungkan tahun kabisat tanpa masalah:

Javascript:

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

Javascript di Google Apps Script:

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

Tindakan utama dari kode ini adalah menemukan jumlah milidetik yang telah berlalu dalam tahun ini dan kemudian mengonversinya menjadi hari. Jumlah milidetik yang telah berlalu di tahun ini dapat ditemukan dengan mengurangkan jumlah milidetik dari detik pertama hari pertama tahun berjalan, yang diperoleh dengan new Date(new Date().getYear()+1900, 0, 1, 0, 0, 0)(Javascript) atau new Date(new Date().getYear(), 0, 1, 0, 0, 0)(Google Apps Script), dari milidetik dari jam ke-23 hari ini, yang ditemukan dengan new Date().setHours(23). Tujuan menyetel tanggal saat ini ke jam ke-23 adalah untuk memastikan bahwa hari dalam setahun dibulatkan dengan benar Math.round().

Setelah Anda mengetahui jumlah milidetik tahun ini, Anda dapat mengonversi waktu ini menjadi hari dengan membaginya dengan 1000 untuk mengubah milidetik menjadi detik, kemudian membaginya dengan 60 untuk mengubah detik menjadi menit, kemudian membaginya dengan 60 untuk mengubah menit menjadi jam, dan akhirnya membaginya dengan 24 untuk mengubah jam menjadi hari.

Catatan: Posting ini telah diedit untuk menjelaskan perbedaan antara JavaScript dan JavaScript yang diterapkan di Google Apps Script. Juga, lebih banyak konteks ditambahkan untuk jawabannya.

Liz Page-Gould
sumber
Bisakah Anda menjelaskan sedikit lebih dari sekadar mengatakan itu berfungsi?
Stephen Reindl
Iya! Saya minta maaf karena tidak memberikan detail lebih lanjut. Ekspresi di dalam pernyataan "Math.round" menemukan jumlah milidetik dalam tahun ini dengan mengurangkan hari pertama tahun itu dari milidetik jam terakhir hari ini dalam setahun. Jumlah milidetik kemudian dibagi dengan 1000 untuk diubah menjadi detik, 60 untuk diubah menjadi menit, 60 untuk diubah menjadi jam, dan 24 untuk diubah menjadi hari. Ekspresi tersebut dibungkus dalam fungsi "Math.round ()" sehingga dibulatkan menjadi integer untuk hari dalam setahun.
Liz Page-Gould
Saya juga harus menambahkan bahwa solusi ini pada dasarnya sama dengan solusi "diterima", kecuali solusi ini melakukan semuanya dalam satu baris kode.
Liz Page-Gould
Bagaimana cara menghitung waktu musim panas? Bukankah itu membuangnya sedikit?
Dan Oswalt
Tidak, waktu musim panas tidak akan mempengaruhi perhitungan ini, karena waktu musim panas memiliki resolusi jam dan kode ini menghitung jumlah hari dalam setahun. Selain itu, karena saya menggunakan .setHoursmetode pada objek tanggal pertama dan menentukan waktu hari dengan objek tanggal kedua, perubahan 1 jam dari waktu musim panas tidak akan memengaruhi waktu objek Tanggal yang digunakan dalam perhitungan ini.
Liz Page-Gould
4

Saya pikir ini lebih mudah:

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!
Sean
sumber
3

Metode ini memperhitungkan masalah zona waktu dan waktu musim panas

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

(diambil dari sini )

Lihat juga biola ini

Andriy F.
sumber
Ini sedikit tidak efisien, tetapi berfungsi dengan sempurna. Anda bisa saja mendapatkan waktu objek dan setDate mengubah tanggal ke hari 1. Keduanya didukung dengan sempurna. Idenya adalah Anda tidak akan berpindah-pindah zona waktu. Ini juga mengasumsikan bahwa waktu musim panas kurang dari 12 jam ... yang merupakan asumsi yang aman di bumi.
Ray Foss
2

Math.round ((Tanggal baru (). SetHours (23) - Tanggal baru (Tanggal baru (). GetFullYear (), 0, 1, 0, 0, 0)) / 1000/86400);

lebih mengoptimalkan jawabannya.

Selain itu, dengan mengubah setHours (23) atau nol terakhir-tapi-dua kemudian ke nilai lain dapat memberikan hari-tahun-tahun yang terkait dengan zona waktu lain. Misalnya, untuk mengambil sumber daya dari Eropa yang terletak di Amerika.

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

inilah solusi saya

Mainkan
sumber
Saya menggunakan 31 Des tahun sebelumnya untuk membuat Jan 01 = DOY 01. Juga saya temukan 10 Maret memiliki DOY yang sama dengan 11 Maret karena yang satu 69,9 dan yang lainnya 69,9, keduanya berlevel 69. Melakukan Math.round malah memperbaiki ini . Saya yakin 10 Maret atau 11 Maret adalah pengalih waktu musim panas yang menyebabkan 11 Maret tidak cukup DOY 70.
user3015682
0

Saya telah membuat satu yang mudah dibaca dan akan melakukan trik dengan sangat cepat, serta menangani objek JS Date dengan zona waktu yang berbeda.

Saya telah menyertakan beberapa kasus uji untuk zona waktu, DST, detik kabisat, dan tahun kabisat.

PS ECMA-262 mengabaikan detik kabisat, tidak seperti UTC. Jika Anda mengonversinya ke bahasa yang menggunakan UTC nyata, Anda cukup menambahkan 1 ke 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"
);

Ray Foss
sumber
0

Saya ingin memberikan solusi yang menghitung dengan menambahkan hari untuk setiap bulan sebelumnya:

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

Dengan cara ini Anda tidak perlu mengelola detail tahun kabisat dan penghematan siang hari.

manix
sumber
0

Alternatif menggunakan stempel waktu UTC. Juga seperti yang dicatat orang lain, hari yang menunjukkan tanggal 1 sebulan adalah 1 daripada 0. Namun bulan itu dimulai dari 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);
emctwoo
sumber
0

Anda dapat melewatkan parameter sebagai nomor tanggal dalam setDatefungsi:

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)
Ilyas karim
sumber
0

Ini mungkin berguna bagi mereka yang membutuhkan hari dalam setahun sebagai string dan memiliki jQuery UI yang tersedia.

Anda dapat menggunakan jQuery UI Datepicker:

day_of_year_string = $.datepicker.formatDate("o", new Date())

Di bawahnya berfungsi dengan cara yang sama seperti beberapa jawaban yang telah disebutkan ( (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())
Adrian G.
sumber
0

Bagi kita yang menginginkan solusi alternatif yang cepat.

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

Ukuran bulan dalam setahun dan cara Tahun Kabisat bekerja sangat cocok untuk menjaga waktu kita tetap sejalan dengan matahari. Heck, ini bekerja dengan sangat sempurna sehingga yang pernah kita lakukan hanyalah menyesuaikan beberapa detik di sana-sini . Sistem tahun kabisat kita saat ini telah berlaku sejak 24 Februari 1582 , dan kemungkinan besar akan tetap berlaku di masa mendatang.

DST, bagaimanapun, sangat bisa berubah. Mungkin 20 tahun dari sekarang, beberapa negara mungkin mengimbangi waktu satu hari penuh atau beberapa ekstrim lainnya untuk DST. Seluruh hari DST hampir pasti tidak akan pernah terjadi, tetapi DST masih sangat terbuka dan ragu-ragu. Dengan demikian, solusi di atas adalah bukti masa depan selain sangat sangat cepat.

Potongan kode di atas berjalan sangat cepat. Komputer saya dapat memproses 65536 tanggal dalam ~ 52ms di Chrome.

Jack Giffin
sumber
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);

pengguna7331530
sumber
0

Ini adalah solusi yang menghindari masalah objek Tanggal dan zona waktu yang merepotkan, yang mengharuskan tanggal masukan Anda dalam format "yyyy-dd-mm". Jika Anda ingin mengubah format, ubah fungsi 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)
    }
}
Yogistra Anderson
sumber
-1

Itu selalu membuat saya khawatir saat mencampur matematika dengan fungsi tanggal (sangat mudah melewatkan beberapa detail tahun kabisat lainnya). Katakanlah Anda memiliki:

var d = new Date();

Saya akan menyarankan menggunakan yang berikut ini, hari-hari akan disimpan dalam day:

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

Tidak dapat melihat alasan mengapa ini tidak akan berfungsi dengan baik (dan saya tidak akan terlalu khawatir tentang beberapa iterasi karena ini tidak akan digunakan secara intensif).

Martin Ekblom
sumber
-1

/ * GUNAKAN SKRIP INI * /

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");
Pankaj Yadav
sumber