So initialisieren Sie ein JavaScript-Datum für eine bestimmte Zeitzone


232

Ich habe Datums- und Uhrzeitangaben in einer bestimmten Zeitzone als Zeichenfolge und möchte diese in die Ortszeit konvertieren. Ich weiß jedoch nicht, wie ich die Zeitzone im Date-Objekt festlegen soll.

Zum Beispiel habe ich Feb 28 2013 7:00 PM ET,dann kann ich

var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);  

Soweit ich weiß, kann ich entweder die UTC-Zeit oder die Ortszeit einstellen. Aber wie stelle ich die Zeit in einer anderen Zeitzone ein?

Ich habe versucht, den Offset von UTC zu addieren / subtrahieren, aber ich weiß nicht, wie ich der Sommerzeit entgegenwirken kann. Ich bin mir nicht sicher, ob ich in die richtige Richtung gehe.

Wie kann ich die Zeit von einer anderen Zeitzone in die Ortszeit in Javascript konvertieren?



1
Datumsobjekte haben keine Zeitzone, sie sind UTC.
RobG

Antworten:


349

Hintergrund

Das JavaScript- DateObjekt verfolgt die Zeit in UTC intern, akzeptiert jedoch normalerweise Eingaben und erzeugt Ausgaben in der Ortszeit des Computers, auf dem es ausgeführt wird. Es gibt nur sehr wenige Möglichkeiten, mit der Zeit in anderen Zeitzonen zu arbeiten.

Die interne Darstellung eines DateObjekts ist eine einzelne Zahl, die die Anzahl der Millisekunden darstellt, die seitdem vergangen sind 1970-01-01 00:00:00 UTC, ohne Rücksicht auf Schaltsekunden. Im Date-Objekt selbst ist keine Zeitzone oder kein Zeichenfolgenformat gespeichert. Wenn verschiedene Funktionen des DateObjekts verwendet werden, wird die lokale Zeitzone des Computers auf die interne Darstellung angewendet. Wenn die Funktion eine Zeichenfolge erzeugt, können die Gebietsschemainformationen des Computers berücksichtigt werden, um zu bestimmen, wie diese Zeichenfolge erzeugt wird. Die Details variieren je nach Funktion und einige sind implementierungsspezifisch.

Die einzigen Operationen, die das DateObjekt mit nicht lokalen Zeitzonen ausführen kann, sind:

  • Es kann eine Zeichenfolge analysieren, die einen numerischen UTC-Versatz von einer beliebigen Zeitzone enthält. Damit wird der zu analysierende Wert angepasst und das UTC-Äquivalent gespeichert. Die ursprüngliche Ortszeit und der Offset werden im resultierenden DateObjekt nicht beibehalten . Beispielsweise:

    var d = new Date("2020-04-13T00:00:00.000+08:00");
    d.toISOString()  //=> "2020-04-12T16:00:00.000Z"
    d.valueOf()      //=> 1586707200000  (this is what is actually stored in the object)
    
  • In Umgebungen, in denen die ECMASCript Internationalization API (auch bekannt als "Intl") implementiert ist , kann ein DateObjekt eine länderspezifische Zeichenfolge erstellen, die an eine bestimmte Zeitzonen- ID angepasst ist. Dies wird über die timeZoneOption toLocaleStringund ihre Variationen erreicht. Die meisten Implementierungen unterstützen IANA-Zeitzonen-IDs, z 'America/New_York'. Beispielsweise:

    var d = new Date("2020-04-13T00:00:00.000+08:00");
    d.toLocaleString('en-US', { timeZone: 'America/New_York' })
    //=> "4/12/2020, 12:00:00 PM"
    // (midnight in China on Apring 13th is noon in New York on April 12th)
    

    Die meisten modernen Umgebungen unterstützen den vollständigen Satz von IANA-Zeitzonen-IDs ( siehe Kompatibilitätstabelle hier ). Doch bedenken Sie, dass die einzige Kennung erforderlich von Intl unterstützt werden soll 'UTC', so sollten Sie sorgfältig überprüfen , ob Sie älteren Browser oder atypische Umgebungen unterstützen müssen (zum Beispiel leichte IoT - Geräte).

Bibliotheken

