Jak uzyskać znacznik czasu UTC w JavaScript?

157

Podczas pisania aplikacji internetowej sensowne jest przechowywanie (po stronie serwera) wszystkich dat w bazie danych jako znaczników czasu UTC.

Byłem zdumiony, gdy zauważyłem, że natywnie nie można zrobić zbyt wiele w zakresie manipulacji strefą czasową w JavaScript.

Rozszerzyłem nieco obiekt Date. Czy ta funkcja ma sens? Zasadniczo za każdym razem, gdy wysyłam cokolwiek na serwer, będzie to znacznik czasu sformatowany za pomocą tej funkcji ...

Czy widzisz tutaj jakieś poważne problemy? A może rozwiązanie z innej strony?

Date.prototype.getUTCTime = function(){ 
  return new Date(
    this.getUTCFullYear(),
    this.getUTCMonth(),
    this.getUTCDate(),
    this.getUTCHours(),
    this.getUTCMinutes(), 
    this.getUTCSeconds()
  ).getTime(); 
}

Po prostu wydaje mi się to trochę zagmatwane. I nie jestem pewien co do wydajności.

Merc
źródło
Wiem, że to stare pytanie, ale staraj się nie rozszerzać obiektów natywnych, takich jak obiekt Date. Uznano, ponieważ podoba mi się samo pytanie.
trysis
Date.parse (new Date (). ToUTCString ())
Sagi
25
To stare pytanie, które pojawiło się dzisiaj w moim kanale i jest pełne dezinformacji. Sygnatura czasowa jest zawsze w UTC. new Date().toString()pokaże reprezentację czasową aktualnej strefy czasowej, new Date().toUTCString()pokaże czas UTC, ale zawszenew Date().getTime() jest to UTC , ponieważ tak definiuje się czas uniksowy: "Czas uniksowy (znany również jako czas POSIX lub czas epoki) to system do opisywania chwil w czasie, zdefiniowana jako liczba sekund, które upłynęły od 00:00:00 uniwersalnego czasu koordynowanego (UTC), czwartek, 1 stycznia 1970 r., nie licząc sekund przestępnych. "
Amadan,

Odpowiedzi:

155
  1. Daty skonstruowane w ten sposób korzystają z lokalnej strefy czasowej, przez co data utworzenia jest nieprawidłowa. Aby ustawić strefę czasową określonego obiektu daty, należy skonstruować go na podstawie ciągu dat, który zawiera strefę czasową. (Miałem problemy z uruchomieniem tego w starszej przeglądarce Androida).

  2. Zwróć uwagę, że getTime()zwraca milisekundy, a nie zwykłe sekundy.

W przypadku znacznika czasu UTC / Unix wystarczy:

Math.floor((new Date()).getTime() / 1000)

Uwzględni to aktualne przesunięcie strefy czasowej w wyniku. W przypadku reprezentacji łańcuchowej działa odpowiedź Davida Ellisa .

W celu wyjaśnienia:

new Date(Y, M, D, h, m, s)

Te dane wejściowe są traktowane jako czas lokalny . Jeśli zostanie przekazany czas UTC , wyniki będą się różnić. Obserwuj (jestem teraz w GMT +02: 00, a jest 07:50):

> var d1 = new Date();
> d1.toUTCString();
"Sun, 18 Mar 2012 05:50:34 GMT" // two hours less than my local time
> Math.floor(d1.getTime()/ 1000)
1332049834 

> var d2 = new Date( d1.getUTCFullYear(), d1.getUTCMonth(), d1.getUTCDate(), d1.getUTCHours(), d1.getUTCMinutes(), d1.getUTCSeconds() );
> d2.toUTCString();
"Sun, 18 Mar 2012 03:50:34 GMT" // four hours less than my local time, and two hours less than the original time - because my GMT+2 input was interpreted as GMT+0!
> Math.floor(d2.getTime()/ 1000)
1332042634

