2013-08-12 11 views
10

Ad esempio, utilizzando una data e tempo di controllo, l'utente seleziona una data e ora, in modo tale che la rappresentazione stringa è il seguente:Come si conserva il fuso orario di una data JavaScript dal browser al server e viceversa?

"6-25-2012 12:00:00 PM" 

accade che questo utente è nel fuso orario EST. La stringa viene passata al server, che la traduce in un oggetto .NET DateTime, quindi la archivia in SQL Server in una colonna datetime.

Quando la data viene restituita in seguito al browser, deve essere riconvertita in una data, tuttavia quando la stringa sopra riportata viene inserita in una data perde 4 ore di tempo. Credo che questo sia dovuto al fatto che quando non si specifica un fuso orario durante la creazione di una data JavaScript, il valore predefinito è ora locale, e poiché EST è -400 da GMT, sottrae 4 ore dalle 12pm, anche se quello 12pm doveva essere specificato come EST quando l'utente lo ha selezionato su una macchina nel fuso orario EST.

Chiaramente deve essere aggiunto qualcosa alla stringa datetime originale prima che sia passata al server da mantenere. Qual è il modo consigliato per farlo?

+0

Si potrebbe preferire gestire la data come un numero di secondi d.getTime()/1000 che può essere facilmente convertita fino ad oggi utilizzando la maggior parte delle lingue. – Serge

+0

Ok, ma se la data originale è costruita partendo da parti di stringhe (due controlli diversi, uno da un selettore di date, l'altro al time picker), ancora una volta come faccio a dire alla data di JavaScript che costruisco in che fuso orario è, altrimenti il ​​d.getTime()/1000 sarà fatto contro il tempo che gli ho dato, meno le 4 ore. – brushleaf

+0

Hai eseguito test con fuso orario diverso per assicurarti che il problema provenisse da lì e non dalla conversione? – Serge

risposta

18

Non fare affidamento sul costruttore di JavaScript Date per analizzare una stringa. Il comportamento e i formati supportati variano notevolmente per browser e impostazioni internazionali. Here sono solo alcuni dei comportamenti predefiniti se si utilizza direttamente l'oggetto Date.

Se è necessario provenire da una stringa, provare a utilizzare un formato standardizzato come ISO8601. La data che hai dato in quel formato sarebbe "2012-06-25T12:00:00". Il modo più semplice per lavorare con questi in JavaScript è con moment.js.

Inoltre, fate attenzione a ciò che intendete effettivamente rappresentare. In questo momento, stai passando una data/ora locale, salvando una/data/ora locale e restituendo una data/ora locale. Lungo la strada, l'idea di ciò che è "locale" potrebbe cambiare.

In molti casi, la data/ora è destinata a rappresentare un esatto momento nel tempo. Per farlo funzionare, è necessario convertire dall'ora locale immessa in UTC sul client. Invia UTC al tuo server e memorizzalo. Successivamente, recuperare UTC e inviarlo al client, elaborarlo come UTC e riconvertire in ora locale. Si può fare tutto questo facilmente con moment.js:

// I'll assume these are the inputs you have. Adjust accordingly. 
var dateString = "6-25-2012"; 
var timeString = "12:00:00 PM"; 

// Construct a moment in the default local time zone, using a specific format. 
var m = moment(dateString + " " + timeString, "M-D-YYYY h:mm:ss A"); 

// Get the value in UTC as an ISO8601 formatted string 
var utc = m.toISOString(); // output: "2012-06-25T19:00:00.000Z" 

Sul server in .Net:

var dt = DateTime.Parse("2012-06-25T19:00:00.000Z", // from the input variable 
         CultureInfo.InvariantCulture, // recommended for ISO 
         DateTimeStyles.RoundtripKind) // honor the Z for UTC kind 

Conservare che nel database. Più tardi recuperarlo e rinviarlo:

// when you pull it from your database, set it to UTC kind 
var dt = DateTime.SpecifyKind((DateTime)reader["yourfield"], DateTimeKind.Utc); 

// send it back in ISO format: 
var s = dt.ToString("o"); // "o" is the ISO8601 "round-trip" pattern. 

Passo di nuovo al javascript in moment.js:

// construct a moment: 
var m = moment("2012-06-25T19:00:00.000Z"); // use the value from the server 

// display it in this user's local time zone, in whatever format you want 
var s = m.format("LLL"); // "June 25 2012 12:00 PM" 

// or if you need a Date object 
var dt = m.toDate(); 

Sede - che era facile, e non hai bisogno di entrare in qualcosa di fantasia con fusi orari.

+0

Per memorizzare quella stringa ISO nel database, la colonna non deve essere un campo datetimeoffset (rispetto a un campo SQL datetime)? Supponendo ovviamente che non stiamo memorizzando solo una stringa. O è preferibile semplicemente archiviare la stringa? – brushleaf

+0

No, non memorizzare una stringa. Se si memorizza UTC, è possibile utilizzare datetime o datetime2. Non è necessario un datetimeoffset per questo particolare scenario. È possibile * usarlo, ma probabilmente non è necessario a meno che non ti interessi il fuso orario locale degli utenti. Vedi la mia risposta su [DateTime vs DateTimeOffset] (http://stackoverflow.com/questions/4331189/datetime-vs-datetimeoffset). –

+0

Solo per aggiungere al mio commento precedente - molte persone preferiscono in effetti utilizzare "DateTimeOffset" per UTC. Anche se sanno che l'offset è sempre zero, tenere traccia che in un 'DateTimeOffset' invece che in un' DateTime' è un buon modo per evitare che venga interpretato accidentalmente in modo errato. L'unico svantaggio di questo è che verrà serializzato con '+00: 00' invece di' Z', ma questo è spesso accettabile. –

2

Ecco, credo che questo è quello che stai cercando: How to ignore user's time zone and force Date() use specific time zone

Mi sembra che si può fare qualcosa di simile:

var date = new Date("6-25-2012 12:00:00 PM"); 

var offset = date.getTimezoneOffset(); // returns offset from GMT in minutes 

// to convert the minutes to milliseconds 
offset *= 60000; 

// the js primitive value is unix time in milliseconds so this retrieves the 
// unix time in milliseconds and adds our offset. 
// Now we can put this all back in a date object 
date = new Date(date.valueOf() + offset); 

// to get back your sting you can maybe now do something like this: 
var dateString = date.toLocaleString().replace(/\//g,'-').replace(',',''); 
0

Sto usando un filtro prima di inviare la data al server vm.dateFormat = 'aaaa-MM-gg'; dateToSendToServer = $ filter ('date') (dateFromTheJavaScript, vm.dateFormat);

Problemi correlati