undefined method `zone` for Time:Class after requiring active_support/time_with_zone - ruby

I'm on Ruby 2.2.1 and have active_support 4.2 installed so I want to use
Time.zone.parse('2007-02-10 15:30:45')
as described here: http://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html
But even after requiring active_support and active_support/time_with_zone, I doesn't seem like Time.zone still doesn't work. Observe:
2.2.1 :002 > require "active_support"
=> true
2.2.1 :003 > Time.zone
NoMethodError: undefined method `zone' for Time:Class
2.2.1 :004 > require "active_support/time_with_zone"
=> true
2.2.1 :005 > Time.zone
NoMethodError: undefined method `zone' for Time:Class
What's going on?

The zone class method for the Time class is actually in active_support/core_ext/time/zones. You can require that class if you really want to use Time.zone but a better approach might to require active_support/all
Suggested Solution
require "active_support/all"
If you want to check out the source code fort for active_support look at the github repo

active_support/time_with_zone provides the ActiveSupport::TimeWithZone class, but it doesn't extend the core Time class.
You can require active_support/time instead:
require 'active_support'
require 'active_support/time'
Time.zone = 'Eastern Time (US & Canada)' #=> "Eastern Time (US & Canada)"
Time.zone.parse('2007-02-10 15:30:45') #=> Sat, 10 Feb 2007 15:30:45 EST -05:00

Try
require 'active_support/all'
instead of
require "active_support"

Related

NoMethodError: undefined method `yesterday' for Date:Class

Every answer posted on SO (yes, I checked) seems to have require 'date' as a solution. I've done that and my code still won't work.
require 'date'
yesterday = RepSched::Helpers.datestring(Date.yesterday)
For some reason, Ruby chokes on Date.yesterday
NoMethodError: undefined method `yesterday' for Date:Class
What am I doing wrong?
edit
Oh no! Now my problem is bigger than I thought. Now that I've realized that issue, I realize DateTime's behavior is different too!
yesterday is provided by Rails / Active Support. You can either require it in your non-Rails project:
require 'active_support/core_ext/date/calculations'
Date.yesterday
#=> #<Date: 2014-09-02 ((2456903j,0s,0n),+0s,2299161j)>
Or calculate it yourself:
require 'date'
Date.today - 1
#=> #<Date: 2014-09-02 ((2456903j,0s,0n),+0s,2299161j)>
Rails can be a bit of a pain because it adds new methods to Date which surprises many newcomers to Ruby. You can get yesterday, without using Rails by doing:
$ pry
[1] pry(main)> require 'date'
=> false
[2] pry(main)> Date.today
=> #<Date: 2014-09-03 ((2456904j,0s,0n),+0s,2299161j)>
[4] pry(main)> Date.today - 1
=> #<Date: 2014-09-02 ((2456903j,0s,0n),+0s,2299161j)>

Setting up Time.zone in Padrino

I am having a trouble setting the default ActiveSupport::TimeZone in my padrino project.
In my boot.rb I have
Padrino.after_load do
Time.zone = 'UTC'
ActiveRecord::Base.default_timezone = :utc
end
My controller file has:
MyApp::App.controllers :post do
get :index do
puts Time.zone # this returns nil
render 'index'
end
end
When I hit the index action I get nil for Time.zone. It seems as though something might be overwriting Time.zone or it isn't loaded properly.
I am able to print out the Timezone after setting it in boot.rb. So I know it was set.
You can set it like this:
Time.zone_default = Time.find_zone!("UTC")
That's all you need, but see below for details.
The above worked for me with activesupport 5.0.2. I looked at how Time.zone is implemented:
class Time
include DateAndTime::Zones
class << self
attr_accessor :zone_default
# Returns the TimeZone for the current request, if this has been set (via Time.zone=).
# If <tt>Time.zone</tt> has not been set for the current request, returns the TimeZone specified in <tt>config.time_zone</tt>.
def zone
Thread.current[:time_zone] || zone_default
end
I then guessed that it might be missing in the current thread with Padrino.
Presumably Time.zone would need to be set once for each thread. For whatever reason, that's not always the case when assigning the zone in Padrino.before_load. I did not dig into this, but I'm sure there's a nicer solution to be found that assigns it in each thread.
If you want per-user time zones, not just a global one for the entire app, you will need to dig further.
In my boot.rb I've got:
Padrino.before_load do
Time.zone = 'UTC'
end
and in my database.rb:
ActiveRecord::Base.default_timezone = :utc
Which having tested in the console seems to work:
ruby-2.1.4$ padrino c
=> Loading development console (Padrino v.0.12.4)
2.1.4 :001 > Time.zone
=> #<ActiveSupport::TimeZone:0x007fbff62ed5c0 #name="UTC", #utc_offset=nil, #tzinfo=#<TZInfo::TimezoneProxy: Etc/UTC>, #current_period=#<TZInfo::TimezonePeriod: nil,nil,#<TZInfo::TimezoneOffset: 0,0,UTC>>>>
2.1.4 :002 > Time.zone.now
=> Tue, 30 Dec 2014 13:14:57 UTC +00:00
2.1.4 :003 > Time.current
=> Tue, 30 Dec 2014 13:15:01 UTC +00:00
2.1.4 :004 > ActiveRecord::Base.default_timezone
=> :utc
N.B. Tested with ruby v2.1.4, padrino v0.12.4, activesupport/activerecord v4.2.0.