Należy również pamiętać, że getUTCDate()nie można tego zastąpić getUTCDay(). Dzieje się tak, ponieważ getUTCDate()zwraca dzień miesiąca ; podczas gdy getUTCDay()zwraca dzień tygodnia .

DCoder
źródło
1
1) Nie skonstruowałem daty ... Dodałem prototypową funkcję, która nad tym działała . 2) Słuszna uwaga, powinienem wykonać Math.floor / 1000 - ale nadal potrzebowałbym tej funkcji, aby mieć znacznik czasu UTC istniejącego obiektu daty ... prawda?
Merc
@Merc: 1) dzwonisz new Date(), który tworzy nową datę na podstawie danych wejściowych UTC, ale traktuje ją jako lokalną datę / godzinę. 2) Tak, powinieneś użyć Math.floor(this.getTime() / 1000)w tym przypadku.
DCoder
Odpowiadam tutaj, ponieważ muszę zaktualizować kod ... To ma mieć uniksowy znacznik czasu w UTC dla istniejącej daty: function () {return Math.floor (new Date (this.getUTCFullYear (), this.getUTCMonth (), this.getUTCDate (), this.getUTCHours (), this.getUTCMinutes (), this.getUTCSeconds ()) .getTime () / 1000); } Oznacza to, że mogę: var n = new Date (2008,10,10) ... ... n.getUTCTime (); (Będzie to INNE niż n.getUTCTime ())
Merc
1
Dzięki bracie Jego roboczy plik Math.floor ((new Date ()). GetTime () / 1000)
Manoj Patel,
51

Możesz to również zrobić za pomocą getTimezoneOffset i getTime,

x = new Date()
var UTCseconds = (x.getTime() + x.getTimezoneOffset()*60*1000)/1000;

console.log("UTCseconds", UTCseconds)

Shiplu Mokaddim
źródło
4
Dzięki, tego nigdzie nie można znaleźć w internecie!
Theofanis Pantelides
Przetestować następujące kody: var tt = new Date('Thu Jan 01 1970 08:00:00 GMT+0800 (China Standard Time)'); (tt.getTime() - tt.getTimezoneOffset()*60*1000)/1000. Wydaje się, że tt.getTime() - tt.getTimezoneOffset()jest to poprawne GMT+0800.
zangw
1
To jest lepszevar UTCseconds = (Math.floor(x.getTime()/1000) + x.getTimezoneOffset()*60)
StefansArya
Wygląda na to, że to nie działa tak, jak zostało napisane .. Wygląda na to, że musisz przejść w ciągu czasu do new Date()zawierającego strefę czasową ... która w
pewnym sensie
To jest po prostu źle, wartość przypisana do UTCseconds nie UTC sekund .. wartość czasu randkę za to przepraszamy, zmieniając go w jakikolwiek sposób oznacza to reprezentuje inny moment w czasie.
RobG
34

Najłatwiejszy sposób uzyskania czasu UTC w konwencjonalnym formacie jest następujący:

new Date().toISOString()
"2016-06-03T23:15:33.008Z"
Tahsin Turkoz
źródło
3
To jest poprawna odpowiedź. Wiele innych odpowiedzi podaje „uniwersalny ciąg czasu”, ale nie podaje aktualnego „uniwersalnego czasu koordynowanego”. Nie rozumiem, dlaczego wszystko tutaj jest takie skomplikowane.
gburton
Dziękuję @gburton. Doceń, że widzisz prostą drogę do prawdy. :)
Tahsin Turkoz
1
Używam tego wraz z „.split ('T') [0]” do łatwych porównań na podstawie daty RRRR-MM-DD.
Sean O
Miło mieć @SeanO
Tahsin Turkoz
Zapewnia ciąg czasu UTC, ale OP prosi o podanie znacznika czasu UTC (epoki)
Jordi Nebot
13

