Rails 5.2.3
I have a date:
"Apr-03-2013 17:47:00"
I have a date zone:
"America/Los_Angeles"
I am trying to turn it into a string:
"Apr-03-2013 17:47:00 Pacific Daylight Time (GMT-07)"
The best I can come up with is:
time_obj = ActiveSupport::TimeZone["America/Los_Angeles"].parse("2013-04-03 17:47:00")
Time.at(time_obj).strftime("%b-%d-%Y %H:%M:%S %Z")
Which gives me:
"Apr-03-2013 17:47:00 PDT"
Any ideas?
I believe you need custom logic and/or you own database of timezones to get it exactly like that.
Using %Z with strftime is going to give you what ever your OS likes and there are a few disclaimers in the ruby docs.
One idea that you might get some mileage out of: If you are starting with a time zone identifier like "America/Los_Angeles" then you can use ActiveSupport::TimeZone::MAPPING to get a friendlier name, or at least a Rails time zone name.
eg:
ActiveSupport::TimeZone::MAPPING.key("America/Los_Angeles")
=> "Pacific Time (US & Canada)"
But that won't work for every identifier:
ActiveSupport::TimeZone::MAPPING.key("America/Detroit")
=> nil
You can see which ones will map like this:
TZInfo::Country.get('US').zone_identifiers.map {|ident| [ident, ActiveSupport::TimeZone::MAPPING.key(ident)] }
So in that case you need to fall back to the identifier you have, or perhaps this approach might work.
Then you'd need to deal with the daylight savings part, here you can use dst?
ActiveSupport::TimeZone["America/Los_Angeles"].parse("2013-04-03 17:47:00").dst?
Then you'd need to splice all that together! ... and add the offset as well.
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("...")
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.
I'm using Rails 3.2 and ruby 1.9.3 on Debian. I have an app that collects a date, time, and timezone in the form of strings via an HTML form. Something like this:
start_date: "04-15-2010",
start_time: "10:00:00",
timezone: "Central Time (US & Canada)"
What I'd like to do is parse these 3 elements into a single date that is saved into my database as UTC, which in this case would add 7 hours to the start time, once it's in the UTC time zone.
So the stored time would be 17:00 once it's in the DB as UTC instead of the received Central time.
I have tried something like this to parse the date:
ActiveSupport::TimeZone[timezone].at DateTime.strptime("{ 2012-04-09 20:00:00 }", "{ %Y-%m-%d %H:%M:%S }").to_i
However, I'm not able to incorporate the time zone into the resulting time with %Z. It either doesn't parse or the time is interpreted as UTC not Central time. So my question is, how to coerce a date string into a certain time zone without changing the value of the actual date/time stored. I'd like to be able to parse the string into a date/time object that includes the correct time zone with it at that time so that future time zone conversions are accurate. I've looked all over and can't find a way to do this. It's strange, since this seems like something common one does with dates inputted from HTML forms. Thank you for any help.
Try this:
zone = "Central Time (US & Canada)"
ActiveSupport::TimeZone[zone].parse("2013-04-03 17:47:00")
Use String#in_time_zone (Rails 4+)
I personally prefer using String#in_time_zone:
>> '22.09.1986 10:30'.in_time_zone('Central Time (US & Canada)')
# => Mon, 22 Sep 1986 10:30:00 CDT -05:00
This parses the date and time in the String into the time zone provided.
%Z is the correct way to specify a Time zone name. Have you tried the following ?
date_and_time = '%m-%d-%Y %H:%M:%S %Z'
DateTime.strptime("04-15-2010 10:00:00 Central Time (US & Canada)",date_and_time)
This is the method that I came up with. Not the prettiest, but it works. Allows parsing the string using a specified format, and then turning it into the format that I know Time.zone.parse requires.
class ActiveSupport::TimeZone
def strptime(time, format='%m/%d/%Y')
formatted = Time.strptime(time, format).strftime('%Y-%m-%d %T')
parse(formatted)
end
end
Then you can do something like what was mentioned in another question, but with a specified format:
zone = "Central Time (US & Canada)"
ActiveSupport::TimeZone[zone].strptime('2013-04-03', '%Y-%m-%d')
Or if you already have a time zone set:
Time.zone = "Central Time (US & Canada)"
Time.zone.strptime('01/13/2006')
I used a default format of %m/%d/%Y because that's what my user input is most of the time. You can customize this to your needs, or use the default format DateTime uses which is believe is iso8601 (%FT%T%z)
I've finally found the dirty, yet definitive way to do this.
First, parse the string using plain Ruby Time.strptime like this:
time = Time.strptime('12 : 00 : PM', '%I : %M : %p')
This way you get the parsed Time, but not yet in correct timezone. To fix that, let's convert the time to string form and parse it with the standard ActiveSupport::TimeZone#parse
Time.zone.parse(time.to_s)
The result is the ActiveSupport::TimeWithZone with our time parsed into the correct timezone.
The reason why we have to do it this way is that neither ActiveSupport::TimeZone nor ActiveSupport::TimeWithZone support the strptime method. So we have to parse the Time with core Ruby strptime that does not have timezone information, convert it to format acceptable in ActiveSupport objects and then parse it yet again.
To have DateTime take the date string and attach a timezone other than UTC without changing the values of the date string , use this, its easy , doesnt break on leap day :)
xx = DateTime.strptime("9/1/15 #{object.time_zone}", "%m/%d/%Y %Z")
Convert specific date format in UTC.
ActiveSupport::TimeZone['UTC'].parse(Time.strptime('01/24/2019T16:10:16', "%m/%d/%YT%H:%M:%S").asctime)
I've got an old database with time zone formats like:
US/Eastern
Australia/Melbourne
In my new Rails app, I'm saving them as:
Eastern Time (US & Canada)
Melbourne
How can I convert the old to the new? I've been messing around with ActiveSupport::TimeZone, but can't figure out the right combination to get from one to the other.
I was hoping I could create a new object, then return the newly formatted name, but it just returns the name I gave it. Example:
> tz = ActiveSupport::TimeZone.new("US/Eastern")
=> (GMT-05:00) US/Eastern
> tz.name
=> "US/Eastern"
Thanks in advance!
This is pretty ugly, but it's the only way I've found to do it:
city = TZInfo::Timezone.get('US/Eastern').instance_eval('#linked_timezone').name
ActiveSupport::TimeZone::MAPPING.invert[city]
Edit:
For this code to work with either city or zone, you can do this:
zone = TZInfo::Timezone.get(zone_name)
city = (zone.instance_eval('#linked_timezone') || zone).name
ActiveSupport::TimeZone::MAPPING.invert[city]