Rails Date and Time user entered isn't in UTC - ruby-on-rails

I've looked through a lot of issues like this but none seem to correspond to my issue, which is:
I have a Rails app that contains events. Event is a model that has attributes for start date (Date field), start time (Time) and end time (Time). When I created them, I didn't convert any of the entered dates to UTC based times (all times local).
I'm trying to find out if the event is over. I've added a few methods to my model that should help with this, but because I'm comparing Apples (non-UTC) to Oranges (UTC) time. I'm running into a brick wall.
Because I'm mixing Date and Times, I've added the following methods to my Event model:
helpers
def date_start_time
return DateTime.new(self.date.year, self.date.month, self.date.day, self.start_time.hour, self.start_time.min, self.start_time.sec)
end
def date_end_time
return DateTime.new(self.date.year, self.date.month, self.date.day, self.end_time.hour, self.end_time.min, self.end_time.sec)
end
in_past method
def in_past
logger.debug 'comparing end time: ' + self.date_end_time.to_s + ' to the current time: ' + DateTime.now.to_s
self.date_end_time <= DateTime.now
end
I'm loading an event in Rails Console that should end in a few minutes, but I'm getting a true to in_past:
1.9.3-p194 :020 > event.in_past
comparing end time: 2013-08-19T20:38:00+00:00 to the current time: 2013-08-19T20:37:22-05:00
=> true
I've tried adding .zone to my DateTime.now, but that makes it worse it seems. I feel like I've tried every combination of Zone options here and really I'd just prefer to ignore time zones since all events are currently local.
Thoughts? Suggestions?

The quick solution to this is add timezone to rails config (application.rb) like this
config.time_zone = '<your local timezone>'
You can get all the available timezones by
#rake time:zones:all

Related

Rails - How to save datetimes correctly in MongoID and trigger them with whenerver (cronjobs)?

I try to save datetimes into events in MongoDB with Mongoid. The difficulty is that I want to save them for different timezones (e.g. Berlin and London). I want the user (admin) to see the actual time in the timezone so that he does not need to calculate. Afterwards I have a cron job in whenever, which looks every minute for an event to process.
I have the following parameters:
application.rb (I tried without -> standard UTC -> London is ok, Berlin wrong hour)
config.time_zone = 'Berlin' # as the server stays in Germany
mongoid.yml (tried all combinations, need use_activesupport_time_zone to get correct times int oDB though)
use_activesupport_time_zone: true
use_utc: false
schedule.rb (no problem here so far)
every 1.minutes do
runner "Event.activate_due", environment: 'development'
end
event.rb (not sure for which times I am looking now)
def self.activate_due
events_due = Event.where(:eventStart.lte => (Time.now + 1.minute), :eventStart.gte => (Time.now))
events_due.each do |e|
e.activate
end
end
I tried to change the Time.zone in events#new in order to depict the timezone's actual time in the simple_form. It seems to work, but then the controller create method seems to treat the params as standard time zone again and transforms it wrongly (+-1hour when experimenting with London/Berlin). I tried out almost every parameter combination and also Time.now/Time.zone.now.
In event#index I switch through time_zones in order to show the right time.
To complicate things a bit: I save the timezone in the area model, which is connected through areaId with the event model.
How would I show the admin in the form the correct time for the event in the zone he wants to add (not his timezone) and save it correctly in Mongo to trigger it through the cronjob later?
Try the following
def self.activate_due
events_due = Event.where(
:eventStart.to_utc.lte =>(Time.now.to_utc),
:eventStart.to_utc.gte => (1.minute.ago.to_utc))
events_due.each do |e|
e.activate
end
end
Plesse note that this will work with UTC times, so if you have an event in UTC - 7 timezone don't think it will get activated now if the server timezone is UTC + 2

Rails - Getting datetime_select into user timezone for model validation

I tried to get this answered with no luck so I'll try again.
I've implemented the railcast timezone goodies to allow the user to set their time zone. It works. Time.zone.now gives the correct time zone. It's in here
http://stevenyue.com/2013/03/23/date-time-datetime-in-ruby-and-rails/
I have events and have been trying to get the datetime_select in my form to give me a time that is also in the user's time zone.
My goal is to be able to compare it to current time (Time.zone.now) to validate that the start time is not before current time. And eventually end time > start time etc.
I've tired several ways including this one with no luck...
This one - he answered his own question later (is exactly my problem)
Rails datetime_select posting my current time in UTC
def start_date_cannot_be_in_the_past
if date_start.in_time_zone(Time.zone) < Time.zone.now
errors.add(:date_start, "has already passed")
end
end
The above doesn't seem to work because you can't extract date_start just like that. It's separated into different components, so I tried to do something like this
def start_date_cannot_be_in_the_past
date = DateTime.new(params[event][date_start(1i)].to_i, params[event][date_start(2i)].to_i, params[event][date_start(3i)].to_i, params[event][date_start(4i)].to_i, params[event][date_start(5i)].to_i)
if date.in_time_zone < Time.zone.now
errors.add(:date_start, "has already passed")
end
end
In my model I can't access params so I don't know how to get this to work...
I want to move to a jquery calendar/time picker if possible as I can't seem to get this work.. but any suggestions on alternatives or on this is appreciated..
Make sure you have this line in your model:
validate :start_date_cannot_be_in_the_past
and then this method can be something like:
private
def start_date_cannot_be_in_the_past
errors.add(:date_start, "has already passed") if self.date_start < Time.zone.now
end
See this for more information.

