Trouble on handling cookie data with time zones - ruby-on-rails

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.

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 custom time zone in Rails? "-03:30GMT"

I know we can set time zone with
Time.zone = "Eastern Time (US & Canada)"
But how to set with UTC/GMT time, I want to set time zone to -03:30GMT, but I cant find any place which lies in that time zone, so how to set it by giving values?
try this. this will work
Time.zone = -12600
this will give you the full list of timezones from the library
ActiveSupport::TimeZone.zones_map.values.collect { |z| z.tzinfo.name }.compact.uniq.each do |tz|
puts "#{ActiveSupport::TimeZone.seconds_to_utc_offset(Time.now.in_time_zone(tz).utc_offset)}\t#{tz}"
end; nil
I cant find any place which lies in that time zone
It looks like all zones are covered

Rails 4 - how to set a timezone for strftime?

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("...")

How to show Time.now based on TimeZone - Rails 4

Hey guys i am trying to show server time but instead it shows local time. Is it possible to set server timezone to something like canada?
i tried this in application.rb
config.time_zone = 'Central Time (US & Canada)'
but when i use Time.now it shows local time.
Would appreciate your help.
Time.now will always print your system local time. If you want to print current time according to zone, then use:
Time.zone.now
Or,
Time.now.in_time_zone(Central Time (US & Canada))
Just use Time.current. Quote from its docs:
Time.current returns Time.zone.now when Time.zone or config.time_zone are set, otherwise just returns Time.now.

Rails and dates, are they stored in UTC by default?

What is the best way for me to handle dates and timezones in rails?
Scenerio: I have customers who purchase products on a website from all over the world, and when they log in they will be able to choose which timezone they are from.
So I believe I should be storing everything in the database at UTC, and then on the front-end I should be converting the dates to the users set timezone preference.
Are their any gotchas with Ruby and Rails and datetimes etc?
I'm new to rails, so I am looking for guidance on how to handle this properly.
Fortunately Rails will pretty much handle things for you. As others pointed out, dates are stored by AR in UTC format. If you have a time_zone field for your users table you can do something like this:
# application.rb
config.time_zone = "Mountain Time (US & Canada)" # Default time zone
-
# application_controller.rb
before_filter :set_time_zone, :if => :logged_in?
protected
def set_time_zone
Time.zone = current_user.time_zone if current_user.time_zone
end
All the datetimes should be shown in the proper time zone in your views.
I have had one production app that didn't like using the default time zone, but I can't remember which version of Rails/Ruby it was running.
Ok so take a look at your config/application.rb file.
You should find commented lines:
# 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 = 'Central Time (US & Canada)'
So default is UTC but you can set whatever ou need there.
Yes, they are. In app, whenever you display date or time for user, everything you need is just adding timezone offset (for example: date + 1.hour for GMT+1). Remember that you need to take care of daylight saving, too. For efficency, consider adding 2 columns in your user table: timezone and time_offset. Then you would on each case do something like
= #order.created_at + session[:user].time_offset
Instead of always checking offset for each timezone set in profile.
I found
rake time:zones:all
to be really useful. It shows a list of offsets and then zone name strings under that. eg:
* UTC +12:00 *
Auckland
Fiji
Kamchatka
Magadan
Marshall Is.
Solomon Is.
Wellington
I needed below in application.rb (not intuitive given default time zone string of "Mountain Time (US & Canada)"):
config.time_zone = 'Wellington'

Resources