2012-04-10 13 views
27

Utilizzo Rails 3.2 e ruby ​​1.9.3 su Debian. Ho un'app che raccoglie data, ora e fuso orario sotto forma di stringhe tramite un modulo HTML. Qualcosa di simile a questo:: Come analizzare la stringa data/ora in un fuso orario specifico

start_date: "04-15-2010", 
start_time: "10:00:00", 
timezone: "Central Time (US & Canada)" 

Quello che mi piacerebbe fare è analizzare questi 3 elementi in un unico data che viene salvato nel mio database come UTC, che in questo caso dovrebbe aggiungere 7 ore per l'ora di inizio, una volta è nel fuso orario UTC. Quindi il tempo memorizzato sarebbe 17:00 una volta nel DB come UTC anziché l'ora centrale ricevuta.

Ho provato qualcosa di simile per analizzare la data:

ActiveSupport::TimeZone[timezone].at DateTime.strptime("{ 2012-04-09 20:00:00 }", "{ %Y-%m-%d %H:%M:%S }").to_i 

Tuttavia, io non sono in grado di integrare il fuso orario nel tempo risultante con% Z. Non viene analizzato o l'ora viene interpretata come ora UTC non centrale. Quindi la mia domanda è, come forzare una stringa di data in un certo fuso orario senza cambiare il valore della data/ora effettiva memorizzata. Mi piacerebbe essere in grado di analizzare la stringa in un oggetto data/ora che include il fuso orario corretto con esso in quel momento in modo che le future conversioni del fuso orario siano accurate. Ho guardato dappertutto e non riesco a trovare un modo per farlo. È strano, dal momento che questo sembra qualcosa di comune con date immesse da moduli HTML. Grazie per tutto l'aiuto.

risposta

16

%Z è il modo corretto per specificare un nome di fuso orario. Hai provato quanto segue?

date_and_time = '%m-%d-%Y %H:%M:%S %Z' 
DateTime.strptime("04-15-2010 10:00:00 Central Time (US & Canada)",date_and_time) 
+0

"% Z" consente nomi di fuso orario con spazi? Ho sempre pensato che ci si aspettasse cose come "EST5EDT" o "-0500". – tadman

+1

Non sono sicuro, l'esempio sopra funziona per me e dà il risultato "Gio 15 Apr 2010 10:00:00 -0600". Se conosci l'offset puoi passarlo anche direttamente sotto forma di "-0600". Immagino che il sistema riconosca tutti i fusi orari da "rake time: zones: all". – 0x4a6f4672

+1

volevo dire questo. Grazie @ 0x4a6f4672! Questo non funzionava: DateTime.strptime ("{2012-04-09 20:00:00 Central Time (USA e Canada)}", "{% Y-% m-% d% H:% M:% S% Z} ") ma quando ho tirato fuori le parentesi graffe come nel tuo esempio, ha funzionato. Quanto segue ha funzionato, e l'unica differenza sono state le parentesi graffe rimosse, che avevo letto in alcuni esempi di strptime o documenti come parte del funzionamento di strptime: DateTime.strptime ("2012-04-09 20:00:00 Central Time (US) & Canada) ","% Y-% m-% d% H:% M:% S% Z "). Pensavo che fossero gli spazi nel fuso orario a buttarlo via ma erano le parentesi graffe. Grazie ancora. –

89

Prova questo:

zone = "Central Time (US & Canada)" 

ActiveSupport::TimeZone[zone].parse("2013-04-03 17:47:00") 
+6

Questo è fantastico, ma c'è comunque da fare con il tempo? Le mie date hanno un formato specifico e non funzionano con .parse – taelor

+0

Forse intendi la risposta sopra. La soluzione utilizza #strptime. – ryancheung

+0

Questo account è valido per l'ora legale? – Tallboy

20

Io personalmente preferisco utilizzare String # in_time_zone:

>> '22.09.1986 10:30'.in_time_zone('Central Time (US & Canada)') 
Mon, 22 Sep 1986 10:30:00 CDT -05:00 
+1

Questo funziona per me con 'DateTime.parse'. Grazie – daniel

+0

Felice di aver risolto il tuo problema! –

0

Per avere DateTime prendere la stringa della data e collegare un fuso orario diverso da quello UTC senza modificare i valori della stringa data, usa questo, è facile, non si rompe il giorno bisestile :)

xx = DateTime.strptime("9/1/15 #{object.time_zone}", "%m/%d/%Y %Z") 
1

Questo è il metodo che mi è venuto in mente. Non è il più bello, ma funziona. Consente di analizzare la stringa utilizzando un formato specificato e quindi di trasformarla nel formato che conosco Time.zone.parse.

class ActiveSupport::TimeZone 
    def strptime(time, format='%m/%d/%Y') 
    formatted = Time.strptime(time, format).strftime('%Y-%m-%d %T') 
    parse(formatted) 
    end 
end 

allora si può fare qualcosa di simile a ciò che è stato detto in un'altra domanda, ma con un formato specificato:

zone = "Central Time (US & Canada)" 
ActiveSupport::TimeZone[zone].strptime('2013-04-03', '%Y-%m-%d') 

Oppure, se si dispone già di un set di fuso orario:

Time.zone = "Central Time (US & Canada)" 
Time.zone.strptime('01/13/2006') 

Ho usato un formato predefinito di %m/%d/%Y perché questo è ciò che il mio input utente è la maggior parte del tempo. È possibile personalizzare questo per le proprie esigenze, o utilizzare il formato predefinito DateTime usi che è iso8601 (%FT%T%z)

+0

Il mio fuso orario è impostato: sembrava ottimo, ma: "metodo non definito' strptime 'per # JosephK

0

Ho finalmente trovato il modo sporco, ma definitivo per farlo.

Innanzitutto, analizzare la stringa utilizzando il semplice Tempo di rubino.durata del tempo:

In questo modo si ottiene il Tempo analizzato, ma non ancora nel fuso orario corretto. Per risolvere questo, cerchiamo di convertire il momento di forma di stringa e analizzarlo con lo standard di ActiveSupport :: timezone # analizzare

Time.zone.parse(time.to_s) 

Il risultato è l'ActiveSupport :: TimeWithZone con il nostro tempo analizzato nel fuso orario corretto.

Il motivo per cui dobbiamo farlo in questo modo è che né ActiveSupport :: TimeZone né ActiveSupport :: TimeWithZone supportano il metodo strptime. Quindi dobbiamo analizzare il tempo con il tempo di Ruby core che non ha informazioni sul fuso orario, convertirlo in formato accettabile negli oggetti ActiveSupport e quindi analizzarlo nuovamente.