Get hour from user and store in rails model + timezone

I have a rails view where the user is presented with a dropdown displaying the hours '00:00', '01:00' etc.
Once the user has selected this hour, then it is stored in the model with some other fields.
My application is working in timezone UTC+2 (I have set config.time_zone = 'Jerusalem').
At what stage to I related to timezones when handling this time on its path from the view to the model? If I use e.g. DateTime.strptime("10:00", "%H:%M").in_time_zone(Time.zone), then I get a time at '12:00' - while what I really would like is for the database to store in UTF (which should be 08:00 while the rest of the site works with local time.
You can use TZInfo ruby library http://tzinfo.rubyforge.org and convert your time with following method
def local_to_utc(date, time_zone)
begin
unless time_zone.nil?
tz = TZInfo::Timezone.get(time_zone)
return tz.local_to_utc(date)
end
rescue
return nil
end
end

How to save dates in local timezone to db with rails3?

I have Rails3 application with model user and field expires_at created like this:
t.column :expires_at, :timestamp
In my database (postgresql) it has type:
timestamp without timezone
The problem is when I call:
#user.expires_at = Time.now
#user.save
it is saved into database with UTC timezone (my local time is UTC + 1:00, Warsaw) but I don't want that. I just want to have time with my local timezone saved into the database (2011-03-30 01:29:01.766709, not 2011-03-29 23:29:01.766709)
Can I achieve this using rails3?
For saving time in local timezone to database this has to be set in application.rb
config.active_record.default_timezone = :local
If you only want to use local times on certain columns, rather than as a global setting, then the Rails documentation tells us this:
# If your attributes are time zone aware and you desire to skip time zone conversion to the current Time#zone when reading certain attributes then you can do following:
class Topic < ActiveRecord::Base
self.skip_time_zone_conversion_for_attributes = [:written_on]
end
(This also skips time zone conversion on writing, not just reading). And you can pass in an array of symbols for multiple attributes.
I am not sure which versions of Rails this was introduced in, though.

How do I work with Time in Rails?

I've been pulling my hair out trying to work with Time in Rails. Basically I need to set all time output (core as well as ActiveSupport) to the server's local time -- no GMT, no UTC, etc. I've seen various posts relating to Time, but they usually involve someone's need to set it for each user. Mine isn't nearly as complex, I simply want consistency when I use any Time object. (I'd also appreciate not receiving errors every 3 seconds telling me that I can't convert a Fixnum (or some other type) to string -- it's Ruby, just do it!)
I also seem to be getting drastically different times for Time.new vs the ActiveSupport 1.second.ago. Anyway, does anyone have any quality suggestions as regards working with Time in Rails?
If you just want Time objects to be consistent, then why not stick with UTC? I just tried Time.new and 1.second.ago using script/console and I get the same output (give or take a second for typing the command). How are you doing it?
Somewhere in your initializers, define the format(s) that you want to use.
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(:default => '%m/%d/%Y %H:%M')
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(:my_special_format => '%H:%M %p')
Then when you want to print a Time object, it works like the following example. Notice that the Time object in my console is already aware of my time zone. I'm not performing any magical transformations here.
>> t = Time.now
=> Wed Jul 15 18:47:33 -0500 2009
>> t.to_s
=> "07/15/2009 18:47"
>> t.to_s(:my_special_format)
=> "18:47 PM"
Calling Time#to_s uses the :default format, or you can pass in the name of the format you'd rather use like I did with :my_special_format.
You can see the various options for formatting a Time object here.
If u don't want to store each user time setting, the only solution is to use javascript time system because it work on user client time. For example i have an application that each time user try it, the app will create some example data with each data have a initial date value "today". At first time, it confuse me a lot because my host server is in australia and lot of user is on western part, so sometime the initial date value is not "today", it said "yesterday" because of different time region.
After a couple day of headache i finally take decision to JUST use javascript time system and include it in the link, so when user click the "try now" link it will also include today date value.
<% javascript_tag do -%>
var today = new Date();
$("trynow").href = "<%= new_invitation_path %>?today=" + today.toLocaleString();
<% end -%>
Add the following to config/environment.rb to handle time correctly and consistently all the time within the context of Rails. It's important to know that it will store your times to the database in UTC -- but this is what you want -- all the conversion is done automatically.
config.time_zone = 'Pacific Time (US & Canada)'
You can run rake time:zones:local from your Rails root directory to get a list of valid time zone strings in your area.
A quick addition to the DATE_FORMAT solution posted above. Your format can be a string, in which case it works as noted above by calling strftime, but you can also define the format as a lambda:
CoreExtensions::Time::Conversions::DATE_FORMATS.merge! :my_complex_format => lambda {|time|
# your code goes here
}

Resources