ISO 8601, JavaScript'te Saat Dilimi Uzaklığı ile Tarih nasıl biçimlendirilir?


103

Hedef: URL'yi bulun local timeve UTC time offsetardından aşağıdaki biçimde oluşturun.

Örnek URL: / Eylemler / Uyku? Süresi = 2002-10-10T12: 00: 00−05: 00

Biçim, W3C önerisine dayanmaktadır: http://www.w3.org/TR/xmlschema11-2/#dateTime

Belgeler şunu söylüyor:

Örneğin, 2002-10-10T12: 00: 00-05: 00 (10 Ekim 2002 öğlen, ABD'de Orta Yaz Saati Uygulaması ve Doğu Standart Saati) 2002-10-10T17: 00: 00Z'ye eşittir, 2002-10-10T12: 00: 00Z'den beş saat sonra.

Bu yüzden, anladığıma göre, yerel saatimi new Date () ile bulmam ve ardından farkı hesaplamak için getTimezoneOffset () fonksiyonunu kullanmam ve ardından onu dizenin sonuna eklemem gerekiyor.

1. Format ile yerel saati öğrenin

var local = new Date().format("yyyy-MM-ddThh:mm:ss"); //today (local time)

çıktı

2013-07-02T09:00:00

2. UTC saat farkını saate göre alın

var offset = local.getTimezoneOffset() / 60;

çıktı

7

3. URL'yi oluşturun (yalnızca zaman bölümü)

var duration = local + "-" + offset + ":00";

çıktı:

2013-07-02T09:00:00-7:00

Yukarıdaki çıktı, yerel saatimin 2013/07/02 09:00 ve UTC'den farkın 7 saat olduğu anlamına gelir (UTC, yerel saatin 7 saat ilerisindedir)

Şimdiye kadar işe yarıyor gibi görünüyor ama ya getTimezoneOffset () -120 gibi negatif bir değer döndürürse?

Böyle bir durumda formatın nasıl görünmesi gerektiğini merak ediyorum çünkü W3C belgesinden anlayamıyorum. Şimdiden teşekkürler.

Yanıtlar:


178

Aşağıdakiler düzgün çalışmalı ve tüm tarayıcılar için (ipucu için @MattJohnson'a teşekkürler)

Date.prototype.toIsoString = function() {
    var tzo = -this.getTimezoneOffset(),
        dif = tzo >= 0 ? '+' : '-',
        pad = function(num) {
            var norm = Math.floor(Math.abs(num));
            return (norm < 10 ? '0' : '') + norm;
        };
    return this.getFullYear() +
        '-' + pad(this.getMonth() + 1) +
        '-' + pad(this.getDate()) +
        'T' + pad(this.getHours()) +
        ':' + pad(this.getMinutes()) +
        ':' + pad(this.getSeconds()) +
        dif + pad(tzo / 60) +
        ':' + pad(tzo % 60);
}

var dt = new Date();
console.log(dt.toIsoString());


2
İşaret, yerel saatin GMT'den farkını gösterir
Steven Moseley

1
@ masato-san İşareti ters
çevirmelisiniz

2
Burada pad işlevi, milisaniyeler dışında her tarih bölümü için uygun dizge döndürür. Örneğin, 5 ms için bir giriş olarak 005 olması gereken 05 değerini döndürecektir. İşte aynı fonksiyonun minimum değiştirilmiş versiyonunu içeren bir bağlantı jsbin
Safique Ahmed Faruque

9
Lütfen dikkat: Bu cevapta ince bir hata var. Saat dilimi farkı, bölgenin fark dakikalarına sahipse ve Fransa ve Kanada'daki belirli konumlar gibi negatif (ör. -09: 30) ise doğru hesaplanmayacaktır. Mod negatif bir sayı döndürür, bu nedenle abs () 'den önce floor () yapmak yanlışlıkla ofseti MORE negatif yaptı. Bu hatayı düzeltmek için abs () ve SONRA kat (). Yanıtı düzenlemeye çalıştım, ancak görünüşe göre "Bu düzenleme, yazının yazarına hitap etmeyi amaçlıyordu ve düzenleme olarak bir anlam ifade etmiyor".
tytk

5
@tytk - Harika yakalayış! Bu gerçekten ince. Düzeltmenizi yanıta ekledim. Yorum yaptığınız için teşekkürler!
Steven Moseley

67

getTimezoneOffset() Başvurduğunuz spesifikasyonun gerektirdiği formatın zıt işaretini döndürür.

Bu biçim aynı zamanda ISO8601 veya daha doğrusu RFC3339 olarak da bilinir .

Bu biçimde, UTC bir ile temsil Zedilirken, diğer tüm biçimler UTC'den bir farkla temsil edilir. Anlamı JavaScript'le aynıdır, ancak çıkarma sırası tersine çevrilir, bu nedenle sonuç zıt işaretini taşır.

Ayrıca, yerel Datenesnede çağrılan bir yöntem yoktur format, bu nedenle, bunu başarmak için bir kitaplık kullanmadığınız sürece 1 numaralı işleviniz başarısız olacaktır. Bu belgelere bakın .

Doğrudan bu formatla çalışabilecek bir kütüphane arıyorsanız , moment.js'yi denemenizi tavsiye ederim . Aslında, bu varsayılan biçimdir, dolayısıyla bunu kolayca yapabilirsiniz:

var m = moment();    // get "now" as a moment
var s = m.format();  // the ISO format is the default so no parameters are needed

// sample output:   2013-07-01T17:55:13-07:00

Bu, iyi test edilmiş, tarayıcılar arası bir çözümdür ve başka birçok kullanışlı özelliğe sahiptir.


ToISOString () kullanmak işe yaramaz. +01: 00 biçimi, zaman bölümünün yerel saat olmasını gerektirir. toISOString () bir UTC zaman dizesi verecektir.
Austin Fransa

1
@AustinFrance - Haklısın! Başkalarını bu noktada sık sık düzelttiğim için o zaman bu hatayı yaptığıma şaşırdım. Üzgünüm iki yıl önce yorumunuzu görmedim! Cevap düzenlendi.
Matt Johnson-Pint

9

Standart kitaplığa tek bir API çağrısı ile istenen bilgileri alabileceğinizi düşünmeye değer diye düşünüyorum ...

new Date().toLocaleString( 'sv', { timeZoneName: 'short' } );

// produces "2019-10-30 15:33:47 GMT−4"

'T' sınırlayıcısını eklemek, 'GMT-' yi kaldırmak veya ': 00' karakterini sona eklemek istiyorsanız, metin değiştirme yapmanız gerekir.

Ancak , örneğin isterseniz diğer seçeneklerle kolayca oynayabilirsiniz . 12 saat kullanın veya saniyeyi atlayın vb.

ISO 8601 biçimini kullanan ülkelerden biri olduğu için İsveç'i yerel ayar olarak kullandığımı unutmayın. Sanırım ISO ülkelerinin çoğu bu 'GMT-4' biçimini saat dilimi farkı için Kanada dışında saat dilimi kısaltmasını kullanan örn. Doğu gündüz saati için "EDT".

Aynı şeyi daha yeni standart i18n işlevi "Intl.DateTimeFormat ()" ile de elde edebilirsiniz, ancak seçenekler aracılığıyla saati dahil etmesini söylemelisiniz yoksa sadece tarih verecektir.


1
Hm, sv için aslında "CET" ve bir yaz saati tarihi için "CEST" alıyorum ... Ama girdi için teşekkürler, standart API benim için yeterli (günlük mesajlarına bir tarih eklemek gerekir). Zaman ve saat dilimlerini ciddiye almak isteseydim, sanırım anlık kitaplığa giderdim ...
mmey

4

Bu, istemcilerin saat dilimi için benim işlevim, hafif ve basit

  function getCurrentDateTimeMySql() {        
      var tzoffset = (new Date()).getTimezoneOffset() * 60000; //offset in milliseconds
      var localISOTime = (new Date(Date.now() - tzoffset)).toISOString().slice(0, 19).replace('T', ' ');
      var mySqlDT = localISOTime;
      return mySqlDT;
  }

@tsh, emin misin? Daha sonra yerel saati simüle etmek için kullanılan geçerli saat farkını alıyorsunuz. Belki o noktada ofset farklıydı, ama önemli değil çünkü sadece şimdiyi önemsiyorsun.
Andrew

2

Şuna göz at:

function dateToLocalISO(date) {
    const off    = date.getTimezoneOffset()
    const absoff = Math.abs(off)
    return (new Date(date.getTime() - off*60*1000).toISOString().substr(0,23) +
            (off > 0 ? '-' : '+') + 
            (absoff / 60).toFixed(0).padStart(2,'0') + ':' + 
            (absoff % 60).toString().padStart(2,'0'))
}

// Test it:
d = new Date()

dateToLocalISO(d)
// ==> '2019-06-21T16:07:22.181-03:00'

// Is similar to:

moment = require('moment')
moment(d).format('YYYY-MM-DDTHH:mm:ss.SSSZ') 
// ==> '2019-06-21T16:07:22.181-03:00'

1

Buraya sadece iki gönderiyorum

Bu sorunla veri saatleriyle karşı karşıyaydım, bu yüzden yaptığım şey şuydu:

const moment = require('moment-timezone')

const date = moment.tz('America/Bogota').format()

Sonra tarihi bir sorgudan karşılaştırabilmek için veritabanına kaydedin.


Yüklemek moment-timezone

npm i moment-timezone

1

Moment.js'ye gerek yok: İşte bir ISOLocal dizesini GMT'de UTC saniyelerine ve geri veren "datetime-local" giriş türünden tam bir gidiş dönüş cevabı :

<input type="datetime-local" value="2020-02-16T19:30">

isoLocal="2020-02-16T19:30"
utcSeconds=new Date(isoLocal).getTime()/1000

//here you have 1581899400 for utcSeconds

let isoLocal=new Date(utcSeconds*1000-new Date().getTimezoneOffset()*60000).toISOString().substring(0,16)
2020-02-16T19:30

0

Cevabım, YYYY-AA-GG formatında yerel saat diliminde bugünün tarihini isteyenler için küçük bir değişiklik.

Açıklığa kavuşturayım:

Benim Hedef: get bugünün tarihini de kullanıcının saat dilimi ama ISO8601 olarak biçimlendirilmiş (YYYY-AA-GG)

İşte kod:

new Date().toLocaleDateString("sv") // "2020-02-23" // 

Bu işe yarar çünkü İsveç yerel ayarı ISO 8601 biçimini kullanır.


Geçersiz cevap, bu cevap, ama başka bir soru ... Bu cevap SO'da kolayca bulunabilir.
PsychoX

0

İşte bu amaç için kullandığım işlevler:

function localToGMTStingTime(localTime = null) {
    var date = localTime ? new Date(localTime) : new Date();
    return new Date(date.getTime() + (date.getTimezoneOffset() * 60000)).toISOString();
};

function GMTToLocalStingTime(GMTTime = null) {
    var date = GMTTime ? new Date(GMTTime) : new Date();;
    return new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString();
};

0

Bunu birkaç basit uzatma yöntemi ile başarabilirsiniz. Aşağıdaki Tarih uzantısı yöntemi yalnızca ISO biçiminde saat dilimi bileşenini döndürür, ardından tarih / saat bölümü için başka bir bileşen tanımlayabilir ve bunları eksiksiz bir tarih-saat-uzaklık dizesi için birleştirebilirsiniz.

Date.prototype.getISOTimezoneOffset = function () {
    const offset = this.getTimezoneOffset();
    return (offset < 0 ? "+" : "-") + Math.floor(Math.abs(offset / 60)).leftPad(2) + ":" + (Math.abs(offset % 60)).leftPad(2);
}

Date.prototype.toISOLocaleString = function () {
    return this.getFullYear() + "-" + (this.getMonth() + 1).leftPad(2) + "-" +
        this.getDate().leftPad(2) + "T" + this.getHours().leftPad(2) + ":" +
        this.getMinutes().leftPad(2) + ":" + this.getSeconds().leftPad(2) + "." +
        this.getMilliseconds().leftPad(3);
}

Number.prototype.leftPad = function (size) {
    var s = String(this);
    while (s.length < (size || 2)) {
        s = "0" + s;
    }
    return s;
}

Örnek kullanım:

var date = new Date();
console.log(date.toISOLocaleString() + date.getISOTimezoneOffset());
// Prints "2020-08-05T16:15:46.525+10:00"

2020 olduğunu biliyorum ve çoğu insan şu anda muhtemelen Moment.js kullanıyor, ancak basit bir kopya ve yapıştırılabilir çözüme sahip olmak hala kullanışlı.

(Tarih / saat ve uzaklık yöntemlerini bölmemin nedeni toString, özel biçim belirticileriyle zaten esnek bir yöntem sağlayan, ancak saat dilimi farkını içermeyen eski bir Datejs kitaplığı kullanmamdır . Bu nedenle, toISOLocaleStringolmayan herkes için ekledim . söz konusu kütüphane.)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.