Właściwie myślę, że wartości Date w js są znacznie lepsze niż powiedzmy, że obiekty C # DateTime. Obiekty C # DateTime mają właściwość Kind, ale nie ma ścisłej podstawowej strefy czasowej jako takiej, a konwersje stref czasowych są trudne do śledzenia, jeśli konwertujesz między dwoma czasami innymi niż UTC i innymi czasami. W js wszystkie wartości Date mają bazową wartość UTC, która jest przekazywana i znana bez względu na wykonywane przez Ciebie konwersje offest lub strefy czasowej. Moją największą skargą dotyczącą obiektu Date jest liczba niezdefiniowanych zachowań, które twórcy przeglądarek zdecydowali się uwzględnić, co może zmylić ludzi atakujących daty w js metodą prób i błędów niż czytanie specyfikacji. Użycie czegoś takiego jak iso8601.js rozwiązuje to zróżnicowane zachowanie, definiując pojedynczą implementację obiektu Date.

Domyślnie specyfikacja mówi, że możesz tworzyć daty w rozszerzonym formacie daty ISO 8601, takim jak

var someDate = new Date('2010-12-12T12:00Z');

W ten sposób możesz wywnioskować dokładny czas UTC.

Gdy chcesz przekazać wartość Date z powrotem do serwera, do którego chcesz zadzwonić

someDate.toISOString();

lub jeśli wolisz pracować z milisekundowym znacznikiem czasu (liczbą milisekund od 1 stycznia 1970 UTC)

someDate.getTime();

ISO 8601 to standard. Nie możesz być zdezorientowany, co oznacza ciąg daty, jeśli dołączysz przesunięcie daty. Dla programisty oznacza to to, że nigdy nie musisz samodzielnie zajmować się konwersjami w czasie lokalnym . Lokalne wartości czasu istnieją wyłącznie dla korzyści użytkownika, a wartości dat są domyślnie wyświetlane w ich czasie lokalnym. Wszystkie operacje na czasie lokalnym pozwalają na wyświetlenie użytkownikowi czegoś sensownego i przekonwertowanie napisów na podstawie danych wprowadzonych przez użytkownika. Dobrą praktyką jest konwersja na UTC tak szybko, jak to możliwe, a obiekt js Date sprawia, że ​​jest to dość trywialne.

Z drugiej strony nie ma dużego zakresu na wymuszanie strefy czasowej lub lokalizacji dla klienta (o czym jestem świadomy), co może być denerwujące w przypadku ustawień specyficznych dla witryny, ale domyślam się, że powodem tego jest to, że jest to użytkownik konfiguracja, której nie należy dotykać.

Krótko mówiąc, powodem, dla którego nie ma natywnego wsparcia dla manipulacji strefą czasową, jest to, że po prostu nie chcesz tego robić.

Matt Esch
źródło
12

Zwykle nie musisz wykonywać zbyt wielu „manipulacji strefą czasową” po stronie klienta. Z reguły staram się przechowywać i pracować z datami UTC, w postaci ticksliczby milisekund od północy 1 stycznia 1970 r .”. To naprawdę upraszcza przechowywanie, sortowanie, obliczanie przesunięć, a przede wszystkim eliminuje ból głowy związany z dostosowywaniem „czasu letniego”. Oto mały kod JavaScript, którego używam.

Aby uzyskać aktualny czas UTC:

function getCurrentTimeUTC()
{
    //RETURN:
    //      = number of milliseconds between current UTC time and midnight of January 1, 1970
    var tmLoc = new Date();
    //The offset is in minutes -- convert it to ms
    return tmLoc.getTime() + tmLoc.getTimezoneOffset() * 60000;
}

Następnie generalnie potrzebujesz sformatować datę / godzinę dla użytkownika końcowego dla jego lokalnej strefy czasowej i formatu. Poniższe rozwiązuje wszystkie zawiłości formatów daty i czasu na komputerze klienckim:

