Bagaimana cara menghasilkan string yang diformat ISO 8601 dalam JavaScript?

247

Saya punya Dateobjek. Bagaimana cara membuat titlebagian dari cuplikan berikut?

<abbr title="2010-04-02T14:12:07">A couple days ago</abbr>

Saya memiliki bagian "waktu relatif dalam kata-kata" dari perpustakaan lain.

Saya sudah mencoba yang berikut ini:

function isoDate(msSinceEpoch) {

   var d = new Date(msSinceEpoch);
   return d.getUTCFullYear() + '-' + (d.getUTCMonth() + 1) + '-' + d.getUTCDate() + 'T' +
          d.getUTCHours() + ':' + d.getUTCMinutes() + ':' + d.getUTCSeconds();

}

Tapi itu memberi saya:

"2010-4-2T3:19"
James A. Rosen
sumber

Jawaban:

453

Sudah ada fungsi yang disebut toISOString():

var date = new Date();
date.toISOString(); //"2011-12-19T15:28:46.493Z"

Jika, entah bagaimana, Anda menggunakan browser yang tidak mendukungnya, saya membantu Anda:

if ( !Date.prototype.toISOString ) {
  ( function() {

    function pad(number) {
      var r = String(number);
      if ( r.length === 1 ) {
        r = '0' + r;
      }
      return r;
    }

    Date.prototype.toISOString = function() {
      return this.getUTCFullYear()
        + '-' + pad( this.getUTCMonth() + 1 )
        + '-' + pad( this.getUTCDate() )
        + 'T' + pad( this.getUTCHours() )
        + ':' + pad( this.getUTCMinutes() )
        + ':' + pad( this.getUTCSeconds() )
        + '.' + String( (this.getUTCMilliseconds()/1000).toFixed(3) ).slice( 2, 5 )
        + 'Z';
    };

  }() );
}
Anatoly Mironov
sumber
1
.toISOString () pasti mengembalikan tanggal dalam UTC?
Jon Wells
new Date("xx").toISOString()menghasilkan NaN-NaN-NaNTNaN:NaN:NaN.NZImplementasi asli melempar RangeException.
Joseph Lennox
Jika Anda ingin memberikan objek kencan ke layanan sabun ... begitulah caranya! :) Terima kasih.
thinklinux
1
Dalam sampel yang disediakan oleh OP, tidak ada milidetik atau zona waktu.
Dan Dascalescu
Semua panggilan fungsi seperti "getUTCFullYear" gagal karena mereka tidak dikenal dengan mode dokumen IE 5.
Elaskanator
63

Lihat contoh terakhir di halaman https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference:Global_Objects:Date :

/* Use a function for the exact format desired... */
function ISODateString(d) {
    function pad(n) {return n<10 ? '0'+n : n}
    return d.getUTCFullYear()+'-'
         + pad(d.getUTCMonth()+1)+'-'
         + pad(d.getUTCDate())+'T'
         + pad(d.getUTCHours())+':'
         + pad(d.getUTCMinutes())+':'
         + pad(d.getUTCSeconds())+'Z'
}

var d = new Date();
console.log(ISODateString(d)); // Prints something like 2009-09-28T19:03:12Z
dev-null-dweller
sumber
1
Sampel yang disediakan oleh OP ( <abbr title="2010-04-02T14:12:07">) tidak memiliki zona waktu. Mungkin mereka menginginkan waktu lokal, yang masuk akal untuk rangkaian waktu UI?
Dan Dascalescu
60

Hampir setiap metode to-ISO di web menjatuhkan informasi zona waktu dengan menerapkan konversi ke waktu ulu "Z" (UTC) sebelum mengeluarkan string. .ToISOString () asli browser juga menjatuhkan informasi zona waktu.

Ini membuang informasi berharga, sebagai server, atau penerima, selalu dapat mengonversi tanggal ISO lengkap ke waktu Zulu atau zona waktu mana pun yang diperlukan, sambil tetap mendapatkan informasi zona waktu pengirim.

Solusi terbaik yang pernah saya temui adalah menggunakan perpustakaan javascript Moment.js dan menggunakan kode berikut:

