Przeanalizuj datę bez javascript strefy czasowej


147

Chcę przeanalizować datę bez strefy czasowej w JavaScript. Próbowałem:

new Date(Date.parse("2005-07-08T00:00:00+0000"));

Zwroty pią, 08 lipca 2005, 02:00:00 GMT + 0200 (środkowoeuropejski czas letni)

new Date(Date.parse("2005-07-08 00:00:00 GMT+0000"));

Zwraca ten sam wynik

new Date(Date.parse("2005-07-08 00:00:00 GMT-0000"));

Zwraca ten sam wynik

Chcę przeanalizować czas:

  1. Bez strefy czasowej.

  2. Bez wywoływania konstruktora Date.UTC lub new Date (rok, miesiąc, dzień).

  3. Proste przekazanie ciągu znaków do konstruktora Date (bez podejścia prototypowego).

  4. Nie mam Dateprzedmiotu produktu String.


3
Możesz po prostu pominąć Date.parsebtw i bezpośrednio przekazać łańcuch do Datekonstruktora.
Bergi,

1
Nie jestem pewien, dlaczego tego potrzebujesz, ale jestem prawie pewien, że Date zawsze ma lokalną strefę czasową użytkownika. Jeśli chcesz, aby Twój JavaScript działał z innymi strefami czasowymi
HMR

1
Niestety musiałem skopiować Dateobiekt, aby uzyskać prawidłowy obiekt do porównania dat w MongoDB:new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate())
Athlan

Jeśli chcesz przeanalizować datę bez godziny, musisz określić, jaką strefę czasową chcesz przyjąć, ponieważ „2005-07-08” oznacza różne rzeczy w różnych strefach czasowych. Od maja 2020 r. Dokumentacja MDN odradza jakiekolwiek wbudowane funkcje analizowania daty z powodu różnic w implementacji. Jednak użycie Date.parse („2005-07-08”) prawdopodobnie zwróci godzinę 00:00 UTC. z drugiej strony, analiza daty-fns zwróci 00:00 czasu lokalnego podczas analizowania tego samego ciągu daty
Andy

Odpowiedzi:


106

Data jest przetwarzana poprawnie, to po prostu toString konwertuje ją na lokalną strefę czasową:

let s = "2005-07-08T11:22:33+0000";
let d = new Date(Date.parse(s));

// this logs for me 
// "Fri Jul 08 2005 13:22:33 GMT+0200 (Central European Summer Time)" 
// and something else for you

console.log(d.toString()) 

// this logs
// Fri, 08 Jul 2005 11:22:33 GMT
// for everyone

console.log(d.toUTCString())

Obiekt JavaScript Date to znaczniki czasu - zawierają one tylko liczbę milisekund od epoki. W obiekcie Date nie ma informacji o strefie czasowej. To, która data kalendarzowa (dzień, minuty, sekundy) reprezentuje ten znacznik czasu, jest kwestią interpretacji (jedna z to...Stringmetod).

Powyższy przykład pokazuje, że data jest przetwarzana poprawnie - to znaczy, że faktycznie zawiera liczbę milisekund odpowiadającą „2005-07-08T11: 22: 33” w GMT.


4
Niestety muszę stworzyć obiekt Date, a nie String.
Athlan,

@Athlan: dodano kilka wyjaśnień.
georg

1
Sprawdziłem to. I minęło przeanalizowane datę do MongoDB zapytania new Date(Date.parse("2005-07-08T11:22:33+0000")), a data kopiowane przez konstruktora: new Date(dateStart.getFullYear(), dateStart.getMonth(), dateStart.getDate()). Oba rozwiązania, różne wyniki, drugie poprawne! Twoja odpowiedź była przydatna, właśnie wspomniano o niej w hunlock.com/blogs/Javascript_Dates-The_Complete_Reference . W górę.
Athlan

Udało mi się idealnie - .toUTCString () był biletem, który podał mi prawidłowy czas z pierwotnego podanego ciągu. tj. nowa data („2016-08-22T19: 45: 00.0000000”). toUTCString ()
Michael Giovanni Pumo

38
Źródłem wszelkiego zła w datach i godzinach JavaScript jest twoje pierwsze zdanie ... To tylko ciąg, który KONWERTUJE to do twojej lokalnej strefy czasowej ... Gdzie jest w tym pojedyncza odpowiedzialność? toString powinna po prostu określić wynik i nie konwertować go. Jeśli chcę przekonwertować datę, powinienem skorzystać z innych metod.
kotwica

109

