TimeZone helper methods...

I was having a bitch of a time trying to set these new TZ aware
attributes from a string. I've added this helper method to my app, and
thought there might be some interest in adding it to the core.

It parses a time string and returns a proper time instance set in the
right zone. I'm calling it Time.parse_with_zone

Thoughts?

module ActiveSupport #:nodoc:
  module CoreExtensions #:nodoc:
    module Time #:nodoc:
      # Enables the use of time calculations within Time itself
      module Calculations
        module ClassMethods

          def parse_with_zone(time_str)
            d = parse(time_str)
            t = utc_time(d.year, d.month, d.day, d.hour, d.min)
            begin
              result = zone.local_to_utc(t)
            rescue TZInfo::PeriodNotFound
              t += 1.hour
              retry
            end
            result.in_time_zone(self.zone)
          end

        end
      end
    end
  end
end

Time.zone.parse() should do the trick.

...better docs and a thorough writeup of the new time zone features
coming soon. In the meantime, here's a quick overview of the api:

Rails initializer option for turning on ActiveRecord's automatic time
zone conversions for datetime/timestamp columns, and setting a default
zone for Time.zone (which can be overridden per request, if
necessary):

  # No need to set config.active_record.default_timezone when you set
this:
  config.time_zone = 'Eastern Time (US & Canada)'

Set Time.zone per request:

  class ApplicationController < ActionController::Base
    before_filter :set_time_zone

    protected
      def set_time_zone
        Time.zone = current_user.time_zone
      end
  end

Methods for creating TimeWithZone instances in Time.zone:

  Time.zone.local(*values)
  Time.zone.at(secs)
  Time.zone.parse(str)
  Time.zone.now
  Time.zone.today #returns a Date instance

  Time#in_time_zone
  Time#in_time_zone("Alaska") #use this zone instead of Time.zone

Opt out of automatic time zone conversions for specific ActiveRecord
model attributes:

  class Task < ActiveRecord::Base
    skip_time_zone_conversion_for_attributes = :alert_at, :alert_at2
  end

That doesn't work for me because I'm using TZInfo::Timezones

There is no parse for that class AFAIK. Since Rails accepts that as a
zone, it'd be nice if you included that method for those of us stuck
on TZInfo::Timezone.

Unless there's a way to automatically convert that to a Rails TimeZone
object when setting Time.zone? Might be a better idea...

Unless there's a way to automatically convert that to a Rails TimeZone
object when setting Time.zone? Might be a better idea...

That's not a bad idea -- the Time.zone setter method could wrap
TZInfo::Timezone instances in a Rails TimeZone object, and that would
allow you to use parse, local, at, now and today methods, plus any
other methods that we might add to TimeZone instances in the future.
Should be easy enough to implement this.

Opt out of automatic time zone conversions for specific ActiveRecord
model attributes:

  class Task < ActiveRecord::Base
    skip_time_zone_conversion_for_attributes = :alert_at, :alert_at2
  end

...correction, the call to skip_time_zone_conversion_for_attributes
needs to have an explicit +self+:

class Task < ActiveRecord::Base
  self.skip_time_zone_conversion_for_attributes
= :alert_at, :alert_at2
end

That would save a ton of headaches. A lot of these issues I've run
into seem to be because of TZInfo::LinkedTimezone / TZInfo::Timezone.
Wrapping that class would be beautiful.

I'd make the switch to TimeZone but I can't seem to find a proper
translation for the identifier strings already stored in my DB. I'm
willing to bet a lot of other people are in the same boat.

Please keep us posted...

I'd make the switch to TimeZone but I can't seem to find a proper
translation for the identifier strings already stored in my DB. I'm
willing to bet a lot of other people are in the same boat.

You can find the mapping between TimeZone and TZInfo indentifiers in
the TimeZone::MAPPING hash. Converting over should be straightforward,
just be aware of the following:

1. TZInfo defines more zones than TimeZone does, so some TZInfo
identifiers have no TimeZone equivalent
2. some TZInfo identifiers map to more than one TimeZone (e.g.,
"America/Mexico_City" maps to both "Guadalajara" and "Mexico City")

That would save a ton of headaches. A lot of these issues I've run
into seem to be because of TZInfo::LinkedTimezone / TZInfo::Timezone.
Wrapping that class would be beautiful.

Added in [9107] -- in addition to recognizing Rails TimeZone instances
and identifiers, Time.zone= now accepts a TZInfo::Timezone instance,
or a TZInfo/Olson identifier string (e.g., "America/New_York").
TZInfo::Timezones are then wrapped on the fly in a Rails TimeZone.

Glad you're putting the new time zone features through the paces --
keep us posted if you run into any more issues.

Geoff

Not sure where this comment should go, but a fresh rails command
generates a configuration in environment.rb that attempts :timezone=
on the Rails::Configuration object. (NoMethodError)
Result: rails does not generate a working app!

Make sure you have vendor/rails set to edge - (run rake rails:freeze:edge) - and you’ll be up and running.

Hi Chris:
Thanks for your reply, but I'm afraid I don't understand:
If I do:
1> gem install rails #( rails (2.0.2.9129)
2> rails mysite
3> cd mysite
4> (placeholder)
5> ruby script\about
(NoMethodError)

but if I insert in placeholder
4> rake rails:freeze:edge

I get a good result?

But why should the generator packed with the gem, generate edge-only
code?
I didn't really want to run on the edge.
Why would the gem-generator anticipate an edge installation?

Geoff, wanted to chime in and thank you for rolling that in.

I just upped to edge and tested with the new changes. Solved a few
bugs I've been having issues with for a looooooong time that were
maddening.

Great work on this.