Untuk mendapatkan waktu ISO saat ini dengan informasi zona waktu dan milidetik

now = moment().format("YYYY-MM-DDTHH:mm:ss.SSSZZ")
// "2013-03-08T20:11:11.234+0100"

now = moment().utc().format("YYYY-MM-DDTHH:mm:ss.SSSZZ")
// "2013-03-08T19:11:11.234+0000"

now = moment().utc().format("YYYY-MM-DDTHH:mm:ss") + "Z"
// "2013-03-08T19:11:11Z" <- better use the native .toISOString() 

Untuk mendapatkan waktu ISO dari objek Tanggal JavaScript asli dengan informasi zona waktu tetapi tanpa milidetik

var current_time = Date.now();
moment(current_time).format("YYYY-MM-DDTHH:mm:ssZZ")

Ini dapat digabungkan dengan Date.js untuk mendapatkan fungsi seperti Date.today () yang hasilnya kemudian dapat diteruskan ke saat.

String tanggal yang diformat seperti ini adalah kompilasi JSON, dan cocok untuk disimpan ke dalam basis data. Python dan C # sepertinya menyukainya.

Daniel F
sumber
21
jangan mencari-cari orang kencan. Cukup gunakan moment.js dan simpan rambut Anda.
Valamas
1
sebenarnya, pada python dan db itu ternyata menyebalkan. db menggunakan UTC (tanpa masalah, karena Anda dapat dengan mudah mengonversi ke sisi server UTC), jadi jika Anda ingin menyimpan info offset, Anda perlu bidang lain. Dan Python lebih memilih penggunaan nanodetik daripada milidetik javascript, yang biasanya cukup dan lebih disukai selama detik biasa. Pada python, hanya dateutil.parser.parse yang menguraikannya dengan benar, dan untuk menulis milidetik, ISO membutuhkan "_when = when.strftime ("% Y-% m-% dT% H:% M:% S.% f% z "); kembalikan _when [: - 8] + _when [-5:]" untuk mengubah nanos menjadi millis. itu tidak baik.
Daniel F
3
Anda dapat benar-benar hanya menghilangkan format seperti: moment(new Date()).format(). "Pada versi 1.5.0, format # saat panggilan tanpa format akan secara default ke ... format ISO8601 YYYY-MM-DDTHH:mm:ssZ". Doc: Gulir ke atas dari momentjs.com/docs/#/displaying/fromnow
user193130
1
Good point @ user193130 tetapi Anda benar-benar perlu berhati-hati karena output berbeda dari metode asli. moment().format() "2015-03-04T17:16:05+03:00" (new Date()).toISOString() "2015-03-04T14:16:24.555Z"
Olga
1
Mungkin pilih-pilih tetapi contoh-contoh ini mengembalikan offset saat ini dari UTC, bukan zona waktu. Zona waktu adalah wilayah geografis yang biasanya dinyatakan sebagai misalnya "Amerika / Toronto". Banyak zona waktu mengubah offset UTC-nya dua kali setahun dan zona waktu tidak dapat (selalu) ditentukan dari offset UTC saat ini ... sehingga jawaban ini juga menjatuhkan informasi zona waktu :-)
Martin Fido
27

Pertanyaan yang diajukan adalah format ISO dengan presisi rendah. Voila:

 new Date().toISOString().slice(0, 19) + 'Z'
 // '2014-10-23T13:18:06Z'

Dengan asumsi Z trailing diinginkan, jika tidak hanya menghilangkan.

arcseldon
sumber
14

Terpendek, tetapi tidak didukung oleh Internet Explorer 8 dan sebelumnya:

new Date().toJSON()
younes0
sumber
12

Jika Anda tidak perlu mendukung IE7, berikut ini adalah peretasan hebat dan ringkas:

JSON.parse(JSON.stringify(new Date()))
Russell Davis
sumber
untuk IE7 keputusan ini juga cocok jika disertakan json3-library ( bestiejs.github.io/json3 ). Terima kasih :)
vladimir
Juga gagal di IE8. ("'JSON' tidak terdefinisi")
Cees Timmerman
1
Round-tripping melalui JSON jelek, terutama jika tujuan yang Anda nyatakan adalah keringkasan; gunakan metode tanggal toJSONsebagai gantinya. JSON.stringifytetap menggunakannya di bawah selimut.
Mark Amery
@CeesTimmerman IE8 mendukung JSONobjek, meskipun tidak dalam beberapa mode kompatibilitas. Lihat stackoverflow.com/questions/4715373/…
Mark Amery
3
Dalam hal apa ini lebih baik daripada .toISOString()?
Martin
7

Saya biasanya tidak ingin menampilkan tanggal UTC karena pelanggan tidak suka melakukan konversi di kepala mereka. Untuk menampilkan tanggal ISO lokal , saya menggunakan fungsi:

function toLocalIsoString(date, includeSeconds) {
    function pad(n) { return n < 10 ? '0' + n : n }
    var localIsoString = date.getFullYear() + '-'
        + pad(date.getMonth() + 1) + '-'
        + pad(date.getDate()) + 'T'
        + pad(date.getHours()) + ':'
        + pad(date.getMinutes()) + ':'
        + pad(date.getSeconds());
    if(date.getTimezoneOffset() == 0) localIsoString += 'Z';
    return localIsoString;
};

Fungsi di atas menghilangkan informasi offset zona waktu (kecuali jika waktu setempat adalah UTC), jadi saya menggunakan fungsi di bawah ini untuk menunjukkan offset lokal di satu lokasi. Anda juga dapat menambahkan outputnya ke hasil dari fungsi di atas jika Anda ingin menunjukkan offset di setiap waktu:

function getOffsetFromUTC() {
    var offset = new Date().getTimezoneOffset();
    return ((offset < 0 ? '+' : '-')
        + pad(Math.abs(offset / 60), 2)
        + ':'
        + pad(Math.abs(offset % 60), 2))
};

toLocalIsoStringmenggunakan pad. Jika diperlukan, ini berfungsi seperti hampir semua fungsi pad, tetapi demi kelengkapan inilah yang saya gunakan:

// Pad a number to length using padChar
function pad(number, length, padChar) {
    if (typeof length === 'undefined') length = 2;
    if (typeof padChar === 'undefined') padChar = '0';
    var str = "" + number;
    while (str.length < length) {
        str = padChar + str;
    }
    return str;
}
Charles Burns
sumber
3

Ada '+' yang hilang setelah 'T'

isoDate: function(msSinceEpoch) {
  var d = new Date(msSinceEpoch);
  return d.getUTCFullYear() + '-' + (d.getUTCMonth() + 1) + '-' + d.getUTCDate() + 'T'
         + d.getUTCHours() + ':' + d.getUTCMinutes() + ':' + d.getUTCSeconds();
}

harus melakukannya.

Untuk nol terkemuka Anda bisa menggunakan ini dari sini :

function PadDigits(n, totalDigits) 
{ 
    n = n.toString(); 
    var pd = ''; 
    if (totalDigits > n.length) 
    { 
        for (i=0; i < (totalDigits-n.length); i++) 
        { 
            pd += '0'; 
        } 
    } 
    return pd + n.toString(); 
} 

Menggunakannya seperti ini:

PadDigits(d.getUTCHours(),2)
kaiz.net
sumber
Tangkapan hebat! Itu tidak membahas "0" yang hilang.
James A. Rosen
1
Tulis fungsi untuk mengonversi bilangan bulat menjadi string 2 karakter (mengawali huruf '0' jika argumennya kurang dari 10), dan memanggilnya untuk setiap bagian dari tanggal / waktu.
dan04
3
function timeStr(d) { 
  return ''+
    d.getFullYear()+
    ('0'+(d.getMonth()+1)).slice(-2)+
    ('0'+d.getDate()).slice(-2)+
    ('0'+d.getHours()).slice(-2)+
    ('0'+d.getMinutes()).slice(-2)+
    ('0'+d.getSeconds()).slice(-2);
}
Sean
sumber
1
Dalam mode IE5 saya harus menempuh rute ini karena semua jawaban lain di sini menggunakan fungsi yang tidak ada.
Elaskanator
3

