Rails 4 - how to set a timezone for strftime? - ruby-on-rails

Every user in our database can select his/her own timezone. The default timezone of our application Eastern Time:
config.time_zone = 'Eastern Time (US & Canada)'
config.active_record.default_timezone = 'Eastern Time (US & Canada)'
When I display some dates/times in the application, I usually use for that purpose .strftime. How can I give a parameter to strftime to display the date/time properly (in the given timezone for the specific user)?
Or is there a better way than to format every date/time with using strftime?
EDIT:
Every user has a time_zone string column, where is stored the timezone like this: "Eastern Time (US & Canada)".
As the every date/time will be re-calculated for every timezone, how about the performance? Will this not slow down too much rendering views?

Set your time object in_time_zone() before strftime.
Say you're displaying created_at, you'd do:
object.created_at.in_time_zone(current_user.timezone).strftime("...")

Related

Parsing a TimeZone name string that includes GMT offset hours

I did find this question but I am still stumbling around looking for a simple solution to the following:
An API call returns the following format which looks like they are using Time.zone.to_s
irb> ShopifyAPI::Shop.current.timezone
=> "(GMT-08:00) Pacific Time (US & Canada)"
I would like to parse the "(GMT-08:00) Pacific Time (US & Canada)" into a Ruby class and output the TimeZone name "Pacific Time (US & Canada)"
Alternately I could just strip the "(GMT-08:00)" offset and be left with a clean TimeZone name "Pacific Time (US & Canada)" but this seems like a messy string editing solution.
ShopifyAPI::Shop.current returns properties documented here. Yes, timezone is one of them, but it is intended to be a display name, not something you should parse.
Instead, use the iana_timezone property, which will give you the IANA time zone identifier, such as America/Los_Angeles. These are compatible with Rails, as well as Ruby's tzinfo gem, and also are used in many other platforms.
irb> ShopifyAPI::Shop.current.timezone
=> "(GMT-08:00) Pacific Time (US & Canada)"
irb> ShopifyAPI::Shop.current.iana_timezone
=> "America/Los_Angeles"
If you want to get a Rails time zone from there, you can use the MAPPING constant defined in ActiveSupport::TimeZone. Though I'd avoid it if possible, for the reasons mentioned in the timezone tag wiki in the "Rails Time Zone Identifiers" section at the bottom.
If you are confident about the API and string format you are going to receive, you can manipulate string as
string.partition(')').last.strip
# => Pacific Time (US & Canada)

How to set the timezone to EST throughout the rails app?

I want to use EST throughout the app. I have set the
config.time_zone = 'Eastern Time (US & Canada)'
config.active_record.default_timezone = 'Eastern Time (US & Canada)'
what I want is, I have to get all the time I have used like "DateTime.now" and it now returns time in my local timezone but I want it to return date time in EST. Also I have date time range picker and I get the start date and end date and parse the string to time using
(params[:start_date]).to_time
which also returns the date time in local zone and instead i want all those to return in EST. How can I do this? Any help is appreciated.
Thanks in advance.
DateTime.now and Time.now doesn't respect Time.zone and will always use the server time. If the machine you're using is set to a different timezone, these 2 will use that timezone.
to_time on the other hand defaults to local timezone as mentioned in apidock (although just tried this out and I get utc by default). To get these times in the timezone set, append in_time_zone
DateTime.now.in_time_zone
Time.now.in_time_zone
string.to_time.in_time_zone
There are some shortcuts for these though. The following code will return the timestamps in the current timezone
Time.zone.now
Time.zone.parse(string)
Normally, in database date-time would be saved in UTC format unless you have selected a specific TimeZone for Active Record and it would be easier if you have to meddle with multiple TimeZones. But, while you access the values you will get the values in you selected TimeZone.
config.time_zone = 'Eastern Time (US & Canada)
Now, suppose you have a datetime value in UTC from table as
datetime1 = "2014-08-25 10:25:57 +0000"
You can convert it to the selected timezone 'Eastern Time (US & Canada)' as below,
Time.zone.parse(datetime1) => Mon, 25 Aug 2014 06:25:57 EDT -04:00
Then, if you need it in a proper format, use method strftime.
Time.zone.parse("2014-08-25 10:25:57 +0000").strftime("%d-%m-%Y %H:%M:%S") => "25-08-2014 06:25:57"
Hoep it helps :)

Rails parse datetime in model