Es gibt mehrere Bibliotheken, mit denen mit Zeitzonen gearbeitet werden kann. Obwohl sie das DateObjekt immer noch nicht anders verhalten können, implementieren sie normalerweise die Standard-IANA-Zeitzonendatenbank und bieten Funktionen für die Verwendung in JavaScript. Moderne Bibliotheken verwenden die von der Intl-API bereitgestellten Zeitzonendaten. Ältere Bibliotheken haben jedoch normalerweise Overhead, insbesondere wenn Sie in einem Webbrowser ausgeführt werden, da die Datenbank etwas größer werden kann. In einigen dieser Bibliotheken können Sie den Datensatz auch selektiv reduzieren, entweder nach Zeitzonen und / oder nach Datumsbereich, mit dem Sie arbeiten können.

Hier sind die zu berücksichtigenden Bibliotheken:

Intl-basierte Bibliotheken

Neuentwicklungen sollten aus einer dieser Implementierungen wählen, deren Zeitzonendaten auf der Intl-API basieren:

Nicht-internationale Bibliotheken

Diese Bibliotheken werden verwaltet, müssen jedoch ihre eigenen Zeitzonendaten verpacken, die sehr groß sein können.

* Während Moment und Moment-Timezone zuvor empfohlen wurden, bevorzugt das Moment-Team jetzt Benutzer, die Luxon für die Neuentwicklung ausgewählt haben.

Ausgelaufene Bibliotheken

Diese Bibliotheken wurden offiziell eingestellt und sollten nicht mehr verwendet werden.

Zukünftige Vorschläge

Der TC39-Zeitvorschlag zielt darauf ab, einen neuen Satz von Standardobjekten für die Arbeit mit Datum und Uhrzeit in der JavaScript-Sprache selbst bereitzustellen. Dies umfasst die Unterstützung eines zeitzonensensitiven Objekts.


1
Bitte ändern Sie "repräsentieren" in "ausgeben / analysieren", da die dargestellten Zeitstempel
zeitzonenunabhängig

1
@Bergi - Ich habe das überdacht und stimme dir zu. Meine Antwort wurde entsprechend aktualisiert.
Matt Johnson-Pint

1
Wenn Sie dies in der Firebug - Konsole zu tun: var date_time = new Date()der Wert von date_time(für mich in AEST) Date {Sun Aug 21 2016 22:18:47 GMT+1000 (AEST)}scheint und so damit es es hat eine Zeitzone gespeichert. Wie kann ich sicherstellen, dass date_timenur die UTC-Zeit ohne Zeitzone angegeben wird?
user1063287

Hmm, laut dieser Antwort ( stackoverflow.com/a/8047885/1063287 ) ist es dies: new Date().getTime();
user1063287

1
@ user1063287 - Die toString- Methode verwendet den Host-Zeitzonenversatz, um ein Datum und eine Uhrzeit in der "lokalen" Zeitzone zu erstellen. Das Datumsobjekt selbst hat einen Zeitwert, der ein Versatz von 1970-01-01T00: 00: 00Z ist, also effektiv UTC. Verwenden Sie toISOString , um Datum und Uhrzeit der UTC anzuzeigen .
RobG

68

Wie Matt Johnson sagte

Wenn Sie Ihre Nutzung auf moderne Webbrowser beschränken können, können Sie jetzt ohne spezielle Bibliotheken Folgendes tun:

new Date().toLocaleString("en-US", {timeZone: "America/New_York"})

Dies ist keine umfassende Lösung, funktioniert jedoch für viele Szenarien, in denen nur die Ausgabe konvertiert werden muss (von UTC oder Ortszeit in eine bestimmte Zeitzone, jedoch nicht in die andere Richtung).

Obwohl der Browser beim Erstellen eines Datums keine IANA-Zeitzonen lesen kann oder über Methoden zum Ändern der Zeitzonen für ein vorhandenes Datumsobjekt verfügt, scheint es einen Hack zu geben:

function changeTimezone(date, ianatz) {

  // suppose the date is 12:00 UTC
  var invdate = new Date(date.toLocaleString('en-US', {
    timeZone: ianatz
  }));

  // then invdate will be 07:00 in Toronto
  // and the diff is 5 hours
  var diff = date.getTime() - invdate.getTime();

  // so 12:00 in Toronto is 17:00 UTC
  return new Date(date.getTime() + diff);

}

// E.g.
var there = new Date();
var here = changeTimezone(there, "America/Toronto");

console.log(`Here: ${here.toString()}\nToronto: ${there.toString()}`);


5
Ich frage mich, warum diese Antwort nicht mehr Liebe bekommt. Für meine Zwecke ist es absolut die beste Lösung. In meiner App sind alle Daten UTC, müssen jedoch in expliziten IANA-Zeitzonen in der Benutzeroberfläche eingegeben oder ausgegeben werden. Zu diesem Zweck verwende ich diese Lösung und sie funktioniert perfekt. Einfach, effektiv, Standard.
Logidelic

