Managing multiple users time zones in ruby on rails - ruby-on-rails

I want to save an event in a default time zone i.e. Whenever an user submits an event it will get convert to the default time zone and will be save in the database.
Whenever user requests for an event, the system will find that users time zone and convert the date (from the default format) in that user time zone and display it to the user.
I'm having difficult time where to start from i saw many notes and documents but couldn't figure it out the complete process of doing it.
I saw this code but couldn't understand how to use it :
before_filter :set_time_zone
def set_time_zone
Time.zone = current_user.time_zone if current_user
end

The default time zone in the database is UTC.
There are 2 ways you can do it:
Allow their user to store their time zone in the database
Grab their time zone from their IP
For option 1, Rails has very good support for time zones. The #all method will allow you to create a dropdown for them to choose from. Then save it in the database with the user record.
Option 2 is less work for the user, but is also less accurate. There are a few services that convert IP's to Time Zones.
To display the time in a given time zone, use Time#in_time_zone or you can set the Time.zone as above and it should display properly.

Related

Finding records across time zones using active record

I'm developing an app where a user can request that an email be sent to them at a specific time every day in their timezone.
For example User A lives in London and schedules an email at 2pm every day London time and User B lives in New York and schedules an email at 2pm New York time.
I'm wondering how I should store my schedule timestamps in my database and what supporting information I need to store along side this to support the fact that all times depend on a specific timezone.
I'm thinking that storing the timestamps as utc with a separate column for the timezone is the way to go but I'm unsure of how to query the database to return all scheduled emails at a specific time without having to perform one query per timezone.
Yes, store the data in UTC - rails will do this by default; put a time_zone column on your User model
Here is a post I wrote for timezones in rails which you might find helpful: http://jessehouse.com/blog/2013/11/15/working-with-timezones-and-ruby-on-rails/
This might be overly complicated, but I am thinking if you had a background job running (delayed_job, sidekiq, etc) it would check each timezone/email schedule - something like this (You definitely want time_zone on your User, maybe on the schedule as well?)
# loop through all timezones
ActiveSupport::TimeZone.zones_map(&:name).each do |time_zone|
# get a list of any saved schedules in this timezone
scheduled_in_zone = EmailSchedule.where(time_zone: time_zone)
# execute block in that timezone
Time.use_zone(time_zone) do
# Time.current is timezone aware (same as Time.zone.now)
now = Time.current
scheduled_in_zone.each do |scheduled|
if scheduled.deliver_at <= now
scheduled.deliver_it!
end
end
end
end
I also recommend checking out: http://railscasts.com/episodes/106-time-zones-revised

Rails seems to be creating objects in wrong time zone for created_at, updated_at values