I'm getting datetime string from the form and the example value is below:
2014-02-21 13:00:00
I want to be able to convert this into datetime before it gets saved in the model.
Is there a way to do this as Rails 4 seems to put wrong date in there automatically when it gets saved
Adding your timezone as default in application.rb like below should do the trick:
config.time_zone = 'Eastern Time (US & Canada)'
config.active_record.default_timezone = 'Eastern Time (US & Canada)'
Try
Time.zone.parse("2014-02-21 13:00:00")
instead of
Time.parse("2014-02-21 13:00:00")
as the latter will "assume the string is given in the system's time zone"
Source and more about the topic
Try this to_time or to_date_time method.
It convert string into date time format
"2014-02-21 13:00:00".to_time
"2014-02-21 13:00:00".to_datetime

Trouble on handling cookie data with time zones

I am using Ruby on Rails 4 and I would like to handle data present in cookies the proper way. That is, when I store to cookie data as-like (GMT-06:00) Central Time (US & Canada)
cookies.permanent[:time_zone] = "(GMT-06:00) Central Time (US & Canada)"
then in the cookie content it is stored %28GMT-06%3A00%29+Central+Time+%28US+%26+Canada%29.
That way, when I use the cookies[:time_zone] data in my code
Time.use_zone(cookies[:time_zone], &block)
then I get ArgumentError Invalid Timezone: (GMT-06:00) Central Time (US & Canada).
I think the problem is due to the fact that the cookies[:time_zone] data is read from cookies "as it is" (%28GMT-06%3A00%29+Central+Time+%28US+%26+Canada%29), so it generates the error when called in Time.use_zone.
How should I read / write the cookie data?
UPDATE after #Matt Johnson comment
My "hadcode" is
time_zone = cookies[:time_zone] || Time.zone
so that I can use the time_zone variable for my matters. However, I noted that Time.zone returns always
(GMT-06:00) Central Time (US & Canada)
# instead of "Central Time (US & Canada)"
It is the problem: in my "hardcode" when the cookie is nil then Time.zone should return the proper value for my matters, that is Central Time (US & Canada).
So my question become: how should I handle the issue in order to properly set the time_zone variable?
Notes: The Time.zone documentation states that the method
Returns the TimeZone for the current request, if this has been set
(via ::zone=). If Time.zone has not been set for the current request,
returns the TimeZone specified in config.time_zone.
and in my application.rb file I have set
`config.time_zone = 'Central Time (US & Canada)'`
Rails time zones are listed here. In this particular case, you should drop the first part of your string and just pass "Central Time (US & Canada)".
You may also want to read the timezone tag wiki, which has a section about Rails time zones toward the bottom.
Updated Answer
Based on your update, I can see that you are using Time.zone. This doesn't return a string, but returns a TimeZone object. So you are getting the effect of TimeZone.to_s() which includes the GMT portion.
You should instead use Time.zone.name, which just returns the string identifier of the time zone.

Why doesn't `config.time_zone` seem to do anything?

In application.rb, it says:
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.
But setting config.time_zone = 'Central Time (US & Canada)' or config.time_zone = 'Eastern Time (US & Canada)' has no effect - the created_at field in a model is stil being saved in UTC.
According to this railsforum answer:
config.time_zone just lets rails know
that your server is set to this
timezone so when it writes dates to
the database it can properly convert
it to UTC.
If that is true, then why is it that when my system time is Pacific Time (US & Canada) and config.time_zone = 'Central Time (US & Canada)' or config.time_zone = 'Eastern Time (US & Canada)', that the created_at time is the correct UTC? Should it not be incorrect?!
Because, if the PST time is 8 PM, then EST is 11 PM and UTC is 4 AM.
Presuming that Rails does Time.now, that would be 8 PM. And we told Rails that the server is in EST. So, 8 PM would be EST time as far as Rails is concerned and the UTC would then be 5 AM UTC, which would be incorrect (because the actual time is 8 PM PST/11 PM EST, which is 4 AM UTC)
What's going on here?
Here's a list of concepts and things that may help you:
config.time_zone doesn't set "Server Time", that is controlled by your operating system usually.
Rails always stores your dates in UTC in the database (unless you change a different setting).
Time.now returns the localtime for your computer in your timezone and it also includes the local timezone offset from your operating system, which means Ruby and therefore Rails knows how to convert localtime into UTC. You can try this by using irb directly, so no Rails libraries are loaded:
ctcherry$ irb
>> Time.now
=> Mon Feb 21 20:53:14 -0800 2011
>>
If config.time_zone, or Time.zone is set, to lets say EST, Rails expects that if you set a datetime attribute that you mean for that time and date to be in specified timezone, in this case EST. This is why you set Time.zone equal to your end users timezone, so they can use their local time and dates, and you can pass them directly into your ActiveRecord models and Rails can convert it to UTC for storage in the database.
Does that help at all?
You need to use in_time_zone (i.e. Time.now.in_time_zone) to get some something other than UTC.

Resources