I've been over and over the documentation of the (otherwise) excellent Mysql2 gem.
I have a production Rails app hosted on a server running in UTC. The app's config.time_zone is set to "Eastern Time (US & Canada)."
We have an internal MS Access-headed application (which, thankfully, uses a MySQL DB) that the aforementioned Rails app connects to to sync product data, production schedules, etc. This MySQL server cannot be moved into the cloud due to the application's limitations, and -- needless to say -- we cannot change its timezone handling to UTC -- everything is in EST.
When I connect from our Rails app to our local database to retrieve data, Mysql2 (by default) casts all of the native data into digestible Ruby objects. However, the only way that I can get the Rails app to interpret dates correctly is to send :cast => false during the Mysql2 query command, and then, in the response handling, run Time.zone.parse( string ) on the results. This necessitates native Ruby object casting, which is far less efficient than the casting functions built in to the gem.
I tried passing the database_timezone and application_timezone options mentioned in the documentation, but the :local symbols do not have the intended effect of using the app's config.time_zone property.
thehost.query("SELECT NOW() AS n;", :symbolize_keys => true).each { |result| p result[:n] }
2015-05-19 16:28:41 +0000
thehost.query("SELECT NOW() AS n;", :symbolize_keys => true, :database_timezone => :local, :application_timezone => :local).each { |result| p result[:n] }
2015-05-19 16:30:11 +0000
thehost.query("SELECT NOW() AS n;", :symbolize_keys => true, :database_timezone => :utc, :application_timezone => :local).each { |result| p result[:n] }
2015-05-19 16:30:28 +0000
thehost.query("SELECT NOW() AS n;", :symbolize_keys => true, :database_timezone => :local, :application_timezone => :utc).each { |result| p result[:n] }
2015-05-19 16:30:57 UTC
thehost.query("SELECT NOW() AS n;", :symbolize_keys => true, :database_timezone => :utc, :application_timezone => :utc).each { |result| p result[:n] }
2015-05-19 16:31:19 UTC
Related
I am generating a report from my ruby on rails app that would run everyday at 7 in the morning.
This report would collect the results from the previous day.
So basically I want query previous day's results to my Mongo collection. This is what I am tried:
logs = Log.where(:comp => comp, :created_at => (Date.today -1))
I got the following error:
BSON::InvalidDocument: Date is not currently supported; use a UTC Time instance instead.
What is the best approach to get the aboce result:
This is the the format of my date in my db:
"created_at" : ISODate("2015-12-02T23:12:38.076Z")
You can do something like this in mongoid:
logs = Log.where(:comp => comp, :created_at.gte => (Date.today -1 ).to_datetime)
Date.to_datetime will default to midnight as shown here:
(Date.today - 1).to_datetime
=> Wed, 30 Mar 2016 00:00:00 +0000
I got two models Shift and ShiftDetail. I have a Shift model methods that adds ShiftDetails automatically:
def add_shift_details
(0..6).each do |i|
shift_detail = ShiftDetail.new
t1 = Time.now
shift_detail.weekday = i
shift_detail.start_time = t1.beginning_of_day
shift_detail.end_time = t1.end_of_day
self.shift_details << shift_detail
end
end
But when i save the instance the database is populated with
["start_time", "2016-03-02 23:00:00.000000"]
["end_time", "2016-03-03 22:59:59.999999"]
I am using Rails 4.2.5.1 and ruby 2.3.0p0
What am I doing wrong?
UPDATE:
When I test it in 'rails c', it works as expected:
2.3.0 :001 > Time.now.beginning_of_day
=> 2016-03-03 00:00:00 +0100
2.3.0 :002 > Time.now.end_of_day
=> 2016-03-03 23:59:59 +0100
Your database stores DateTime in the UTC timezone while Rails works with the Berlin timezone. Berlin's midnight (GMT+1) is not equal with UTC's (GMT) midnight :)
You have two options:
Have your algorithm work with an UTC timezone
You can use Time.now.utc or DateTime.now.new_offset(0)
Have your database store dates in your specific timezone (Berlin's in this case). I highly advise not to do this.
Check out this post for more information:
https://stackoverflow.com/a/32229086/4304188
I have set my server time on UTC and and my production.rb to config.time_zone = 'Pacific Time (US & Canada)' as my app is using Pacific time.
In ruby console, Time.now is showing UTC and not Pacific!
Is this normal?
How to make sure my app is using PST?
Thanks!
Mel
I had my own confusion when using timezones in Ruby without Rails and then I discovered an article that shed some clarification. Ruby is packaged with the Date and Time classes. These classes exist without Rails:
require "time"
Time.parse("Dec 8 2015 10:19")
#=> 2015-12-08 10:19:00 -0200
Date.parse("Dec 8 2015")
#=> #<Date: 2015-12-08>
Time.new(2015, 12, 8, 10, 19)
#=> 2015-12-08 10:19:00 -0200
Date.new(2015, 12, 8)
Ruby by default uses the timezone defined in /etc/localtime on Unix-like systems, unless you modify the TZ environmental variable like so:
ENV["TZ"] = 'US/Eastern'
It is recommended to do this if your system time is not UTC time, then you can change the environment to UTC:
Time.now
=> 2018-03-29 20:17:39 -0400
ENV['TZ']
=> nil
ENV['TZ'] = 'UTC'
=> "UTC"
Time.now
=> 2018-03-30 00:17:59 +0000
Now I know that Rails has its own configuration, which you may find in application.rb:
config.time_zone = 'Eastern Time (US & Canada)'
config.active_record.default_timezone = :local
Rails will use this time zone configuration in your application, and it will ignore the TZ environment variable or even your system defaults.
But what you need to understand is Ruby will ignore the Rails timezone configuration, even within the context of the Rails environment! So then how do you take advantage of the Rails configuration and not the Ruby configuration? Rails has its own methods defined in ActiveSupport. These methods will generate date and time objects from the ActiveSupport::TimeWithZone. But you need to understand how to use these methods:
Use Time.current instead of Time.now.
Use Date.current instead of Date.today.
And the example:
rails c
Time.now
=> 2018-03-29 20:20:14 -0400
ENV['TZ']
=> nil
ENV['TZ'] = 'UTC'
=> "UTC"
Time.now
=> 2018-03-30 00:20:35 +0000
Time.current
=> Thu, 29 Mar 2018 20:20:40 EDT -04:00
I am in the Central timezone (ENV['TZ'] = America/Chicago) but all my MongoDB entries are stored in UTC format. So if I want to query entries for all of yesterday, I have to overcompensate for the timezone:
tz = 5.hours
d1 = Date.yesterday.at_midnight + tz
d2 = d1 + 1.day
Entry.where(:created_at.gte => d1, :created_at.lt => d2)
I'm pretty sure that this is a major hack, but I'm not sure how to fix this correctly? Should it be on the database end, or in the code. Are there some reading resources that teach how to do this correctly?
Assuming that your Rails application is configured to use UTC (see config.time_zone in config/application.rb) then you should be able to use Time.zone... to build your dates.
I'm in Pacific time, my app is in UTC:
> Time.now
=> 2013-09-10 15:14:46 -0700
> Time.zone.now
=> Tue, 10 Sep 2013 22:14:48 UTC +00:00
I don't know about Mongoid, but ActiveRecord will do this for you:
> Course.where(['created_at < ?', Time.now]).to_sql
=> "SELECT \"courses\".* FROM \"courses\" WHERE (created_at < '2013-09-10 22:16:27.106841')"
> Course.where(['created_at < ?', Time.zone.now]).to_sql
=> "SELECT \"courses\".* FROM \"courses\" WHERE (created_at < '2013-09-10 22:17:03.236353')"
I have a simple Rails 3.b1 (Ruby 1.9.1) application running on Sqlite3. I have this table:
create_table :time_tests do |t|
t.time :time
end
And I see this behavior:
irb(main):001:0> tt = TimeTest.new
=> #<TimeTest id: nil, time: nil>
irb(main):002:0> tt.time = Time.zone.now
=> Mon, 03 May 2010 20:13:21 UTC +00:00
irb(main):003:0> tt.save
=> true
irb(main):004:0> TimeTest.find(:first)
=> #<TimeTest id: 1, time: "2000-01-01 20:13:21">
So, the time is coming back blank. Checking the table, the data looks OK:
sqlite> select * from time_tests;
1|2010-05-03 20:13:21.774741
I guess it's on the retrieval part? What's going on here?
Technically, it's not coming back blank. It comes back as a time with a default date. It returns 2000-01-01 20:13:21 as the time, which is expected.
Rails is doing some magic loading of the data into a Time object and clearing out the date (since you only told it to store the time).
If you want to store the date and time then you need to define the column as a datetime. And conversely, if you wanted just a date you would use date.
So to recap:
date => "2010-12-12 00:00:00"
time => "2000-01-01 13:14:15"
datetime => "2010-12-12 13:14:15"