Làm cách nào để xuất chuỗi định dạng ISO 8601 trong JavaScript?


247

Tôi có một Dateđối tượng. Làm cách nào để hiển thị titlephần của đoạn mã sau?

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

Tôi có phần "thời gian tương đối trong từ" từ thư viện khác.

Tôi đã thử như sau:

function isoDate(msSinceEpoch) {

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

}

Nhưng điều đó mang lại cho tôi:

"2010-4-2T3:19"

Câu trả lời:


453

Đã có một chức năng gọi là toISOString():

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

Nếu, bằng cách nào đó, bạn đang ở trên một trình duyệt không hỗ trợ nó, tôi đã bảo vệ bạn:

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

  }() );
}

1
.toISOString () chắc chắn trả về ngày trong UTC?
Jon Wells

new Date("xx").toISOString()tạo ra NaN-NaN-NaNTNaN:NaN:NaN.NZviệc thực hiện riêng ném RangeException.
Joseph Lennox

Nếu bạn muốn chuyển một đối tượng ngày cho một dịch vụ xà phòng ... đó là cách! :) Cảm ơn.
thinklinux

1
Trong mẫu do OP cung cấp, không có mili giây hoặc múi giờ.
Dan Dascalescu

Tất cả các lệnh gọi hàm như "getUTCFullYear" đều thất bại vì chúng không được biết đến ở chế độ tài liệu IE 5.
Elaskanator

63

Xem ví dụ cuối cùng trên trang 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

1
Mẫu được cung cấp bởi OP ( <abbr title="2010-04-02T14:12:07">) không có múi giờ. Có lẽ họ muốn giờ địa phương, điều này có ý nghĩa đối với chuỗi thời gian UI?
Dan Dascalescu

60

Hầu như mọi phương thức ISO trên web đều giảm thông tin múi giờ bằng cách áp dụng chuyển đổi thành "Z" ulu time (UTC) trước khi xuất chuỗi. Trình duyệt .toISOString () của trình duyệt cũng giảm thông tin múi giờ.

Điều này loại bỏ thông tin có giá trị, như máy chủ hoặc người nhận, luôn có thể chuyển đổi ngày ISO đầy đủ thành thời gian Zulu hoặc bất kỳ múi giờ nào yêu cầu, trong khi vẫn nhận được thông tin múi giờ của người gửi.

Giải pháp tốt nhất tôi gặp phải là sử dụng thư viện javascript của Moment.js và sử dụng mã sau:

Để có được thời gian ISO hiện tại với thông tin múi giờ và mili giây

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

Để có được thời gian ISO của đối tượng Ngày JavaScript gốc với thông tin múi giờ nhưng không có mili giây

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

Điều này có thể được kết hợp với Date.js để có được các hàm như Date.today () có kết quả có thể được chuyển đến thời điểm này.

Một chuỗi ngày được định dạng như thế này là trình biên dịch JSON và tự cho vay tốt để được lưu trữ vào cơ sở dữ liệu. Python và C # có vẻ thích nó.


21
không những thứ xung quanh với ngày người. Chỉ cần sử dụng khoảnh khắc và lưu lại mái tóc của bạn.
Valamas

1
Thật ra, trên python và db, nó trở thành một nỗi đau. db sử dụng UTC (không có thăm dò, vì bạn có thể dễ dàng chuyển đổi sang phía máy chủ UTC), vì vậy nếu bạn muốn giữ thông tin bù trừ, bạn cần một trường khác. Và Python thích sử dụng nano giây thay vì mili giây của javascript, thường là đủ và thích hợp hơn trong vài giây. Trên python, chỉ dateutil.parser.parse phân tích cú pháp chính xác và để viết một phần nghìn giây, ISO cần có "_when = when.strftime ("% Y-% m-% dT% H:% M:% S.% f% z "); return _when [: - 8] + _when [-5:]" để chuyển đổi nanos thành millis. Điều đó không tốt.
Daniel F

3
Bạn thực sự có thể bỏ qua định dạng như vậy : moment(new Date()).format(). "Kể từ phiên bản 1.5.0, định dạng cuộc gọi # không có định dạng sẽ mặc định là ... định dạng ISO8601 YYYY-MM-DDTHH:mm:ssZ". Tài liệu: Cuộn lên từ khoảnh khắc js.com/docs/#/displaying/fromnow
user193130

1
Điểm tốt @ user193130 nhưng bạn thực sự cần phải cẩn thận vì đầu ra khác với phương thức gốc. moment().format() "2015-03-04T17:16:05+03:00" (new Date()).toISOString() "2015-03-04T14:16:24.555Z"
Olga

