Time Zones

Geplaatst door Michiel de Mare do, 28 mei 2009 21:28:00 GMT

Tijdfuncties in Rails zijn op sommige punten nogal wankel. Zo zou je verwachten dat Time.now en 0.seconds.ago gelijk zijn. Dat is niet zo:

>> Time.now
=> Thu May 28 23:28:37 +0200 2009
>> 0.seconds.ago
=> Thu, 28 May 2009 23:28:42 CEST +02:00

Nadere inspectie leert dat Time.now een normaal Ruby Time instantie is, terwijl 0.seconds.ago een ActiveSupport::TimeWithZone object is.

En dat kan een flink verschil maken! Bij deze code bijvoorbeeld:
>> Time.now.to_s(:db)
=> "2009-05-28 23:33:08" 
>> 0.seconds.ago.to_s(:db)
=> "2009-05-28 21:33:16" 

De to_s(:db) method wordt gebruikt in find queries en named scopes, en bovenstaand verschil maakt dat het gebruik van Time.now, Time.parse en Time.at af te raden is wanneer het als database-parameter gebruikt kan worden. Rails converteert Time instanties wel in TimeWithZone objecten bij ActiveRecord-attributen. Als alternatief kan Time.zone.now etc. gebruikt worden.

Kortom: u.published_at = Time.now werkt prima, maar wanneer je in je environment.rb een lokale tijdzone hebt staan, gaat dit verkeerd in Rails 2.3.2:
named_scope :begun, proc{{:conditions => ['started_at < ?', Time.now]}}

Weest op uw hoede!

Tags ,  | 5 reacties

Reacties

  1. Jan De Poorter zei ongeveer 10 uur later:

    Daarom heeft Rails Time.current toegevoegd aan de Time class, wat de zone wel in rekening brengt en dus nu de voorkeur heeft.

  2. Michiel zei ongeveer 11 uur later:

    Aha! Bedankt voor de tip. Ik blijf het echter een verschrikkelijk lelijke hack vinden. En wat ik niet begrijp is waarom het niet werkt voor Time.now:

    >> Time.current.zone
    => "CEST" 
    >> Time.now.zone
    => "CEST" 
    

    Daarnaast werkt dit nog steeds heel raar:

    
    Time.now.to_i.is_a?(Integer) #=> true
    1.day.is_a?(Integer) #=> true
    (Time.now.to_i / 1.day).is_a?(Integer) #=> false
    

  3. Ariejan de Vroom zei ongeveer 16 uur later:

    Oh, dat is inderdaad wel nasty! Gelukkig nog geen last van gehad, maar goed om te weten. Thanks!

  4. Matthijs Langenberg zei ongeveer 18 uur later:
    >> Time.now.to_i.is_a?(ActiveSupport::Duration) #=> false >> 1.day.is_a?(ActiveSupport::Duration) #=> true
  5. Michiel zei ongeveer 18 uur later:

    Matthijs: Ik weet waarom het komt, maar 1.day lijkt, op een integer, beweert dat het een integer is, was vroeger een integer, maar wanneer je er een andere integer door deelt krijg je een float. Mijns inziens is dat gewoon een bug.

(Laat url/e-mail achter »)

   Voorvertoning