2008-12-09 11 views
30

Rails' ActiveSupport module extends the builtin ruby Time class with a number of methods.¿Rails ActiveSupport Time Parsing?

En particular, no es el método to_formatted_s, lo que le permite escribir Time.now.to_formatted_s(:db) para obtener una cadena en formato de base de datos, en lugar de tener que escribir feas strftime formato de cadenas en todas partes.

Mi pregunta es, ¿hay alguna manera de ir hacia atrás?

Algo así como Time.parse_formatted_s(:db) que analizará una cadena en formato de base de datos y devolverá un nuevo objeto Time. Esto parece algo que los rieles deberían proporcionar, pero si lo es, no puedo encontrarlo.

¿Acaso no puedo encontrarlo o tengo que escribirlo yo mismo?

Gracias

Respuesta

55

Parece que ActiveSupport no proporcionar los métodos de análisis que busca (y que estaba buscando también), después de todo! — al menos si la cadena que está tratando de analizar es una fecha estándar, con formato ISO-8601 (formato :db).

Si la fecha que está tratando de analizar ya está en su zona horaria local, ¡es realmente fácil!

> Time.zone.parse('2009-09-24 08:28:43') 
=> Thu, 24 Sep 2009 08:28:43 PDT -07:00 

> Time.zone.parse('2009-09-24 08:28:43').class 
=> ActiveSupport::TimeWithZone 

y que el tiempo de zona horaria consciente puede ser fácilmente convertida en GMT

> Time.zone.parse('2009-09-24 08:28:43').utc 
=> 2009-09-24 15:28:43 UTC 

o para otras zonas horarias:

> ActiveSupport::TimeZone.us_zones.map(&:name) 
=> ["Hawaii", "Alaska", "Pacific Time (US & Canada)", "Arizona", "Mountain Time (US & Canada)", "Central Time (US & Canada)", "Eastern Time (US & Canada)", "Indiana (East)"] 

> Time.zone.parse('2009-09-24 08:28:43').utc.in_time_zone('Eastern Time (US & Canada)') 
=> Thu, 24 Sep 2009 11:28:43 EDT -04:00 

Si la cadena de fecha que está tratando para analizar está en UTC, por otro lado, no parece que haya ningún método para analizarlo directamente en un TimeWithZone, pero pude evitarlo usando primero Da teTime.strptime ...

Si la fecha que estamos tratando de analizar es en UTC y desea que permanezca como UTC, puede utilizar:

> DateTime.strptime('2009-09-24 08:28:43', '%Y-%m-%d %H:%M:%S').to_time 
=> 2009-09-24 08:28:43 UTC 

Si la fecha que está tratando de análisis sintáctico es en UTC y quiere que convierte a la zona horaria predeterminada, puede utilizar:

> DateTime.strptime('2009-09-24 08:28:43', '%Y-%m-%d %H:%M:%S').to_time.in_time_zone 
=> Thu, 24 Sep 2009 01:28:43 PDT -07:00 

parece que incluso puede analizar otros formatos, como el extraño formato que Time N. ° to_s produce:

irb -> Time.zone.parse('Wed, 23 Sep 2009 02:18:08').to_s(:db) 
    => "2009-09-23 09:18:08" 

irb -> Time.zone.parse('Wed, 23 Sep 2009 02:18:08 EDT').to_s(:db) 
    => "2009-09-23 06:18:08" 

Estoy bastante impresionado.

Aquí hay algunos ejemplos más de [http://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html][1]:

Time.zone = 'Eastern Time (US & Canada)'  # => 'Eastern Time (US & Canada)' 
    Time.zone.local(2007, 2, 10, 15, 30, 45)  # => Sat, 10 Feb 2007 15:30:45 EST -05:00 
    Time.zone.parse('2007-02-10 15:30:45')   # => Sat, 10 Feb 2007 15:30:45 EST -05:00 
    Time.zone.at(1170361845)      # => Sat, 10 Feb 2007 15:30:45 EST -05:00 
    Time.zone.now         # => Sun, 18 May 2008 13:07:55 EDT -04:00 
    Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45 EST -05:00 

más enlaces de documentación para la referencia:

+0

Gracias por publicar tantos detalles. Su referencia DateTime.strptime() es muy útil para el caso en que necesito analizar una fecha de la base de datos que ActiveRecord :: Base.connection.select_value() devuelve como una cadena. – Lee

+0

Killer answer. No me di cuenta de que Time.zone = "..." funcionó. Me acabas de ahorrar un montón de tiempo. – rhh

+2

¡Gracias por la respuesta! Si no desea cambiar la TZ global, puede usar Time :: use_zone, ej. para analizar UTC, use Time.use_zone ('UTC') {Time.zone.parse '2012-11-01 13:37'}. – Divide

1
>> "2009-09-24".to_date 
=> Thu, 24 Sep 2009 
>> "9/24/2009".to_date 
=> Thu, 24 Sep 2009 

Funciona muy bien a menos que su fecha esté en algún formato raro.

+0

"algún formato raro" - como una fecha formateada como el resto del mundo lo hace? :) –

5
ActiveSupport::TimeZone.new('UTC').parse('2009-09-23 09:18:08') 
=> Wed, 23 Sep 2009 09:18:08 UTC +00:00 
2

Acabo de toparme con esto también y ninguna de las respuestas anteriores fue satisfactoria para mí. Lo ideal sería usar ActiveSupport::TimeZone como Time y llamar al .strptime con cualquier formato arbitrario y obtener el objeto TimeZone correcto. ActiveSupport::TimeZone.strptime no existe por lo que creó esta monkeypatch:

class ActiveSupport::TimeZone 
    def strptime(str, fmt, now = self.now) 
     date_parts = Date._strptime(str, fmt) 
     return if date_parts.blank? 
     time = Time.strptime(str, fmt, now) rescue DateTime.strptime(str, fmt, now) 
     if date_parts[:offset].nil? 
     ActiveSupport::TimeWithZone.new(nil, self, time) 
     else 
     time.in_time_zone(self) 
     end 
    end 
    end 
3

carriles 5, finalmente, proporciona strptime!

value = '1999-12-31 14:00:00' 
format = '%Y-%m-%d %H:%M:%S' 
Time.zone.strptime(value, format) 
# => Fri, 31 Dec 1999 14:00:00 HST -10:00 

ActiveSupport::TimeZone.all.sample.strptime(value, format) 
# => Fri, 31 Dec 1999 14:00:00 GST +04:00