1
Có thể kén chọn nhưng những ví dụ này trả về phần bù hiện tại từ UTC, không phải múi giờ. Múi giờ là một khu vực địa lý thường được biểu thị như "America / Toronto". Nhiều múi giờ thay đổi độ lệch UTC của họ hai lần một năm và múi giờ không thể (luôn luôn) được xác định từ độ lệch UTC hiện tại ... do đó, câu trả lời này cũng làm giảm thông tin múi giờ :-)
Martin Fido

27

Câu hỏi được hỏi là định dạng ISO với độ chính xác giảm. Voila:

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

Giả sử Z theo sau là muốn, nếu không thì bỏ qua.


14

Ngắn nhất, nhưng không được Internet Explorer 8 hỗ trợ và sớm hơn:

new Date().toJSON()

12

Nếu bạn không cần hỗ trợ IE7, sau đây là một bản hack ngắn gọn, tuyệt vời:

JSON.parse(JSON.stringify(new Date()))

đối với IE7, quyết định này cũng phù hợp nếu được đưa vào thư viện json3 ( bestiejs.github.io/json3 ). Cảm ơn :)
vladimir

Cũng thất bại trong IE8. ("'JSON' không xác định")
Cees Timmerman

1
Vượt qua JSON là xấu, đặc biệt nếu mục tiêu đã nêu của bạn là sự đồng nhất; sử dụng toJSONphương pháp của ngày thay thế. JSON.stringifydù sao cũng đang sử dụng nó dưới vỏ bọc.
Mark Amery

@CeesTimmerman IE8 hỗ trợ JSONđối tượng, mặc dù không ở một số chế độ tương thích. Xem stackoverflow.com/questions/4715373/ cường
Mark Amery

3
Theo cách này thì tốt hơn .toISOString()?
Martin

7

Tôi thường không muốn hiển thị ngày UTC vì khách hàng không thích thực hiện chuyển đổi trong đầu. Để hiển thị ngày ISO cục bộ , tôi sử dụng chức năng:

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

Hàm trên bỏ qua thông tin bù múi giờ (trừ khi giờ địa phương xảy ra là UTC), vì vậy tôi sử dụng hàm bên dưới để hiển thị bù cục bộ ở một vị trí. Bạn cũng có thể nối đầu ra của nó vào kết quả từ chức năng trên nếu bạn muốn hiển thị phần bù mỗi lần:

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

toLocalIsoStringsử dụng pad. Nếu cần, nó hoạt động giống như gần như bất kỳ chức năng pad nào, nhưng để hoàn thiện thì đây là thứ tôi sử dụng:

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

3

Có dấu '+' sau 'T'

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

Hãy làm nó.

Đối với các số 0 hàng đầu, bạn có thể sử dụng số này từ đây :

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

Sử dụng nó như thế này:

PadDigits(d.getUTCHours(),2)

Cú bắt tuyệt vời! Tuy nhiên, nó không giải quyết các "0" bị thiếu.
James A. Rosen

1
Viết hàm để chuyển đổi một số nguyên thành chuỗi 2 ký tự (đặt trước '0' nếu đối số nhỏ hơn 10) và gọi nó cho từng phần của ngày / giờ.
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);
}

1
Trong chế độ IE5 tôi đã phải đi theo lộ trình này vì tất cả các câu trả lời khác ở đây đã sử dụng các hàm không tồn tại.
Elaskanator

3

Vấn đề với toISOString là nó chỉ cung cấp datetime dưới dạng "Z".

ISO-8601 cũng xác định datetime với chênh lệch múi giờ theo giờ và phút, trong các hình thức như 2016-07-16T19: 20: 30 + 5: 30 (khi múi giờ đi trước UTC) và 2016-07-16T19: 20: 30-01 : 00 (khi múi giờ đứng sau UTC).

Tôi không nghĩ nên sử dụng một plugin khác, khoảnh khắc.js cho một nhiệm vụ nhỏ như vậy, đặc biệt là khi bạn có thể nhận được nó với một vài dòng mã.



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

Khi bạn có thời gian bù theo giờ và phút, bạn có thể nối vào chuỗi thời gian.

Tôi đã viết một bài đăng trên blog: http://usiouslyangle.com/post/30/javascript-get-date-time-with-offset-hours-minutes



2

Tôi đã có thể nhận được dưới đầu ra với mã rất ít.

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

Đầu ra:

Fri Apr 02 2010 19:42 hrs

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

Tôi đã tìm thấy những điều cơ bản trên Stack Overflow ở đâu đó (tôi tin rằng đó là một phần của một số môn đánh gôn Stack Exchange khác) và tôi đã cải thiện nó để nó hoạt động trên Internet Explorer 10 hoặc sớm hơn. Nó xấu, nhưng nó hoàn thành công việc.


0

Để mở rộng câu trả lời tuyệt vời và súc tích của Sean với một số cú pháp hiện đại và đường:

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

Sau đó, ví dụ.

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