2
@logidelic es ist ein ziemlich neuer Beitrag. um ehrlich zu sein, ich habe mich selbst erstaunt, als mir auffiel, dass man damit toLocaleStringden umgekehrten Effekt erzielen könnte , und ja, das sollte allgemein bekannt sein! schreibe einen Artikel darüber und erwähne mich :-)
commonpike

1
Für eine Knotenumgebung, die noch nicht in GMT enthalten ist, muss der obige Code von var invdate = new Date (date.toLocaleString ('en-US', {timeZone: ianatz})) geändert werden. in var invdate = neues Datum ($ {date.toLocaleString ('en-US', {timeZone: ianatz})} GMT`);
Mike P.

5
Browser müssen die Ausgabe von toLocaleString nicht analysieren , daher basiert sie auf einer fehlerhaften Prämisse.
RobG

3
"... warum bekommt diese Antwort nicht mehr Liebe?" - weil das DateObjekt, das es zurückgibt, eine Lüge ist. Selbst im gezeigten Beispiel enthält die Zeichenfolgenausgabe die Zeitzone des lokalen Computers. Auf meinem Computer steht in beiden Ergebnissen "GMT-0700 (Pacific Daylight Time)", wobei dies nur für den ersten korrekt ist (Toronto befindet sich tatsächlich in der Eastern Time). Über die reine Zeichenfolgenausgabe hinaus wurde der Zeitstempel im DateObjekt gespeichert zu einem anderen Zeitpunkt verschoben. Dies kann eine nützliche Technik sein, Datebringt jedoch viele Einschränkungen mit sich - vor allem, dass Objektfunktionen keine normale Ausgabe haben.
Matt Johnson-Pint

30

Sie können einen Zeitzonenversatz angeben new Date(), zum Beispiel:

new Date('Feb 28 2013 19:00:00 EST')

oder

new Date('Feb 28 2013 19:00:00 GMT-0500')

Da Datedie UTC-Zeit gespeichert wird (dh getTimein UTC zurückgegeben wird), konvertiert Javascript die Zeit in UTC. Wenn Sie beispielsweise toStringJavascript aufrufen , konvertiert die UTC-Zeit in die lokale Zeitzone des Browsers und gibt die Zeichenfolge in der lokalen Zeitzone zurück, dh wenn ich sie verwende UTC+8::

> new Date('Feb 28 2013 19:00:00 GMT-0500').toString()
< "Fri Mar 01 2013 08:00:00 GMT+0800 (CST)"

Sie können auch die normale getHours/Minute/SecondMethode verwenden:

> new Date('Feb 28 2013 19:00:00 GMT-0500').getHours()
< 8

(Dies 8bedeutet, dass nach der Umrechnung der Zeit in meine Ortszeit UTC+8die Stundenzahl lautet 8.)


16
Das Parsen eines anderen Formats als des erweiterten ISO 8601-Formats ist implementierungsabhängig und sollte nicht als zuverlässig angesehen werden. Es gibt keinen Standard für Zeitzonenabkürzungen, z. B. könnte "EST" eine von 3 verschiedenen Zonen darstellen.
RobG

1
Die Beispiele in diesem Kommentar funktionieren im Internet Explorer häufig nicht. Wie im vorherigen Kommentar zu diesem Beitrag erwähnt, ist ISO 8601 wichtig. Ich habe dies durch Lesen der Sprachspezifikation der Ausgabe ECMA-262 (Javascript 5th) bestätigt.
Dakusan

12

Dies sollte Ihr Problem lösen, bitte zögern Sie nicht, Korrekturen anzubieten. Diese Methode berücksichtigt auch die Sommerzeit für das angegebene Datum.

dateWithTimeZone = (timeZone, year, month, day, hour, minute, second) => {
  let date = new Date(Date.UTC(year, month, day, hour, minute, second));

  let utcDate = new Date(date.toLocaleString('en-US', { timeZone: "UTC" }));
  let tzDate = new Date(date.toLocaleString('en-US', { timeZone: timeZone }));
  let offset = utcDate.getTime() - tzDate.getTime();

  date.setTime( date.getTime() + offset );

  return date;
};

Verwendung mit Zeitzone und Ortszeit:

dateWithTimeZone("America/Los_Angeles",2019,8,8,0,0,0)

Diese Lösung war für meine Bedürfnisse geeignet. Ich war mir nicht sicher, wie genau ich die Sommerzeit erklären kann.
Hossein Amin

Warum nicht einfach tzDatedirekt zurückkehren?
Levi

8

Ich fand, dass der am meisten unterstützte Weg, dies zu tun, ohne sich um eine Bibliothek eines Drittanbieters zu sorgen, darin bestand getTimezoneOffset, den entsprechenden Zeitstempel zu berechnen oder die Uhrzeit zu aktualisieren und dann die normalen Methoden zu verwenden, um das erforderliche Datum und die erforderliche Uhrzeit zu erhalten.

var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);

// ET timezone offset in hours.
var timezone = -5;
// Timezone offset in minutes + the desired offset in minutes, converted to ms.
// This offset should be the same for ALL date calculations, so you should only need to calculate it once.
var offset = (mydate.getTimezoneOffset() + (timezone * 60)) * 60 * 1000;

// Use the timestamp and offset as necessary to calculate min/sec etc, i.e. for countdowns.
var timestamp = mydate.getTime() + offset,
    seconds = Math.floor(timestamp / 1000) % 60,
    minutes = Math.floor(timestamp / 1000 / 60) % 60,
    hours   = Math.floor(timestamp / 1000 / 60 / 60);

// Or update the timestamp to reflect the timezone offset.
mydate.setTime(mydate.getTime() + offset);
// Then Output dates and times using the normal methods.
var date = mydate.getDate(),
    hour = mydate.getHours();

BEARBEITEN

Ich habe zuvor UTCMethoden verwendet, um die Datumstransformationen durchzuführen, was falsch war. Wenn Sie den Versatz zur Zeit hinzufügen, werden bei Verwendung der lokalen getFunktionen die gewünschten Ergebnisse zurückgegeben.


Wo hast du gerechnet timezone_offset?
Anand Somani

1
Hoppla, ich habe eine meiner Variablen falsch beschriftet. timezone_offsethätte sein sollen offsetoder umgekehrt. Ich habe meine Antwort so bearbeitet, dass der richtige Variablenname angezeigt wird.
Shaun Cockerill

3

Ich bin auf ein ähnliches Problem mit Komponententests gestoßen (insbesondere im Scherz, wenn die Komponententests lokal ausgeführt werden, um die Snapshots zu erstellen, und der CI-Server dann (möglicherweise) in einer anderen Zeitzone ausgeführt wird, wodurch der Snapshot-Vergleich fehlschlägt). Ich verspottete unsere Dateund einige der unterstützenden Methoden wie folgt:

describe('...', () => {
  let originalDate;

  beforeEach(() => {
    originalDate = Date;
    Date = jest.fn(
      (d) => {
        let newD;
        if (d) {
          newD = (new originalDate(d));
        } else {
          newD = (new originalDate('2017-05-29T10:00:00z'));
        }
        newD.toLocaleString = () => {
          return (new originalDate(newD.valueOf())).toLocaleString("en-US", {timeZone: "America/New_York"});
        };
        newD.toLocaleDateString = () => {
          return (new originalDate(newD.valueOf())).toLocaleDateString("en-US", {timeZone: "America/New_York"});
        };
        newD.toLocaleTimeString = () => {
          return (new originalDate(newD.valueOf())).toLocaleTimeString("en-US", {timeZone: "America/New_York"});
        };
        return newD;
      }
    );
    Date.now = () => { return (Date()); };
  });

  afterEach(() => {
    Date = originalDate;
  });

});


2

Aufbauend auf den obigen Antworten verwende ich diesen nativen Einzeiler, um die lange Zeitzonenzeichenfolge in die Zeichenfolge mit drei Buchstaben umzuwandeln:

var longTz = 'America/Los_Angeles';
var shortTz = new Date().
    toLocaleString("en", {timeZoneName: "short", timeZone: longTz}).
    split(' ').
    pop();

Dies gibt PDT oder PST je nach angegebenem Datum. In meinem speziellen Anwendungsfall, der sich auf Salesforce (Aura / Lightning) entwickelt, können wir die Benutzerzeitzone im Langformat vom Backend abrufen.


Nur weil ich von Zeit zu Zeit gerne Pedant spiele, ist 'America / Los_Angeles' keine Zeitzone, sondern ein "repräsentativer Ort" für bestimmte Offset- und Sommerzeitregeln und den Verlauf dieser Änderungen (gemäß der IANA-Zeitzonendatenbank ). . ;-)
RobG

Haha, Sie müssen diesen Kommentar zu mehreren Antworten hier posten: P
Shane

2

Ich weiß, dass es 3 Jahre zu spät ist, aber vielleicht kann es jemand anderem helfen, weil ich so etwas nicht gefunden habe, außer der Moment-Zeitzonen-Bibliothek, die nicht genau das ist, was er hier verlangt.

Ich habe etwas Ähnliches für die deutsche Zeitzone gemacht. Dies ist aufgrund der Sommerzeit und der Schaltjahre, in denen Sie 366 Tage haben, etwas komplex.

Möglicherweise ist ein wenig Arbeit mit der Funktion "isDaylightSavingTimeInGermany" erforderlich, während sich verschiedene Zeitzonen zu unterschiedlichen Zeiten der Sommerzeit ändern.

Schauen Sie sich trotzdem diese Seite an: https://github.com/zerkotin/german-timezone-converter/wiki

Die Hauptmethoden sind: convertLocalDateToGermanTimezone convertGermanDateToLocalTimezone

Ich habe mich bemüht, es zu dokumentieren, damit es nicht so verwirrend wird.


Dies sollte ein Kommentar sein, es ist keine Antwort.
RobG

1

Versuchen Sie: Datum von Zeitzone , es löst das erwartete Datum mithilfe von nativ verfügbar auf Intl.DateTimeFormat.

Ich habe diese Methode bereits seit einigen Jahren in einem meiner Projekte verwendet, aber jetzt habe ich beschlossen, sie als kleines Betriebssystemprojekt zu veröffentlichen :)


0

Für Ionic-Benutzer hatte ich die Hölle damit, weil .toISOString()es mit der HTML-Vorlage verwendet werden muss.

Dadurch wird das aktuelle Datum erfasst, es kann jedoch natürlich zu früheren Antworten für ein ausgewähltes Datum hinzugefügt werden.

Ich habe es damit behoben:

date = new Date();
public currentDate: any = new Date(this.date.getTime() - this.date.getTimezoneOffset()*60000).toISOString();

Der * 60000 zeigt die UTC -6 an, bei der es sich um CST handelt. Unabhängig von der benötigten Zeitzone können Anzahl und Differenz geändert werden.


Dies ist nicht die Antwort, nach der der Fragesteller sucht. Er suchte nach einem Datum für die jeweilige Zeitzone.
Richard Vergis

@RichardVergis Die Frage gibt eindeutig an, dass der Benutzer zur Ortszeit wechseln möchte, gibt jedoch nicht an, in welcher Zeitzone er sich befindet. Ich habe meine Zeitzone als Beispiel angegeben, und der Benutzer kann anhand meines Beispiels klar lesen und Eingaben vornehmen ihr Zeitzonenversatz.
Stephen Romero

0

Vielleicht hilft dir das

/**
 * Shift any Date timezone.
 * @param {Date} date - Date to update.
 * @param {string} timezone - Timezone as `-03:00`.
 */
function timezoneShifter(date, timezone) {
  let isBehindGTM = false;
  if (timezone.startsWith("-")) {
    timezone = timezone.substr(1);
    isBehindGTM = true;
  }

  const [hDiff, mDiff] = timezone.split(":").map((t) => parseInt(t));
  const diff = hDiff * 60 + mDiff * (isBehindGTM ? 1 : -1);
  const currentDiff = new Date().getTimezoneOffset();

  return new Date(date.valueOf() + (currentDiff - diff) * 60 * 1000);
}



const _now = new Date()
console.log(
  [
    "Here: " + _now.toLocaleString(),
    "Greenwich: " + timezoneShifter(_now, "00:00").toLocaleString(),
    "New York: " + timezoneShifter(_now, "-04:00").toLocaleString(),
    "Tokyo: " + timezoneShifter(_now, "+09:00").toLocaleString(),
    "Buenos Aires: " + timezoneShifter(_now, "-03:00").toLocaleString(),
  ].join('\n')
);


-2

War vor dem gleichen Problem, benutzte dieses

Console.log (Date.parse ("13. Juni 2018, 10:50:39 GMT + 1"));

Es wird Millisekunden zurückgeben, auf die Sie überprüfen können, ob +100 Timzone die britische Zeit initialisiert. Hoffe, es hilft !!


3
(Dieser Beitrag scheint keine qualitativ hochwertige Antwort auf die Frage zu liefern . Bitte bearbeiten Sie entweder Ihre Antwort oder veröffentlichen Sie sie einfach als Kommentar zur Frage.)
sɐunıɔ ןɐ qɐp
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.