Sformatuj datę w określonej strefie czasowej

177

Używam Moment.js do analizowania i formatowania dat w mojej aplikacji internetowej. Jako część obiektu JSON mój serwer zaplecza wysyła daty jako liczbę milisekund od epoki UTC (przesunięcie Unix).

Analizowanie dat w określonej strefie czasowej jest łatwe - po prostu dodaj identyfikator strefy czasowej RFC 822 na końcu ciągu przed analizowaniem:

// response varies according to your timezone
const m1 = moment('3/11/2012 13:00').utc().format("MM/DD HH:mm")

// problem solved, always "03/11 17:00"
const m2 = moment('3/11/2012 13:00 -0400').utc().format("MM/DD HH:mm")

console.log({ m1, m2 })
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

Ale jak sformatować datę w określonej strefie czasowej ?

Chcę spójnych wyników niezależnie od aktualnego czasu przeglądarki, ale nie chcę wyświetlać dat w UTC.

cicha mięta
źródło
2
Moment jeszcze tego nie obsługuje, ale pracują nad tym. github.com/timrwood/moment/pull/671
Ben
5
To powinno po prostu działać. Jeśli przekażesz momentowi ciąg czasu zawierający żądane przesunięcie, powinien on zachować to przesunięcie i wyświetlać czas lokalny zgodnie z podanym, zamiast automatycznie dostosowywać się do czasu lokalnego przeglądarki. Gdybym chciał, żeby dostosował się do czasu lokalnego przeglądarki, dałbym mu czas UTC zamiast jawnie nadawać mu przesunięcie do użycia. To znaczy ... daję temu wyraźne przesunięcie, dlaczego w zasadzie to pochłania i wykonuje własną konwersję do offsetu przeglądarek. Okropny projekt.
Triynko
Offsety @Triynko podlegają oszczędzaniu światła dziennego, więc nie zawsze działają zgodnie z oczekiwaniami.
pinkpanther
1
Coś z tym związanego, chcę wydrukować czas w określonym formacie, np. 15 marca 2018, ale nie mogę znaleźć ciągu formatu, aby to zrobić. Generyczny DD MMM, YYYYnie działa, kiedy go używam moment.tz("2018-02-15T14:20:00.000+0530", "Asia/Bangkok").format("DD MMM, YYYY"). Czy ktoś może wskazać mi w dokumentacji, gdzie mogę znaleźć wszystkie klucze do formatowania czasu podczas korzystania z tego interfejsu API.
pRmdk
@PramodKumar Co się stało? To daje "15 Feb, 2018". Czy chodziło Ci o użycie ciągu formatu DD MMMM, YYYYdo pobrania "15 February, 2018"?
quietmint

Odpowiedzi:

248

Jak wskazano w odpowiedzi Manto , .utcOffset()jest to preferowana metoda od momentu 2.9.0. Ta funkcja używa rzeczywistego przesunięcia względem czasu UTC, a nie przesunięcia wstecznego (np. -240 dla Nowego Jorku podczas czasu letniego). Odsuwane ciągi, takie jak „+0400”, działają tak samo jak poprzednio:

// always "2013-05-23 00:55"
moment(1369266934311).utcOffset(60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).utcOffset('+0100').format('YYYY-MM-DD HH:mm')

Starszy .zone()jako ustawiacz został wycofany w Moment.js 2.9.0. Zaakceptował ciąg zawierający identyfikator strefy czasowej (np. „-0400” lub „-04: 00” przez -4 godziny) lub liczbę reprezentującą minuty po czasie UTC (np. 240 dla Nowego Jorku podczas czasu letniego).

// always "2013-05-23 00:55"
moment(1369266934311).zone(-60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).zone('+0100').format('YYYY-MM-DD HH:mm')

Aby pracować z nazwanymi strefami czasowymi zamiast przesunięć numerycznych, uwzględnij strefę czasową momentu i użyj .tz()zamiast tego:

// determines the correct offset for America/Phoenix at the given moment
// always "2013-05-22 16:55"
moment(1369266934311).tz('America/Phoenix').format('YYYY-MM-DD HH:mm')
cicha mięta
źródło
Miałem z tym problem z powodu błędu „TypeError: Object 240 has no method 'format'”. Zdałem sobie sprawę, że strefa jest dostępna tylko jako setter w wersji 2.1.0 i nowszych Moment.js (i byłem na starszej wersji). Dzięki!
Melinda Weathers
5
@ebi Domyślnie używa już strefy czasowej przeglądarki. Aby uzyskać dostęp do przesunięcia strefy czasowej przeglądarki, użyj .zone()jako metody pobierającej, która zwraca minuty z UTC (np. Zwraca 300 dla Nowego Jorku w standardowym czasie).
quietmint
1
@EricCope Nie, niezupełnie. Możesz jednak użyć, .tz("America/Phoenix")jeśli dołączysz również momentjs.com/timezone . Zaktualizowałem odpowiedź na przykładzie.
quietmint
1
Należy pamiętać, że przesunięcie nie będzie działać zgodnie z oczekiwaniami, jeśli strefa czasowa ma różne przesunięcia ze względu na czas letni.
pinkpanther
1
Czy .utcOffset () będzie automatycznie zarządzać czasem letnim? tak jak kiedy ustawię UTC +1 CET zimą, czy obstawiam UTC +2 CEST w czasie letnim? Bo to czyni go użytecznym lub nie!
haemse
61

Użyj chwilowej strefy czasowej

moment(date).tz('Europe/Berlin').format(format)