function formatDateTimeFromTicks(nTicks)
{
    //'nTicks' = number of milliseconds since midnight of January 1, 1970
    //RETURN:
    //      = Formatted date/time
    return new Date(nTicks).toLocaleString();
}

function formatDateFromTicks(nTicks)
{
    //'nTicks' = number of milliseconds since midnight of January 1, 1970
    //RETURN:
    //      = Formatted date
    return new Date(nTicks).toLocaleDateString();
}

function formatTimeFromTicks(nTicks)
{
    //'nTicks' = number of milliseconds since midnight of January 1, 1970
    //RETURN:
    //      = Formatted time
    return new Date(nTicks).toLocaleTimeString();
}

A więc następujący przykład:

var ticks = getCurrentTimeUTC();  //Or get it from the server

var __s = "ticks=" + ticks + 
    ", DateTime=" + formatDateTimeFromTicks(ticks) +
    ", Date=" + formatDateFromTicks(ticks) +
    ", Time=" + formatTimeFromTicks(ticks);

document.write("<span>" + __s + "</span>");

Zwraca następujące dane (dla moich ustawień regionalnych w języku angielskim (USA)):

ticks = 1409103400661, DateTime = 8/26/2014 6:36:40 PM, Date = 8/26/2014, Time = 6: 36: 40 PM

ahmd0
źródło
1
Dodając getTimezoneOffsetwartość do swojej getCurrentTimeUTCfunkcji, w rzeczywistości zwracasz inny punkt w czasie. Wynik getTimejest już w UTC.
Matt Johnson-Pint
1
@MattJohnson: To jest nieprawidłowe. Wynikiem tmLoc.getTime()jest przesunięcie względem czasu lokalnego. Łatwo jest sprawdzić, czy masz dostęp do wszystkiego, co uruchamia JavaScript.
ahmd0
2
Przepraszam, ale to nieprawda. Zobacz odniesienie do MDN . Możesz to również zobaczyć w specyfikacji ECMAScript. W §15.9.3.3 opisanogetTime , co wskazuje na „wartość czasu” zdefiniowaną w §15.9.5 , czyli a PrimitiveValue, określoną w §15.9.3.3 wyraźnie jako UTC.
Matt Johnson-Pint
2
Cóż, skoro otrzymujesz tmLocprzez new Date(), to to samo. Strefa czasowa wpłynie na ciąg znaków wyjściowych tmLoc.toString()i podobnych elementów, ale nie wpłynie. tmLoc.getTime() To zawsze jest tylko liczba milisekund od północy 1970-01-01 czasu UTC.
Matt Johnson-Pint
1
@StefansArya://The offset is in minutes -- convert it to ms
ahmd0
5

Myślę, że to lepsze rozwiązanie

// UTC milliseconds
new Date(Date.now()+(new Date().getTimezoneOffset()*60000)).getTime()

// UTC seconds
new Date(Date.now()+(new Date().getTimezoneOffset()*60000)).getTime()/1000|0
koalex
źródło
Kolejna zła odpowiedź, getTime zwraca przesunięcie UTC, dodanie lokalnego przesunięcia strefy czasowej całkowicie go psuje. Przesunięcia ECMAScript wynoszą + ve dla zachodu i -ve dla wschodu, więc należy je odjąć od czasu UTC, aby uzyskać wartość lokalną. Ale ponieważ wartość czasu to UTC na początku, dodanie go zasadniczo przesuwa go od UTC w kierunku przeciwnym do lokalnego przesunięcia.
RobG
4

Jeśli chcesz mieć jedną linijkę , UTC Unix Timestamp można utworzyć w JavaScript jako:

var currentUnixTimestap = ~~(+new Date() / 1000);

Uwzględni to strefę czasową systemu. Jest to zasadniczo czas, który upłynął w sekundach od epoki.

Jak to działa:

  • Tworzenie obiektu Date: new Date().
  • Konwertuj na znacznik czasu, dodając unary +przed utworzeniem obiektu, aby przekonwertować go na timestamp integer. : +new Date().
  • Zamień milisekundy na sekundy: +new Date() / 1000
  • Użyj podwójnych tyld, aby zaokrąglić wartość do liczby całkowitej. :~~(+new Date())