Mam ten sam problem. Otrzymuję datę jako ciąg, na przykład: „2016-08-25T00: 00: 00”, ale potrzebuję obiektu Date z poprawnym czasem. Aby przekonwertować String na obiekt, używam getTimezoneOffset:

var date = new Date('2016-08-25T00:00:00')
var userTimezoneOffset = date.getTimezoneOffset() * 60000;
new Date(date.getTime() - userTimezoneOffset);

getTimezoneOffset()zwróci wartość ujemną lub dodatnią eteru. Należy to odjąć, aby działało w każdym miejscu na świecie.


6
Mam ten sam problem i uznałem to za pomocne. Jednak odkryłem, że nie obsługuje to przesunięć stref czasowych ze względu na czas letni. Przykład: Jestem w PST, więc moje obecne przesunięcie (w marcu) od GMT to -8: 00, ale w maju będzie to -7: 00. Moim rozwiązaniem było obliczenievar userTimezoneOffset = date.getTimezoneOffset()*60000;
mmh02

3
O ile nie jestem kompletnym idiotą, to faktycznie zwraca zły czas. getTimezoneOffset()zwraca liczbę minut w przeciwnym kierunku niż myślisz - moja strefa czasowa to UTC-4 w tej chwili, ale getTimezoneOffset()zwraca dodatnie 240. Dlatego userTimezoneOffsetnależy ją odejmować date.getTime(), a nie dodawać do niej.
vaindil

1
Zgadzam się z @vaindil, powinieneś odjąć. rozwiązanie wakwa działa tylko wtedy, gdy jesteś po właściwej stronie Greenwich. Wakwas powinien to poprawić.
Janne Harju

1
Ach! przemówił za wcześnie. Nie działa w większości stref czasowych. Mogę potwierdzić, że zwraca nieprawidłową datę podczas kompensowania czasów AEST i CEST z czasem GMT.
saran3h

1
@vaindil teraz wynik jest taki sam, jak new Date('2016-08-25T00:00:00Z')myślę, że chodziło o manipulowanie new Date('2016-08-25T00:00:00Z')tak, aby czas lokalny był wyświetlany z czasem 0:00, ale ten kod został pominiętyZ
barbsan

14

Natknąłem się na ten sam problem, a potem przypomniałem sobie coś dziwnego na temat starszego projektu, nad którym pracowałem, i sposobu, w jaki rozwiązali ten problem. Wtedy tego nie rozumiałem i nie obchodziło mnie to, dopóki sam nie napotkałem problemu

var date = '2014-01-02T00:00:00.000Z'
date = date.substring(0,10).split('-')
date = date[1] + '-' + date[2] + '-' + date[0]

new Date(date) #Thu Jan 02 2014 00:00:00 GMT-0600

Z jakiegoś powodu podanie daty jako „01 -02-2014” ustawia strefę czasową na zero i ignoruje strefę czasową użytkownika. Może to być przypadek w klasie Date, ale istniał jakiś czas temu i istnieje dzisiaj. Wydaje się, że działa w różnych przeglądarkach. Wypróbuj sam.

Ten kod jest wdrażany w globalnym projekcie, w którym strefy czasowe mają duże znaczenie, ale osoba przeglądająca datę nie przejmowała się dokładnym momentem jej wprowadzenia.


Myślę, że jest to zamierzone, ponieważ „Z” oznacza UTC, który JS następnie konwertuje, ale biorąc pod uwagę brak strefy czasowej, nie może jej przekonwertować, więc zasadniczo przyjmuje strefę czasową użytkownika. Chciałbym jednak uzyskać jakieś potwierdzenie lub lepsze wyjaśnienie.
dlsso

