L'oggetto data Javascript è sempre un giorno libero?


238

Nella mia app Java Script ho la data memorizzata in un formato simile al seguente:

2011-09-24

Ora, quando provo a utilizzare il valore sopra per creare un nuovo oggetto Date (in modo da poter recuperare la data in un formato diverso), la data torna sempre un giorno libero. Vedi sotto:

var doo = new Date("2011-09-24");
console.log(doo);

tronchi:

Fri Sep 23 2011 20:00:00 GMT-0400 (Eastern Daylight Time)

11
La classe Date di Javascript non rappresenta una data, ma rappresenta un timestamp (lo stesso in Java). Per renderlo una data, utilizza un fuso orario e questa è la causa del tuo problema. Esso analizza con il fuso orario GMT / UTC (24 Settembre 2011, 00 : 00 UTC) e poi in uscita con un diverso fuso orario di 4 ore (23 settembre 2011, 20 : 00 GMT-0400).
Codo,

2
Ottengo "data non valida". Sostituisci i caratteri "-" con i caratteri "/" e riprova. O dividere la data in bit e impostare i componenti singolarmente (in tal caso, sottrarre 1 dal numero del mese).
RobG,

@Codo - sì, buona risposta. Si applica l'ECMA-262 del 15.9.1.15. L'OP dovrebbe utilizzare "2011-09-24T20: 00: 00-04: 00" o simile.
RobG,

1
Ho scoperto che il formato "24 settembre 2011" restituirà la data corretta. Vedi qui per una spiegazione: stackoverflow.com/questions/2587345/javascript-date-parse
christurnerio

Risposte:


98

Si noti che l'ora legale orientale è -4 hourse che sono le ore della data di ritorno 20.

20h + 4h = 24h

che è la mezzanotte del 24/09/2011. La data è stata analizzata in UTC (GMT) perché hai fornito una stringa di sola data senza alcun indicatore di fuso orario. Se invece fosse stata fornita una stringa data / ora senza un indicatore ( new Date("2011-09-24T00:00:00")), sarebbe stata analizzata nel fuso orario locale. (Storicamente ci sono state incongruenze lì, anche perché le specifiche sono cambiate più di una volta, ma i browser moderni dovrebbero essere a posto; oppure puoi sempre includere un indicatore del fuso orario.)

Stai ricevendo la data giusta, non hai mai specificato il fuso orario corretto.

Se è necessario accedere ai valori della data, è possibile utilizzare getUTCDate()o una qualsiasi delle altre getUTC*()funzioni :

var d,
    days;
d = new Date('2011-09-24');
days = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'];
console.log(days[d.getUTCDay()]);