I just created a new object using a form and its updated_at and created_at values are
created_at: "2013-04-25 03:22:19", updated_at: "2013-04-25 03:22:19",
However that is ~7 hours ahead of where I am (PST).
Time.now.to_s
=> "2013-04-24 20:23:12 -0700"
How can I make sure the time zone is consistent with wherever a user is creating it from?
Your created_at and updated_at values are written from your server to the database, so they will always be in your server's or application's time zone. By the time the server processes the form data and saves to your database, it has no knowledge of the browser's time zone.
You can set a Rails time zone using config.time_zone, as #lulalala suggested.
It sounds like you're interested in displaying times to your users in their native time zones. You have two options for this:
Ask your user for a time zone on signup (or assign a default one and allow users to edit it)
Detect time zone using javascript and report back to your server (http://josephscott.org/archives/2009/08/detecting-client-side-time-zone-offset-via-javascript/) - not guaranteed to be correct
Once you have the time zone saved as a user attribute, you can display your times to your users like this:
Model.created_at.in_time_zone(#current_user.time_zone)
I check irb timezone with the command > Time.now.to_s and the time was correct, but the app save it wrong by 3 hours. So..
The solution for me was add config.time_zone = "Santiago" to config/environments/development.rbfile. The time zone list is here, and my entry was
"Santiago" => "America/Santiago"

Rails: saving record from console with Timezone

I created a new object and saved the same through the console. I noticed that created_at and updated_at columns were in GMT format but when I do a Time.now in my console I get the time in my time zone. How can save my records from the console with my local time?
Rahul, Rails correctly goes out of its way to store dates in UTC (like GMT) format. I strongly advise against undoing this.
Rails (and ruby) provides Time.zone, Time.local and other methods that help you display the values in the correct local time. Your local time is determined by the settings of your system, but your local time isn't necessarily the same as that of other people using the system. Once you put this on a web server in the wild, people may be in different time zones. You can tell Rails which time zone to use by default in application.rb in this section
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
config.time_zone = 'Eastern Time (US & Canada)'
This might work OK for cases where most of your users are in the same timezone, but if you want users to be able to see date/times in their timezone, you'll probably want to store their zone in the User record. There's a time_zone_select helper to make it easy to capture that info.

Time.now.midnight's susceptibility to time zones

I have some daily analytics-style records that track usage on my site, and they work as follows:
When an 'event' occurs, the site looks for a record that was created at Time.now.midnight.
If such a record is not found, a new one is created, and created_at is set to Time.now.midnight.
Here's the question - does Time.now.midnight get recorded differently depending upon the client's time zone? If so, am I correct in assuming that the above very simple system will break down?
How can I fix it so all analytics records, irrespective of the time zone of the user who triggered their creation, get pegged to one time?
Note: I imagine that setting the created_at field to a Date instead of Datetime might have been better in this scenario. Let's assume we're stuck with datetime for this question.
Time.now does not get recorded differently based on the clients timezone.
Time.now returns a new time using the system timezone (aka the server)
To use a client specific timezone you have to have a user select their zone and use Time.current or Time.zone.now (which do the same thing)
created_at is usually pinned to UTC, so you shouldn't have any issues their either.
(to change this you need to change Rails.root/config/application.rb)
config.time_zone = "whatever you want the ActiveRecord default to be"

Row based Time Zones in Rails 2.3.4

What is the best way to handle the following situation:
We have "admins" who create "events". These events can be nationwide, ie: different time zones. As of now there is a select menu with the current list of US time zones. There is a corresponding column in the database table, for the time zone selected. This is so the admin can select 5PM Eastern, 5PM Pacific, etc. Instead of trying to figure out the GMT equivalent.
The application is using UTC as per the environment.rb file, as the default time-zone.
If an admin selects "Eastern Time (US & Canada)", the date stamp selected is still saved as UTC (or the app default). I need to perform queries where events don't show up before the time selected above including the time zone.
Since the events need their own time zone, how should the data be saved?
I was originally thinking I need to trick Rails before it saves the value, so it saves UTC offset for the time zone.
This would be handled in before_save and after_find model methods. But it doesn't seem to work, or rather I am missing something..
You're missing a simple fact. Time is universal. 1:00pm in UTC is 1:00pm in UTC anywhere. You don't even need to store a time_zone with every event. You just need to let admins select it for easier time input. As far as backend, it's always in UTC. You can certainly input time from different timezone, and output into different timezone, but it's still the same "1:00pm in London" no matter how you twist it. So when a user is looking at events, you can simply do event_date < Time.now.utc (all past events).
However, if the observing user is actually in a different timezone from the events, and you want to display event dates in the user's home timezone, then you can let user select their home timezone, and store it in users table. Then in before_filter on your ApplicationController you can just do:
class ApplicationController < ActionController::Base
before_filter :set_time_zone
private
def set_time_zone
Time.zone = current_user.time_zone if current_user
end
end
Then every Time value that comes from database (such as event.date) will be automatically converted in the user's home time zone.
Or maybe I misunderstood the question. : ) Let me know.

Resources