Zanim uzyskasz dostęp do określonej strefy czasowej, musisz ją załadować w ten sposób (lub użyć alternatywnych metod opisanych tutaj )

moment.tz.add('Europe/Berlin|CET CEST CEMT|-10 -20 -30')
Philip Nuzhnyy
źródło
Nie sądzę, aby moment tz był dostępny, kiedy zadano pytanie, ale myślę, że może to być właściwy sposób. Obecnie pracuję nad podobnym problemem ze wszystkimi sygnaturami czasowymi przechowywanymi jako UTC w MySQL, ale do wyświetlenia w określonej strefie zależnej od konfiguracji użytkownika, a nie strefy czasowej klienta.
nickdnk
47

Kilka odpowiedzi już wspomina, że ​​strefa czasowa w chwili jest sposobem na przejście z nazwaną strefą czasową. Chcę tylko wyjaśnić coś o tej bibliotece, co było dla mnie dość zagmatwane. Istnieje różnica między tymi dwoma stwierdzeniami:

moment.tz(date, format, timezone)

moment(date, format).tz(timezone)

Zakładając, że strefa czasowa nie jest określona w terminie podanym w:

Pierwszy kod przyjmuje datę i zakłada, że ​​strefa czasowa jest tą, która została przekazana. Drugi przyjmie datę, przyjmie strefę czasową z przeglądarki, a następnie zmieni godzinę i strefę czasową zgodnie z podaną strefą czasową.

Przykład:

moment.tz('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss', 'UTC').format() // "2018-07-17T19:00:00Z"

moment('2018-07-17 19:00:00', 'YYYY-MM-DD HH:mm:ss').tz('UTC').format() // "2018-07-18T00:00:00Z"

Moja strefa czasowa to +5 od utc. Więc w pierwszym przypadku nie zmienia się i ustawia datę i godzinę tak, aby mieć strefę czasową utc.

W drugim przypadku zakłada, że ​​przekazana data to -5, a następnie zamienia ją na UTC i dlatego wypluwa datę „2018-07-18T00: 00: 00Z”

UWAGA: parametr format jest naprawdę ważny. Jeśli zostanie pominięty moment, może wrócić do klasy Date, co może powodować nieprzewidywalne zachowania


Zakładając, że strefa czasowa jest określona w terminie podanym w:

W tym przypadku oboje zachowują się jednakowo


Chociaż teraz rozumiem, dlaczego to działa, pomyślałem, że to dość myląca funkcja i warta wyjaśnienia.

Nicola Pedretti
źródło
1
moment (...). tz nie jest funkcją
K - Toksyczność w SO rośnie.
5
Czy zainstalowałeś strefę czasową momentu?
Nicola Pedretti
czy istnieje sposób na odzyskanie przeanalizowanej i przekonwertowanej chwili bez formatowania? Na przykład, jeśli chcę sformatować na różne sposoby bez ponownego analizowania.
jEremyB
Dziękuję za wyjaśnienie - miałem problem z ustawieniem innej strefy czasowej niż strefa czasowa przeglądarki użytkownika i to był właśnie problem.
Robin Schaaf
20

.zone () został uznany za przestarzały i zamiast tego należy użyć utcOffset:

// for a timezone that is +7 UTC hours
moment(1369266934311).utcOffset(420).format('YYYY-MM-DD HH:mm')
Manto
źródło
8

Miałem ten sam problem z Moment.js. Zainstalowałem strefę czasową momentu, ale problem nie został rozwiązany. Następnie zrobiłem to, co tutaj jest ujawnione, ustawiłem strefę czasową i działa jak urok:

moment(new Date({your_date})).zone("+08:00")

Wielkie dzięki!

facundofarias
źródło
16
Nie powinieneś używać new Date()konstruktora. Moment zapewnia wszystko, czego kiedykolwiek potrzebujesz do przeanalizowania dat. Zobacz parsowanie dokumentów.
quietmint
Tak, ale jeśli tego nie zrobię, otrzymuję ostrzeżenie od Moment, że jest to przestarzałe
facundofarias
7
Ostrzeżenie oznacza, że ​​Moment wewnętrznie cofa się dokładnie do tego, co robisz (używając new Date()wewnętrznie), ale jest to niespójne w różnych przeglądarkach . Zamiast tego jako drugi argument należy użyć oczekiwanego formatu. Przykład: moment("12-25-1995", "MM-DD-YYYY").
quietmint
4

Właśnie to przyszło, a ponieważ miałem ten sam problem, po prostu opublikowałem wyniki, które wymyśliłem

podczas analizowania można zaktualizować przesunięcie (tj. analizuję dane (1.1.2014) i chcę mieć tylko datę 1 stycznia 2014 r. W GMT + 1 otrzymam 31.12.2013. Więc najpierw wyrównuję wartość.

moment(moment.utc('1.1.2014').format());

Cóż, przydała mi się obsługa w różnych strefach czasowych

b

Bard Rotzer
źródło
-7

Możesz spróbować tego,

Tutaj możesz uzyskać datę w oparciu o strefę czasową klienta (przeglądarkę).

moment(new Date().getTime()).zone(new Date().toString().match(/([-\+][0-9]+)\s/)[1]).format('YYYY-MM-DD HH:mm:ss')

Wyrażenie regularne zasadniczo pobiera wartość przesunięcia.

Twoje zdrowie!!

K. Karthik
źródło
Zazwyczaj chwila daje wszystko, czego potrzebujesz. Nigdy nie musisz dopasowywać niczego niestandardowego.
Mahesh Samudra