7
Niewłaściwe zachowanie jest spowodowane myślnikami. Chrome, Firefox i IE11 wszystko interpretować 2014/5/31i 2014/05/31jak Sat May 31 2014 00:00:00 GMT-0600 (Mountain Daylight Time (MDT) `jest mój bieżącej strefy czasowej). Z myślnikami ... wszystkie przeglądarki interpretują 2014-05-31jako piątek 30 maja 2014 18:00:00 GMT-0600 (górski czas letni). Co dziwne, 2014-5-31Chrome zwraca sobotę, Firefox zwraca piątek, a IE11 informuje, że data jest nieprawidłowa. Wygląda na to, date.replace('-','/')że może załatwić sprawę.
atheaos

6

Sam Dateobiekt i tak będzie zawierał strefę czasową, a zwrócony wynik jest efektem konwersji go na łańcuch w domyślny sposób. Oznacza to, że nie można utworzyć obiektu daty bez strefy czasowej. Ale to, co możesz zrobić, to naśladować zachowanie Dateobiektu, tworząc własny. Lepiej jednak przekazać to bibliotekom takim jak moment.js .


2
Niestety muszę stworzyć obiekt Date, a nie String.
Athlan,

3

proste rozwiązanie

const handler1 = {
  construct(target, args) {
    let newDate = new target(...args);
    var tzDifference = newDate.getTimezoneOffset();
    return new target(newDate.getTime() + tzDifference * 60 * 1000);
  }
};

Date = new Proxy(Date, handler1);

3

Data w javascript jest po prostu prosta w środku. tak więc dane data-czas są przechowywane w epoce unix UTC (milisekundy lub ms).

Jeśli chcesz mieć „stały” czas, który nie zmienia się w żadnej strefie czasowej, w której się znajdujesz, możesz dostosować czas UTC, aby pasował do Twojej bieżącej lokalnej strefy czasowej i zapisać go. A kiedy go odzyskasz, niezależnie od Twojej lokalnej strefy czasowej, w której się znajdujesz, pokaże skorygowany czas UTC na podstawie tego, który go zapisał, i doda lokalne przesunięcie strefy czasowej, aby uzyskać „stały” czas.

Aby zapisać datę (w ms)

toUTC(datetime) {
  const myDate = (typeof datetime === 'number')
    ? new Date(datetime)
    : datetime;

  if (!myDate || (typeof myDate.getTime !== 'function')) {
    return 0;
  }

  const getUTC = myDate.getTime();
  const offset = myDate.getTimezoneOffset() * 60000; // It's in minutes so convert to ms
  return getUTC - offset; // UTC - OFFSET
}

Aby pobrać / pokazać datę (w ms)

fromUTC(datetime) {
  const myDate = (typeof datetime === 'number')
    ? new Date(datetime)
    : datetime;

  if (!myDate || (typeof myDate.getTime !== 'function')) {
    return 0;
  }

  const getUTC = myDate.getTime();
  const offset = myDate.getTimezoneOffset() * 60000; // It's in minutes so convert to ms
  return getUTC + offset; // UTC + OFFSET
}

Następnie możesz:

const saveTime = new Date(toUTC(Date.parse("2005-07-08T00:00:00+0000")));
// SEND TO DB....

// FROM DB...
const showTime = new Date(fromUTC(saveTime));

2

Możesz użyć tego kodu

var stringDate = "2005-07-08T00:00:00+0000";
var dTimezone = new Date();
var offset = dTimezone.getTimezoneOffset() / 60;
var date = new Date(Date.parse(stringDate));
date.setHours(date.getHours() + offset);

1
Nie wierzę, że to bierze pod uwagę czas letni
Daniel Thompson

2

Ponieważ jest to naprawdę problem z formatowaniem podczas wyświetlania daty (np. Wyświetla się w czasie lokalnym), lubię używać nowego (ish) obiektu Intl.DateTimeFormat do formatowania, ponieważ jest bardziej wyraźny i zapewnia więcej opcji wyjściowych:

const dateOptions = { timeZone: 'UTC', month: 'long', day: 'numeric', year: 'numeric' };

const dateFormatter = new Intl.DateTimeFormat('en-US', dateOptions);
const dateAsFormattedString = dateFormatter.format(new Date('2019-06-01T00:00:00.000+00:00'));

console.log(dateAsFormattedString) // "June 1, 2019"

Jak pokazano, ustawienie TimeZone na „UTC” nie spowoduje wykonania lokalnych konwersji. Jako bonus umożliwia również tworzenie bardziej dopracowanych wyników. Więcej o obiekcie Intl.DateTimeFormat można przeczytać w witrynie Mozilla - Intl.DateTimeFormat .

Edytować:

Tę samą funkcjonalność można osiągnąć bez tworzenia nowego Intl.DateTimeFormatobiektu. Po prostu przekaż opcje lokalizacji i daty bezpośrednio do toLocaleDateString()funkcji.

const dateOptions = { timeZone: 'UTC', month: 'long', day: 'numeric', year: 'numeric' };
const myDate = new Date('2019-06-01T00:00:00.000+00:00');
today.toLocaleDateString('en-US', dateOptions); // "June 1, 2019"

1

Tylko ogólna notatka. sposób na zachowanie elastyczności.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

Możemy użyć getMinutes (), ale zwraca ona tylko jedną liczbę przez pierwsze 9 minut.

let epoch = new Date() // Or any unix timestamp

let za = new Date(epoch),
    zaR = za.getUTCFullYear(),
    zaMth = za.getUTCMonth(),
    zaDs = za.getUTCDate(),
    zaTm = za.toTimeString().substr(0,5);

console.log(zaR +"-" + zaMth + "-" + zaDs, zaTm)

Date.prototype.getDate()
    Returns the day of the month (1-31) for the specified date according to local time.
Date.prototype.getDay()
    Returns the day of the week (0-6) for the specified date according to local time.
Date.prototype.getFullYear()
    Returns the year (4 digits for 4-digit years) of the specified date according to local time.
Date.prototype.getHours()
    Returns the hour (0-23) in the specified date according to local time.
Date.prototype.getMilliseconds()
    Returns the milliseconds (0-999) in the specified date according to local time.
Date.prototype.getMinutes()
    Returns the minutes (0-59) in the specified date according to local time.
Date.prototype.getMonth()
    Returns the month (0-11) in the specified date according to local time.
Date.prototype.getSeconds()
    Returns the seconds (0-59) in the specified date according to local time.
Date.prototype.getTime()
    Returns the numeric value of the specified date as the number of milliseconds since January 1, 1970, 00:00:00 UTC (negative for prior times).
Date.prototype.getTimezoneOffset()
    Returns the time-zone offset in minutes for the current locale.
Date.prototype.getUTCDate()
    Returns the day (date) of the month (1-31) in the specified date according to universal time.
Date.prototype.getUTCDay()
    Returns the day of the week (0-6) in the specified date according to universal time.
Date.prototype.getUTCFullYear()
    Returns the year (4 digits for 4-digit years) in the specified date according to universal time.
Date.prototype.getUTCHours()
    Returns the hours (0-23) in the specified date according to universal time.
Date.prototype.getUTCMilliseconds()
    Returns the milliseconds (0-999) in the specified date according to universal time.
Date.prototype.getUTCMinutes()
    Returns the minutes (0-59) in the specified date according to universal time.
Date.prototype.getUTCMonth()
    Returns the month (0-11) in the specified date according to universal time.
Date.prototype.getUTCSeconds()
    Returns the seconds (0-59) in the specified date according to universal time.
Date.prototype.getYear()
    Returns the year (usually 2-3 digits) in the specified date according to local time. Use getFullYear() instead. 

-1

(new Date().toString()).replace(/ \w+-\d+ \(.*\)$/,"")

To da wynik: wtorek 10 lipca 2018 19:07:11

(new Date("2005-07-08T11:22:33+0000").toString()).replace(/ \w+-\d+ \(.*\)$/,"")

To da wynik: piątek 08 lipca 2005 04:22:33

Uwaga: Zwrócony czas będzie zależał od lokalnej strefy czasowej


-1

To jest rozwiązanie, które wymyśliłem na ten problem, które działa dla mnie.


użyta biblioteka: momentjs ze zwykłą klasą Date w javascript.

Krok 1. Konwertuj obiekt Date na moment (PS: moment zachowuje oryginalną datę i czas, o ile toDate()metoda nie jest wywoływana):

const dateMoment = moment("2005-07-08T11:22:33+0000");

Krok 2. Wyodrębnij hoursi minuteswartości z utworzonego wcześniej obiektu momentu:

  const hours = dateMoment.hours();
  const mins = dateMoment.minutes();

Krok 3. Konwertuj moment na datę (PS: spowoduje to zmianę oryginalnej daty w oparciu o strefę czasową przeglądarki / komputera, ale nie martw się i przeczytaj krok 4.):

  const dateObj = dateMoment.toDate();

Krok 4. Ręcznie ustaw godziny i minuty wyodrębnione w kroku 2.

  dateObj.setHours(hours);
  dateObj.setMinutes(mins);

Krok 5. dateObjpokaże teraz oryginalną datę bez różnicy w strefie czasowej. Nawet zmiany czasu letniego nie będą miały żadnego wpływu na obiekt daty, ponieważ ręcznie ustawiamy oryginalne godziny i minuty.

Mam nadzieję że to pomoże.


-7

Istnieją pewne nieodłączne problemy z analizowaniem dat, które niestety nie są domyślnie rozwiązane.

-Daty czytelne dla człowieka mają ukrytą strefę czasową
-Istnieje wiele powszechnie używanych formatów dat w Internecie, które są niejednoznaczne

Aby rozwiązać te problemy w łatwy i czysty sposób, potrzebna byłaby taka funkcja:

>parse(whateverDateTimeString,expectedDatePattern,timezone)
"unix time in milliseconds"

Szukałem tego, ale nic takiego nie znalazłem!

Więc stworzyłem: https://github.com/zsoltszabo/timestamp-grabber

Cieszyć się!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.