2010-03-25 21 views
5

Necesito convertir un objeto Date en un objeto TimeWithZone que representa el comienzo de ese día en un huso horario dado.convertir el objeto Fecha a TimeWithZone

El siguiente enfoque funciona, pero parece demasiado complicado, ya que me requiere para convertir la fecha en una cadena:

?> date = Date.parse("2010-02-17") 
=> Wed, 17 Feb 2010 
>> ActiveSupport::TimeZone['Eastern Time (US & Canada)'].parse(date.to_s) 
=> Wed, 17 Feb 2010 00:00:00 EST -05:00 
>> ActiveSupport::TimeZone['UTC'].parse(date.to_s) 
=> Wed, 17 Feb 2010 00:00:00 UTC 00:00 

¿Hay una mejor manera de que me falta?

Editar: personas están sugiriendo variaciones de:

?> date.to_datetime.in_time_zone('Eastern Time (US & Canada)').beginning_of_day 
=> Tue, 16 Feb 2010 00:00:00 EST -05:00 

Como se puede ver, esto no es una conversión equivalente, ya que me deja en el inicio de Feb. de decima sexta EST, en lugar del inicio de 17 de febrero EST.

+0

Parece que su solución podría ser el camino correcto a seguir. –

+0

He editado mi respuesta para solucionar este problema. –

+0

¡Date la solución! =) El tiempo con zonas horarias siempre es desordenado. – John

Respuesta

0

¿Algo como esto funcionaría para usted?

'2010-04-01'.to_time.in_time_zone('Eastern Time (US & Canada)').beginning_of_day 
+0

ver mi edición a la pregunta de por qué esto no funciona – avaynshtok

0

Reste utc_offset:

d = Date.today 
Time.zone.class.all.map(&:name).map { |tz| dt = d.to_datetime.in_time_zone(tz); dt -= dt.utc_offset } 

Usando ActiveSupport :: Zona horaria [tz] no toma el horario de verano en cuenta.

Time.zone.class.all.map(&:name).map { |tz| o = d.to_datetime.in_time_zone(tz).utc_offset - ActiveSupport::TimeZone[tz].utc_offset } 
4

Si tiene Time.zone conjunto de rieles entonces se puede llamar Date#at_beginning_of_day (ver http://api.rubyonrails.org/classes/Date.html#method-i-at_beginning_of_day). Contrasta esto con Date#to_datetime:

Time.zone 
=> #<ActiveSupport::TimeZone:0x10cf10858 @tzinfo=#<TZInfo::TimezoneProxy: Etc/UTC>, @utc_offset=nil, @current_period=nil, @name="UTC"> 

date = Date.today 
=> Thu, 31 May 2012 

date.to_datetime 
=> Thu, 31 May 2012 00:00:00 +0000 

date.at_beginning_of_day 
=> Thu, 31 May 2012 00:00:00 UTC +00:00 

Time.zone = 'America/Chicago' 
=> "America/Chicago" 

date.to_datetime 
=> Thu, 31 May 2012 00:00:00 +0000 

date.at_beginning_of_day 
=> Thu, 31 May 2012 00:00:00 CDT -05:00 
+2

'Time.zone' ** es ** threadsafe, establece la zona en' Thread.current [: time_zone] '. [fuente] (https://github.com/rails/rails/blob/08754f12e65a9ec79633a605e986d0f1ffa4b251/activesupport/lib/active_support/core_ext/time/zones.rb#L39) –

+1

Gracias por la corrección, eliminé ese comentario, pero dejé este uno para que la gente no crea que estás loco;) – gtd

2

recomiendo fuertemente contra cualquier solución que convierte la fecha a la vez usando to_datetime o to_time porque esos métodos no son conscientes de la zona, y viradas in_time_zone en el resultado, ya que algunas respuestas sugieren, no arreglará retroactivamente el error. Además, no intente construir su propia matemática de horario de verano utilizando compensaciones UTC. Seguramente te equivocarás, y estás haciendo el trabajo innecesariamente. .

uso de la propia zona horaria que tiene esta lógica construida en

Dada una zona y una fecha, se puede obtener una TimeWithZone para el inicio de la jornada como esta:

time = zone.local(date.year, date.month, date.day) 

Si desea una hora específica del día que no sea el comienzo, puede pasar la hora, el minuto y el segundo como argumentos 4to, 5to y 6to al #local.

Si zone es en realidad la zona horaria local de su sistema (Time.zone), entonces ActiveSupport le permitirá acortar el anterior a este:

time = date.to_time_in_current_zone 

Todo el mango por encima de ahorrar tiempo correctamente la luz del día. Vamos a comprobar que al mirar los desfases de UTC por dos veces, una que está fuera de horario de verano y uno que está dentro de horario de verano:

irb(main):009:0> zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] 
=> (GMT-05:00) Eastern Time (US & Canada) 
irb(main):010:0> t1 = zone.local(2013, 1, 1) 
=> Tue, 01 Jan 2013 00:00:00 EST -05:00 
irb(main):011:0> t2 = zone.local(2013, 5, 1) 
=> Wed, 01 May 2013 00:00:00 EDT -04:00 
irb(main):012:0> t1.utc_offset 
=> -18000 
irb(main):013:0> t2.utc_offset 
=> -14400 
+0

Eliminé mi respuesta y voté como tuya. –

5

llego tarde a la fiesta, pero esto sigue siendo una gran pregunta. Se introdujo el in_time_zone de ActiveSupport desde el O.P., pero hace exactamente lo que usted desea sin analizar una cadena (lenta) ni establecer el tiempo.zona (arriesgado):

>> date = Date.parse("2010-02-17") 
=> Wed, 17 Feb 2010 
>> date.in_time_zone('Eastern Time (US & Canada)') 
=> Wed, 17 Feb 2010 00:00:00 EST -05:00 

Por supuesto, si desea que el comienzo del día expresado en UTC, se puede hacer esto:

>> date.in_time_zone('Eastern Time (US & Canada)').utc 
=> 2010-02-17 05:00:00 UTC 
Cuestiones relacionadas