24
Come "specifichi il fuso orario corretto"? Il costruttore della data interpreta sempre la stringa della data come UTC, ma si adatta al fuso orario. Posso anche fare `nuova data ('2012-01-02 EDT') e ancora lo sposta indietro al giorno precedente a causa dell'applicazione dell'offset per l'ora legale, il che non ha senso perché se ti dicessi che è la data secondo l'attuale fuso orario locale di EDT, quindi non applicare un ulteriore offset ad esso. Gli ho detto che il fuso orario era EDT ma applica ancora un offset aggiuntivo spostandolo indietro di un giorno.
AaronLS,

1
@AaronLS, EDTè l' ora legale (anche conosciuta come ora legale) , ESTè il fuso orario che si applica a gennaio.
zzzzBov,

1
Creare come solo UTC da una stringa sarebbe quello che mi piacerebbe fare, quindi perché ho chiesto "Come si fa a" specificare il fuso orario corretto "?" riguardo a dove hai dichiarato "non hai mai specificato il fuso orario corretto". Se lo faccio new Date('2012-01-01 GMT'), applica comunque un offset in quanto lo converte nell'ora della data locale dell'utente.
AaronLS,

7
@AaronLS, se sei costretto a utilizzare i get*metodi e ne hai bisogno per restituire la data / ora corretta, incluso l'offset del fuso orario sconosciuto, aggiungi semplicemente l'offset del fuso orario sconosciuto: d = new Date('2013-01-08 GMT'); d.setMinutes(d.getMinutes() + d.getTimezoneOffset());questo normalizzerà la data alle impostazioni locali dell'utente in modo che i .get*metodi ritornino il valore atteso. I .getUTC*metodi saranno quindi errati, quindi fai attenzione.
zzzzBov

1
C'è una differenza tra definire il comportamento per fornire un riferimento e usarlo come via di fuga quando gli implementatori non riescono a implementare qualcosa in modo corretto. E non è la stessa rappresentazione se i dati non si allineano alle aspettative.
Dissident Rage,

252

Ci sono diverse cose folli che accadono con un oggetto JS DATE che converte le stringhe, ad esempio considera la data seguente che hai fornito

Nota: I seguenti esempi possono essere o non essere un giorno di riposo a seconda TUO fuso orario e l'ora corrente.

new Date("2011-09-24"); // Year-Month-Day
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

Tuttavia, se riordiniamo il formato stringa in Mese-Giorno-Anno ...

new Date("09-24-2011");
=> // Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

Un altro strano

new Date("2011-09-24");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF AS BEFORE.

new Date("2011/09/24"); // change from "-" to "/".
=> // Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

Potremmo facilmente cambiare trattini nella tua data "2011-09-24" quando crei una nuova data

new Date("2011-09-24".replace(/-/g, '\/')); // => "2011/09/24".
=> // Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

E se avessimo una stringa di date del tipo "2011-09-24T00: 00: 00"

new Date("2011-09-24T00:00:00");
// => Fri Sep 23 2011 17:00:00 GMT-0700 (MST) - ONE DAY OFF.

Ora cambia il trattino in avanti come prima; che succede?

new Date("2011/09/24T00:00:00");
// => Invalid Date

In genere devo gestire il formato data 2011-09-24T00: 00: 00 quindi questo è quello che faccio.

new Date("2011-09-24T00:00:00".replace(/-/g, '\/').replace(/T.+/, ''));
// => Sat Sep 24 2011 00:00:00 GMT-0700 (MST) - CORRECT DATE.

AGGIORNARE

Se si forniscono argomenti separati al costruttore Date, è possibile ottenere altri output utili come descritto di seguito

Nota: gli argomenti possono essere di tipo Numero o Stringa. Mostrerò esempi con valori misti.

Ottieni il primo mese e il giorno di un determinato anno

new Date(2011, 0); // Normal behavior as months in this case are zero based.
=> // Sat Jan 01 2011 00:00:00 GMT-0700 (MST)

Ottieni l'ultimo mese e il giorno di un anno

new Date((2011 + 1), 0, 0); // The second zero roles back one day into the previous month's last day.
=> // Sat Dec 31 2011 00:00:00 GMT-0700 (MST)

Esempio di argomenti Number, String. Nota che il mese è marzo perché di nuovo a base zero.

new Date(2011, "02"); 
=> // Tue Mar 01 2011 00:00:00 GMT-0700 (MST)

Se facciamo la stessa cosa ma con un giorno di zero, otteniamo qualcosa di diverso.

new Date(2011, "02", 0); // again the zero roles back from March to the last day of February.
=> // Mon Feb 28 2011 00:00:00 GMT-0700 (MST)

L'aggiunta di un giorno zero a qualsiasi argomento dell'anno e del mese otterrà l'ultimo giorno del mese precedente. Se continui con numeri negativi, puoi continuare a tornare indietro un altro giorno

new Date(2011, "02", -1);
=> // Sun Feb 27 2011 00:00:00 GMT-0700 (MST)

12
Questo in realtà mi ha aiutato il meglio. Ho appena aggiunto .replace (/ - / g, '\ /'). Replace (/ T. + /, '') Alla fine dei miei dati quando ho fissato una nuova data. Super facile!
Devin Prejean,

64
Wow - javascript è terribilmente incoerente.
psparrow

2
Le chiamate .replace () hanno davvero aiutato in un pizzico stasera.
disuso il

2
Sì, ho provato tutto questo ed è davvero strano.
Chintan Adatiya,

27
Tutto ciò è dovuto al comportamento del Date.parse () sottostante che tenta di seguire ISO 8601. Quando la stringa di data segue il formato aaaa-mm-gg, si presume che sia ISO 8601 con UTC implicito 00:00. Quando la stringa si discosta dal formato (ad es. Mm-gg-aaaa o barra anziché trattino), ricade nel parser più libero secondo RFC 2822 che utilizza l'ora locale quando il fuso orario è assente. Certo, tutto sarà abbastanza arcano per una persona media.
Mizstik,

71

Per normalizzare la data ed eliminare l'offset indesiderato (testato qui: https://jsfiddle.net/7xp1xL5m/ ):

var doo = new Date("2011-09-24");
console.log(  new Date( doo.getTime() + Math.abs(doo.getTimezoneOffset()*60000) )  );
// Output: Sat Sep 24 2011 00:00:00 GMT-0400 (Eastern Daylight Time)

Questo compie anche lo stesso e merito a @tpartee (testato qui: https://jsfiddle.net/7xp1xL5m/1/ ):

var doo = new Date("2011-09-24");
console.log( new Date( doo.getTime() - doo.getTimezoneOffset() * -60000 )  );

Per me è stato così: ho dovuto lavorare con le date di un'API, quindi ordinarle / confrontarle, quindi semplicemente aggiungendo l'offset del fuso orario funziona meglio.
Chakeda,

Questo ha funzionato per me, tranne per il fatto che ho dovuto sottrarre timeZoneOffset, non aggiungerlo
ErikAGriffin

@ErikAGriffin Sei in un fuso orario positivo, IE GMT + 0X00 anziché GMT-0X00?
AaronLS

Ho fatto qualcosa di simile:doo.setMinutes(doo.getMinutes() + doo.getTimezoneOffset())
Dissident Rage

2
@AaronLS Eri sulla strada giusta ma con logica leggermente sbagliata. Per compensare l'offset TZ la logica corretta è: console.log (nuova data (doo.getTime () - doo.getTimezoneOffset () * -60000)); - Il segno dell'offset è importante e non può essere assolto ma è necessario anche il segno inverso per la correzione, quindi moltiplichiamo l'offset per -60000 per applicare il segno inverso.
tpartee

28

Se si desidera ottenere l'ora 0 di una certa data nel fuso orario locale, passare le singole parti della data al Datecostruttore.

new Date(2011,08,24); // month value is 0 based, others are 1 based.

26

Voglio solo aggiungere che apparentemente l'aggiunta di uno spazio alla fine della stringa utilizzerà UTC per la creazione.

new Date("2016-07-06")
> Tue Jul 05 2016 17:00:00 GMT-0700 (Pacific Daylight Time)

new Date("2016-07-06 ")
> Wed Jul 06 2016 00:00:00 GMT-0700 (Pacific Daylight Time)

Modifica: questa non è una soluzione consigliata, ma solo una risposta alternativa. Si prega di non utilizzare questo approccio poiché non è molto chiaro cosa stia accadendo. Esistono diversi modi in cui qualcuno potrebbe refacturing questo causando accidentalmente un bug.


Per l'esempio con lo spazio alla fine, la console restituisce "Data non valida = $ 2"
Brian Risk

1
funziona molto bene! nuova data (data.Date + "") .toLocaleDateString ("en-US")
Nakres

Ad essere sinceri, questa era solo una risposta alternativa e non è una soluzione raccomandata.
Kyle Shrader,

25

Credo che abbia a che fare con la regolazione del fuso orario. La data che hai creato è in GMT e l'ora predefinita è mezzanotte, ma il tuo fuso orario è EDT, quindi sottrae 4 ore. Prova questo per verificare:

var doo = new Date("2011-09-25 EDT");

3
Questa è la migliore risposta qui. + 1 milione per l'utilizzo delle stringhe di localizzazione del fuso orario integrate anziché la conversione programmatica.
blearn,

2
Questo aiuta. Funziona così: $ scope.dat = new Date (datestring + 'EDT'). Nota la differenza tra EDT ed EST: link
Weihui Guo,

Non so cosa succede dietro le quinte, ma funziona perfettamente.
the_haystacker il

Direi che è la più semplicistica delle risposte e meno riformattazione del codice.
Michael,

Grazie, considero il modo migliore per me.
Janderson Constantino,

11

Il tuo problema riguarda specificamente il fuso orario. Nota GMT-0400: sei indietro di 4 ore rispetto al GMT. Se aggiungi 4 ore alla data / ora visualizzate, otterrai esattamente la mezzanotte del 2011/09/24. Utilizzare toUTCString()invece il metodo per ottenere la stringa GMT:

var doo = new Date("2011-09-24");
console.log(doo.toUTCString());

7

Questa probabilmente non è una buona risposta, ma voglio solo condividere la mia esperienza con questo problema.

La mia app utilizza globalmente data utc con il formato "AAAA-MM-GG", mentre il plug-in Datepicker che utilizzo accetta solo js date, è difficile per me considerare sia utc che js. Quindi quando voglio passare una data formattata 'AAAA-MM-GG' al mio datepicker, prima la converto nel formato 'MM / GG / AAAA' usando moment.js o qualunque cosa ti piaccia, e la data mostrata su datepicker è ora corretta. Per il tuo esempio

var d = new Date('2011-09-24'); // d will be 'Fri Sep 23 2011 20:00:00 GMT-0400 (EDT)' for my lacale
var d1 = new Date('09/24/2011'); // d1 will be 'Sat Sep 24 2011 00:00:00 GMT-0400 (EDT)' for my lacale

Apparentemente d1 è quello che voglio. Spero che questo possa essere utile per alcune persone.


1
Il solo cambio dei formati come hai fatto tu ha funzionato allo stesso modo per me. Così strano.
jAC

5

Questo attraverso di me per un ciclo, +1 sulla risposta di zzzBov. Ecco una conversione completa di una data che ha funzionato per me utilizzando i metodi UTC:

//myMeeting.MeetingDate = '2015-01-30T00:00:00'

var myDate = new Date(myMeeting.MeetingDate);
//convert to JavaScript date format
//returns date of 'Thu Jan 29 2015 19:00:00 GMT-0500 (Eastern Standard Time)' <-- One Day Off!

myDate = new Date(myDate.getUTCFullYear(), myDate.getUTCMonth(), myDate.getUTCDate());
//returns date of 'Fri Jan 30 2015 00:00:00 GMT-0500 (Eastern Standard Time)' <-- Correct Date!

4

Significa 2011-09-24 00:00:00 GMT, e dato che ci sei GMT -4, sarà 20:00il giorno precedente.

Personalmente, capisco 2011-09-24 02:00:00perché vivo a GMT +2.


3

Sebbene nel caso dell'OP il fuso orario sia EDT, non è garantito che l'utente che esegue lo script sia nel fuso orario EDT, quindi l'hardcoding dell'offset non funzionerà necessariamente. La soluzione che ho trovato divide la stringa della data e utilizza i valori separati nel costruttore Date.

var dateString = "2011-09-24";
var dateParts = dateString.split("-");
var date = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);

Nota che devi tenere conto di un'altra stranezza di JS: il mese è a base zero.


2

Ho riscontrato questo esatto problema in cui il mio cliente era in Atlantic Standard Time. Il valore della data recuperato dal client era "23-11-2018" e quando il codice lo ha passato new Date("2018-11-23")nell'output per il client era per il giorno precedente. Ho creato una funzione di utilità come mostrato nello snippet che ha normalizzato la data, dando al cliente la data prevista.

date.setMinutes(date.getMinutes() + date.getTimezoneOffset());

var normalizeDate = function(date) {
  date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
  return date;
};

var date = new Date("2018-11-23");

document.getElementById("default").textContent = date;
document.getElementById("normalized").textContent = normalizeDate(date);
<h2>Calling new Date("2018-11-23")</h2>
<div>
  <label><b>Default</b> : </label>
  <span id="default"></span>
</div>
<hr>
<div>
  <label><b>Normalized</b> : </label>
  <span id="normalized"></span>
</div>


2

se stai solo cercando di assicurarti che le singole parti della data rimangano invariate ai fini della visualizzazione, * questo sembra funzionare, anche quando cambio il fuso orario:

var doo = new Date("2011-09-24 00:00:00")

aggiungi gli zeri lì dentro.

Nel mio codice lo faccio:

let dateForDisplayToUser = 
  new Date( `${YYYYMMDDdateStringSeparatedByHyphensFromAPI} 00:00:00` )
  .toLocaleDateString( 
    'en-GB', 
    { day: 'numeric', month: 'short', year: 'numeric' }
  )

E cambio il mio fuso orario sul mio computer e la data rimane la stessa della stringa di data yyyy-mm-dd che ottengo dall'API.

Ma mi sto perdendo qualcosa / è una cattiva idea?

* almeno in cromo. Questo non funziona in Safari! a partire da questa scrittura


Quando lo fai .toISOString(), torna indietro di 1 giorno.
vivek_23

new Date('2019/11/18 05:30:00').toISOString();ha funzionato per me
vivek_23

1

Il modo migliore per gestirlo senza utilizzare più metodi di conversione,

 var mydate='2016,3,3';
 var utcDate = Date.parse(mydate);
 console.log(" You're getting back are 20.  20h + 4h = 24h :: "+utcDate);

Ora aggiungi GMT nella tua data o puoi aggiungerlo.

 var  mydateNew='2016,3,3'+ 'GMT';
 var utcDateNew = Date.parse(mydateNew);
 console.log("the right time that you want:"+utcDateNew)

Live: https://jsfiddle.net/gajender/2kop9vrk/1/


1

Ho affrontato alcuni problemi come questo. Ma il mio problema era fuori set mentre ottenevo la data dal database.

questo è tracciato nel database ed è nel formato UTC.

29-03-2019 19: 00: 00.0000000 +00: 00

Quindi, quando ottengo dal database e controllo la data, aggiunge l'offset con esso e lo rimanda a javascript.

inserisci qui la descrizione dell'immagine

Aggiunge +05: 00 perché questo è il fuso orario del mio server. Il mio cliente è in fuso orario diverso +07: 00.

28-03-2019T19: 00: 00 + 05: 00 // questo è ciò che ottengo in JavaScript.

Quindi ecco la mia soluzione cosa faccio con questo problema.

var dates = price.deliveryDate.split(/-|T|:/);
var expDate = new Date(dates[0], dates[1] - 1, dates[2], dates[3], dates[4]);
var expirationDate = new Date(expDate);

Quindi, quando la data proviene dal server e ha un offset del server, quindi divido la data e rimuovo l'offset del server, quindi converto in data. Risolve il mio problema.


1

se hai bisogno di una soluzione semplice per questo vedi:

new Date('1993-01-20'.split('-')); 

inserisci qui la descrizione dell'immagine


0

Stai utilizzando il formato stringa di data ISO che, secondo questa pagina , determina la costruzione della data utilizzando il fuso orario UTC:

Nota: l'analisi delle stringhe di date con il costruttore Date (e Date.parse, sono equivalenti) è fortemente sconsigliata a causa delle differenze e delle incongruenze del browser. Il supporto per le stringhe in formato RFC 2822 è solo per convenzione. Il supporto per i formati ISO 8601 differisce in quanto le stringhe di sola data (ad es. "1970-01-01") sono trattate come UTC, non locali.

Se si formatta il testo in modo diverso, ad esempio "Jan 01 1970", (almeno sulla mia macchina) utilizza il fuso orario locale.


0

Sto cercando di aggiungere i miei 2 centesimi a questa discussione (elaborando la risposta di @ paul-wintz).

Mi sembra che quando il costruttore della data riceve una stringa che corrisponde alla prima parte del formato ISO 8601 (parte della data), esegue una conversione della data precisa nel fuso orario UTC con 0 ora. Quando tale data viene convertita in ora locale, può verificarsi uno spostamento della data se UTC di mezzanotte è una data precedente nel fuso orario locale.

new Date('2020-05-07')
Wed May 06 2020 20:00:00 GMT-0400 (Eastern Daylight Time)

Se la stringa della data è in qualsiasi altro formato "più flessibile" (usa "/" o la data / il mese non è riempita con zero) crea la data nel fuso orario locale, quindi nessun problema di spostamento della data.

new Date('2020/05/07')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-5-07')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-5-7')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
new Date('2020-05-7')
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)

Quindi una soluzione rapida, come accennato in precedenza, è quella di sostituire "-" con "/" nella stringa solo data formattata ISO.

new Date('2020-05-07'.replace('-','/'))
Thu May 07 2020 00:00:00 GMT-0400 (Eastern Daylight Time)

0

Memorizzando yyyy-mm-ddnel formato data MySql è necessario effettuare le seguenti operazioni:

const newDate = new Date( yourDate.getTime() + Math.abs(yourDate.getTimezoneOffset()*60000) );
console.log(newDate.toJSON().slice(0, 10)); // yyyy-mm-dd

-1

Il registro genera GMT in modo da specificare il fuso orario:

var doo = new Date("2011-09-24 EST");

3
Questa domanda ha già molte risposte. Se vuoi comunque rispondere alla domanda, dovresti menzionare qualcosa di nuovo che le altre risposte non rispondono. La risposta principale spiega già il problema con il fuso orario in modo molto più dettagliato.
Calvin Godfrey,

Questa risposta è quasi identica a stackoverflow.com/a/7556642/8828658
un aracnide di pietra

Chi se ne frega se la sua spiegazione è più approfondita ... il suo codice è ancora diverso dal mio. Il mio è molto più semplice. E sì, aracnide di pietra, hai ragione. Colpa mia.
bmacx7,

-3

non importa, non ho notato il GMT -0400, che fa sì che la data sia ieri

Potresti provare a impostare un "orario" predefinito alle 12:00:00


Sì, sono stato un po 'veloce con la mia risposta, mi dispiace per quello. Ho rivisto la mia risposta.
ChrisH,

-3

Quanto segue ha funzionato per me -

    var doo = new Date("2011-09-24").format("m/d/yyyy");

Non funzionerà ancora finché non si giocherà con il fuso orario.
Gar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.