Kushal Likhi
źródło
7
to jest tilde, nie tilda(sic!). Niestety nie pozwala mi to usunąć literówki, muszę wprowadzić co najmniej 6 edycji znaków. Smooth, Stackexchange, smooth
Fred
3
Nie używaj tego . Przy aktualnej specyfikacji ecma operacje bitowe (takie jak tylda - nie bitowe) obsługują wartości całkowite ze znakiem 32-bitowe. Oznacza to, że ta magia tyldy nie będzie działać po 19 stycznia 2038 r., Gdy wartość znacznika czasu przekroczy maksymalną wartość 32-bitowej liczby całkowitej ze znakiem. jsfiddle.net/phb20ymb
Sharky
3

Chcę wyjaśnić, że nowa Date (). GetTime () w rzeczywistości zwraca wartość UTC, więc jest to naprawdę pomocny sposób przechowywania dat i zarządzania nimi w sposób niezależny od zlokalizowanych czasów.

Innymi słowy, nie przejmuj się wszystkimi funkcjami javascript UTC. Zamiast tego po prostu użyj Date.getTime ().

Więcej informacji na temat wyjaśnienia znajduje się tutaj: Jeśli javascript "(new Date ()). GetTime ()" jest uruchamiany z 2 różnych stref czasowych.

Stan Lin
źródło
3

Używam następujących:

Date.prototype.getUTCTime = function(){ 
  return this.getTime()-(this.getTimezoneOffset()*60000); 
};

Po zdefiniowaniu tej metody możesz:

var utcTime = new Date().getUTCTime();
jlbofh
źródło
Najczystsze rozwiązanie. DZIĘKI!
lawina 1
Ale to nie jest czyste rozwiązanie do wysyłania dat, ponieważ znaczniki czasu są zawsze UTC. Najlepszym rozwiązaniem dla mnie podczas wysyłania dat jest użycie reprezentacji w postaci ciągu, takiego jak „dd / MM / rrrr HH: mm: ss”, a następnie przeanalizowanie go po stronie serwera z domyślną strefą czasową serwera, aby uzyskać znacznik czasu UTC lub cokolwiek innego. Zobacz tę odpowiedź
jlbofh
2
parsowanie łańcucha - nazywasz to czystym? meh
avalanche1
Upewnij się, że istnieją metody generowania daty w formacie ciągów zgodnie ze specyfikacjami ISO. Metoda to toISOString (). Możesz go czysto przeanalizować w Javie, używając czegoś takiego:DateTime dt = new DateTime ("2018-07-15T02:36:00+02:00");
jlbofh
Kolejna zła odpowiedź this.getTime()zwraca przesunięcie czasu UTC, odejmując przesunięcie lokalnej strefy czasowej, czyniąc je lokalnym, a nie UTC, więc getUTCTime zwraca przesunięcie lokalne, a nie UTC.
RobG
2

Jestem zdumiony, jak skomplikowane stało się to pytanie.

Wszystkie są identyczne, a ich wartości całkowite all === EPOCH time: D

console.log((new Date()).getTime() / 1000, new Date().valueOf() / 1000, (new Date() - new Date().getTimezoneOffset() * 60 * 1000) / 1000);

Nie wierz mi, sprawdź: http://www.epochconverter.com/

fliptopbox
źródło
2

Ponieważ new Date().toUTCString()zwraca ciąg, taki jak "Wed, 11 Oct 2017 09:24:41 GMT"możesz wyciąć ostatnie 3 znaki i przekazać pokrojony ciąg do new Date():

new Date()
// Wed Oct 11 2017 11:34:33 GMT+0200 (CEST)

new Date(new Date().toUTCString().slice(0, -3))
// Wed Oct 11 2017 09:34:33 GMT+0200 (CEST)
Maurice Wipf
źródło
1