NoMethodError: undefined method `zone' for Time:Class

How do i use Time.zone in ruby if I am not using rails
I want to do Time.now but that's available in rails but not ruby
I thought that
require 'time'
would fix this and make it available in ruby but it didn't and I get
NoMethodError: undefined method `zone' for Time:Class
I don't know, what do you mean. But I think it should work as below :
(arup~>~)$ pry --simple-prompt
>> Time.now
=> 2014-04-09 23:19:04 +0530
>> Time.now.strftime('%Z')
=> "IST"
>> Time.now.strftime('%z')
=> "+0530"
>> Time.now.zone
=> "IST"
Documentation : #strftime and #zone .
You've tried to use zone as if it were a class method (Time.zone) [1]. If you want to use a class method:
1.9.3-p448 :007 > Time.now.zone
=> "EDT"
But Time.now is just a nice way of instantiating your own instance of Time[2]. So you're really just doing this (calling an instance method):
1.9.3-p448 :009 > time = Time.new
=> 2014-04-09 15:14:01 -0400
1.9.3-p448 :010 > time.zone
=> "EDT"
[1] http://www.railstips.org/blog/archives/2009/05/11/class-and-instance-methods-in-ruby/
[2] http://ruby-doc.org/core-1.9.3/Time.html#method-c-now

Why is Ruby's Date class automatically loaded but DateTime is not?

Using IRB, why are the Date & Time classes automatically loaded, but DateTime is not? I have to require 'date', this does not make sense to me because I thought that both Date and DateTime were using the standard library 'date'?
ruby-1.9.2-p290 :001 > Date
=> Date
ruby-1.9.2-p290 :002 > Time
=> Time
ruby-1.9.2-p290 :003 > DateTime
NameError: uninitialized constant Object::DateTime
from (irb):3
from /Users/kamilski81/.rvm/rubies/ruby-1.9.2-p290/bin/irb:16:in `<main>'
ruby-1.9.2-p290 :004 > require 'date'
=> true
ruby-1.9.2-p290 :005 > require 'date'
=> false
ruby-1.9.2-p290 :006 > DateTime
=> DateTime
In IRB, include this line: require 'date' then you will be able to use DateTime.
irb(main):000:0> DateTime.class
NameError: uninitialized constant DateTime
from (irb):0
from /path/to/ruby/irb:12:in '(main)'
irb(main):001:0> require 'date'
=> true
irb(main):002:0> DateTime.class
=> Class
Worked for me when first initializing with require 'date'.
Being a little more curious, I tried:
$ ruby -e 'puts DateTime.class'
-e:1:in `<main>': uninitialized constant Object::DateTime (NameError)
[~, kamilski81#mac]
$ ruby -e 'puts Date.class'
-e:1:in `<main>': uninitialized constant Object::Date (NameError)
$ ruby -e 'puts Time.class'
Class
So it makes me think that it's an irb issue that automatically loads 'date'.

Default TimeZone with ActiveSupport (without Rails)

How does the default TimeZone get set in ActiveSupport?
Here's what's happening:
irb -r 'rubygems'
ruby-1.8.7-p174 > require 'active_support'
ruby-1.8.7-p174 > require 'active_support/time_with_zone'
ruby-1.8.7-p174 > Time.zone
ruby-1.8.7-p174 > nil
How do I set that to the current location by default?
in rails it gets set in environment.rb via the rails initializer
Rails::Initializer.run do |config|
config.time_zone = 'Pacific Time (US & Canada)'
# ...
I just did a test and when the config.time_zone is commented out Time.zone will also return nil in the rails project; so I guess there is not a 'default' it just gets set in the initializers
Guessing you already know this will 'work'?
irb -r 'rubygems'
ruby-1.8.7-p174 > require 'active_support'
ruby-1.8.7-p174 > require 'active_support/time_with_zone'
ruby-1.8.7-p174 > Time.zone
ruby-1.8.7-p174 > nil
ruby-1.8.7-p174 > Time.zone = 'Pacific Time (US & Canada)'
ruby-1.8.7-p174 > Time.zone
=> #<ActiveSupport::TimeZone:0x1215a10 #utc_offset=-28800, #current_period=nil, #name="Pacific Time (US & Canada)", #tzinfo=#<TZInfo::DataTimezone: America/Los_Angeles>>
Note: above code is using rails 2.2.2 things maybe be different with newer versions?
editors note: In rails >= 3.0 all monkey patches have been moved to the core_ext namespace, so the above require does not extend Time. For later ActiveSupport versions use the following:
require 'active_support/core_ext/time/zones'
You can set the timezone with values from 2 sources, its own ActiveSupport short list (~137 values, see ActiveSupport::TimeZone.all to fetch them) or from the IANA names (~ 590 values). In this last case you can use the tzinfo gem (a dependency of ActiveSupport) to get the list or to instance a TZInfo::TimezoneProxy :
e.g.
ActiveSupport::TimeZone.all.map &:name
Time.zone = ActiveSupport::TimeZone.all.first
Time.zone = ActiveSupport::TimeZone.all.first.name
Time.zone = ActiveSupport::TimeZone.new "Pacific Time (US & Canada)"
Time.zone = ActiveSupport::TimeZone.find_tzinfo "Asia/Tokyo"
List all countries, all timezones:
TZInfo::Country.all.sort_by { |c| c.name }.each do |c|
puts c.name # E.g. Norway
c.zones.each do |z|
puts "\t#{z.friendly_identifier(true)} (#{z.identifier})" # E.g. Oslo (Europe/Oslo)
end
end

Resources