Setting up Time.zone in Padrino - ruby

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.

Related

Time.zone works on API but not on workers

I'm building an API using Grape framework and I want to set default timezone for the whole app as UTC so that when I call Time.zone.now I get the proper time
My config/application.rb looks like:
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'api'))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'app'))
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'bundler/setup'
Bundler.require :default, ENV['RACK_ENV']
Time.zone = 'UTC'
require_rel '../app'
require_rel '../api'
require_rel '../lib'
require_rel 'initializers'
If I start it up through bundle exec rackup -p 3000 or bin/console and call Time.zone.now I get the proper time: Fri, 05 Apr 2019 00:47:23 UTC +00:00
Although, when I'm using a Sidekiq worker or something outside Rack itself (bundle exec sidekiq -r ./config/application.rb) and try to call p Time.zone, nil is returned and Time.current returns time with my timezone: 2019-04-04 21:48:57 -0300
, even though I'm requiring application.rb which contains Time.zone = 'UTC' statement
How do I set UTC timezone globally for my workers as well?
EDIT #1 - Worker Code
It's a simple worker: it just prints Time.now or Time.zone.now
module Cron
class Date
include Sidekiq::Worker
JOB_NAME = 'date_job'
def perform(start_date = 1.day.ago, end_date = Time.current)
p [Time.now, Time.current]
end
end
end
You can just introduce an ApplicationWorker and have all other workers inherit from that class. In this new parent class, you can do everything that all workers have in common.
When you have two workers like this
class FooWorker
include Sidekiq::Worker
def perform
# do something
end
end
class BarWorker
include Sidekiq::Worker
def perform
# do something else
end
end
then you can use inheritance like this:
class ApplicationWorker
include Sidekiq::Worker
Time.zone = 'UTC'
end
class FooWorker < ApplicationWorker
def perform
# do something
end
end
class BarWorker < ApplicationWorker
def perform
# do something else
end
end

irb returning NameError: uninitialized constant Date

ruby-v2.2.3 is supposed to have Date class preloaded into irb, however when I enter...
Date
NameError: uninitialized constant Date
from (irb):1
from /Users/noah/.rubies/ruby-2.2.3/bin/irb:11:in `'
Why should I have to require Date every single time if it's supposed to be preloaded into 2.2.3?
Date isn't listed as a core class in v2.2.3 or the current Ruby v2.3.1 core-classes, but Time is. Here's some IRb output:
$ irb -f
irb(main):001:0> Date.class
NameError: uninitialized constant Date
Did you mean? Data
from (irb):1
from /Users/ttm/.rbenv/versions/2.3.1/bin/irb:11:in `<main>'
irb(main):002:0> Time.class
=> Class
irb(main):003:0> Time.methods(false)
=> [:at, :now, :utc, :gm, :local, :mktime]
That is a limited subset of Time's methods though:
irb(main):002:0> require 'time'
=> true
irb(main):003:0> Time.methods(false)
=> [:at, :now, :utc, :gm, :local, :mktime, :parse, :zone_offset, :strptime, :rfc2822, :rfc822, :httpdate, :xmlschema, :iso8601]
Why do you say Date is preloaded? It's not a core class, it's part of the stdlib so it needs to be required. Time is a core class instead.
You can try to do the following in the beginning of your file:
require 'Date'
As far as I know, (and as Ursus said), Date is not preloaded.
Attention: So Tilec suggested to just load the library at the beginning of the file, which gave me (Not sure if that is true in general): this gave me LoadError: cannot load such file -- Date. Trying gem install Date gives me
ERROR: Could not find a valid gem 'Date' (>= 0) in any repository
ERROR: Possible alternatives: date
Solution: So I'm proposing to correct to lower case:
require 'date'

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

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"

How do I use this mixin to alter the DateTime object?

I need to alter the DateTime object. The resource I've found states that this is what I need to do, but I'm not sure exactly what to do with this code. Where do I put it? Thanks for reading.
module DateTimePatch
def getlocal
"works!"
end
end
DateTime.send(:include, DateTimePatch)
EDIT:
So this is what I have
/lib/date_time.rb
class DateTime
def getlocal
"it works"
end
end
Console
ruby-1.9.2-p0 > Time.now.getlocal
=> 2010-11-09 23:40:36 +1000
ruby-1.9.2-p0 > DateTime.now
=> Tue, 09 Nov 2010 23:40:57 +1000
ruby-1.9.2-p0 > DateTime.now.getlocal
NoMethodError: undefined method `getlocal' for Tue, 09 Nov 2010 23:41:02 +1000:DateTime
EDIT2:
Ok so now I'm doing:
ruby-1.9.2-p0 > require './lib/date_time.rb'
=> true
ruby-1.9.2-p0 > DateTime.now.getlocal
NoMethodError: undefined method `now' for DateTime:Class
from (irb):2
from /Users/benhartney/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>'
ruby-1.9.2-p0 > DateTime.now
NoMethodError: undefined method `now' for DateTime:Class
from (irb):3
from /Users/benhartney/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>'
I tried adding a temporary now method to the mixin to see if the error still occurred and it did. DateTime.now worked fine before I loaded the mixin, not sure why this is happening?
So, you want to add a method to the DateTime class ? Try:
class DateTime
def get_local
"works!"
end
end
Probably you forgot to require your file.
irb(main):002:0> DateTime.now.getlocal
NoMethodError: undefined method `getlocal' for #
from (irb):2
from d:/Ruby/bin/irb.bat:20:in `'
irb(main):003:0> require './lib/date_time.rb'
=> true
irb(main):004:0> DateTime.now.getlocal
=> "it works"
UPD: and require 'date' in order to use ruby's DateTime class.

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