EDYCJA: Poniższy kod NIE działa. Zawsze zakładałem, że new Date (). GetTime () zwróciło liczbę sekund od 1 stycznia 1970 roku W BIEŻĄCEJ STREFIE CZASOWEJ. Tak nie jest: getTime () zwraca liczbę sekund w UTC. Tak więc poniższy kod powoduje rażące przeregulowanie. Dziękuję wszystkim!]

Przede wszystkim dziękuję za fantastyczne spostrzeżenia. Wydaje mi się, że moje pytanie miało zły tytuł… powinno brzmieć „Pobierz UTC Unix Timestamp dla istniejącej daty”.

Tak więc, jeśli mam obiekt daty:

var d = new Date(2009,01,31)

Szukałem funkcji, która powie mi „UTC Unix Timestamp”.

Ta funkcja wydaje się być prawdziwą sztuczką:

Date.prototype.getUTCUnixTime =  function (){
  return Math.floor( new Date(
    this.getUTCFullYear(),
    this.getUTCMonth(),
    this.getUTCDate(),
    this.getUTCHours(),
    this.getUTCMinutes(), 
    this.getUTCSeconds()
  ).getTime() / 1000); 
}

Zauważ, że to działa na „to”. Oznacza to, że mogę:

var n = new Date(2008,10,10)
...
...

n.getUTCUnixTime();

I uzyskaj liczbę sekund od 1 stycznia 1970 w czasie uniksowym. Dobrze?

To trochę szalone, dla mnie, że JavaScript przechowuje wszystko w czasie UTC, ale potem, aby uzyskać tę liczbę, muszę utworzyć nowy obiekt Date przekazujący poszczególne metody pobierające UTC, a następnie wywołać w tym celu getTime () ...

Merc.

Merc
źródło
1
czy widziałeś aktualizację @ DCodera w jego odpowiedzi? Twoja metoda getUTCUnixTimestaje się zły czas i JavaScript ma zapewnić prosty sposób uzyskać uniksowego znacznika czasu z pomocą Dateobiektu - przy użyciu getTimemetody. Zobacz wszystkie inne odpowiedzi.
Anurag
1
Ugh masz rację, właśnie je widziałem. (Walenie głową w ścianę)
Merc
1

Myślę, że tego oczekujesz ...

var currTimestamp = Date.now(), //1482905176396
    utcDateString = (new Date(currTimestamp)).toUTCString(); //"Wed, 28 Dec 2016 06:06:50 GMT"

Teraz,

new Date(utcDateString).getTime(); //This will give you UTC Timestamp in JavaScript
Kapilrc
źródło
0

Kiedy to zrobisz

new Date(dateString).getTime() / 1000

To już jest znacznik czasu UTC

   const getUnixTimeUtc = (dateString = new Date()) => Math.round(new Date(dateString).getTime() / 1000)

Testowałem na https://www.unixtimestamp.com/index.php

fiddlest
źródło
0

Korzystanie z day.js.

W wyszukiwarce:

dayjs.extend(dayjs_plugin_utc)
console.log(dayjs.utc().unix())
<script src="https://cdn.jsdelivr.net/npm/dayjs@latest/dayjs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dayjs@latest/plugin/utc.js"></script>

W node.js:

import dayjs from 'dayjs'
dayjs.extend(require('dayjs/plugin/utc'))
console.log(dayjs.utc().unix())

Otrzymujesz znacznik czasu UTC unix bez milisekund.

Iljicz
źródło
-2

Spowoduje to zwrócenie sygnatury czasowej w UTC:

var utc = new Date(new Date().toUTCString()).getTime();

Yash Pandya
źródło
2
To nie zwraca czasu w UTC: new Date(new Date().toUTCString())podaje Wed 04 Oct 2017 07:20:14 GMT + 0200 (GMT + 02:00)
Bas van Dijk