Masalah dengan toISOString adalah bahwa ia memberikan datetime hanya sebagai "Z".

ISO-8601 juga mendefinisikan datetime dengan perbedaan zona waktu dalam jam dan menit, dalam bentuk seperti 2016-07-16T19: 20: 30 + 5: 30 (saat zona waktu di depan UTC) dan 2016-07-16T19: 20: 30-01 : 00 (ketika zona waktu di belakang UTC).

Saya tidak berpikir itu ide yang baik untuk menggunakan plugin lain, moment.js untuk tugas sekecil itu, terutama ketika Anda bisa mendapatkannya dengan beberapa baris kode.



    var timezone_offset_min = new Date().getTimezoneOffset(),
        offset_hrs = parseInt(Math.abs(timezone_offset_min/60)),
        offset_min = Math.abs(timezone_offset_min%60),
        timezone_standard;

    if(offset_hrs < 10)
        offset_hrs = '0' + offset_hrs;

    if(offset_min > 10)
        offset_min = '0' + offset_min;

    // getTimezoneOffset returns an offset which is positive if the local timezone is behind UTC and vice-versa.
    // So add an opposite sign to the offset
    // If offset is 0, it means timezone is UTC
    if(timezone_offset_min < 0)
        timezone_standard = '+' + offset_hrs + ':' + offset_min;
    else if(timezone_offset_min > 0)
        timezone_standard = '-' + offset_hrs + ':' + offset_min;
    else if(timezone_offset_min == 0)
        timezone_standard = 'Z';

    // Timezone difference in hours and minutes
    // String such as +5:30 or -6:00 or Z
    console.log(timezone_standard); 

Setelah Anda mengimbangi zona waktu dalam beberapa jam dan menit, Anda dapat menambahkan string datetime.

Saya menulis posting blog di atasnya: http://usefulangle.com/post/30/javascript-get-date-time-with-offset-hours-minutes

Sudut yang berguna
sumber
2

Saya bisa mendapatkan output di bawah ini dengan kode yang sangat sedikit.

var ps = new Date('2010-04-02T14:12:07')  ;
ps = ps.toDateString() + " " + ps.getHours() + ":"+ ps.getMinutes() + " hrs";

Keluaran:

Fri Apr 02 2010 19:42 hrs
Srikanth Srikanth
sumber
0
function getdatetime() {
    d = new Date();
    return (1e3-~d.getUTCMonth()*10+d.toUTCString()+1e3+d/1)
        .replace(/1(..)..*?(\d+)\D+(\d+).(\S+).*(...)/,'$3-$1-$2T$4.$5Z')
        .replace(/-(\d)T/,'-0$1T');
}

Saya menemukan dasar-dasar pada Stack Overflow di suatu tempat (saya percaya itu adalah bagian dari beberapa golf kode Stack Exchange lainnya), dan saya memperbaikinya sehingga bekerja di Internet Explorer 10 atau lebih awal juga. Itu jelek, tapi itu menyelesaikan pekerjaan.

Jonas Byström
sumber
0

Untuk memperluas jawaban Sean yang hebat dan ringkas dengan sedikit gula dan sintaksis modern:

// date.js

const getMonthName = (num) => {
  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Oct', 'Nov', 'Dec'];
  return months[num];
};

const formatDate = (d) => {
  const date = new Date(d);
  const year = date.getFullYear();
  const month = getMonthName(date.getMonth());
  const day = ('0' + date.getDate()).slice(-2);
  const hour = ('0' + date.getHours()).slice(-2);
  const minutes = ('0' + date.getMinutes()).slice(-2);

  return `${year} ${month} ${day}, ${hour}:${minutes}`;
};

module.exports = formatDate;

Lalu misalnya.

import formatDate = require('./date');

const myDate = "2018-07-24T13:44:46.493Z"; // Actual value from wherever, eg. MongoDB date
console.log(formatDate(myDate)); // 2018 Jul 24, 13:44
Juha Untinen
sumber