Strptime with Timezone
Asked Answered
W

9

25

I have a String which I parse with DateTime.strptime. The Timezone of the Date in the String is CET but Ruby creates an UTC DateTime object which of course has an offset of 2hrs.

Currently I'm working around the issue with DateTime.strptime().change(:offset => "+0020") but I'm pretty sure this is not the way it's meant to work.

Can someone enlighten me on the correct way to do this?

Wideman answered 26/10, 2011 at 21:26 Comment(1)
if you are in a country with CEST/CET timezone a fixed offset won't work. Also interested in this, I don't see how make strptime parse for the current timezone (but not the value right now, the right one depending on the parsed string).Quinone
H
-3

I can't delete an accepted answer

As @LeeJarvis pointed out in the comment section below, Chronic.parse does not accept a :time_class option. So this answer is buggy and while it looks like it works, it doesn't (unless Chronic allows passing a :time_class option soon.)


The Chronic gem is really powerful.

I use it like this:

Chronic.parse("next 5:00 pm", 
:time_class => ActiveSupport::TimeZone.new(User.first.time_zone)).utc

In my example above, User.first.time_zone is "Pacific Time (US & Canada)".

Chronic supports a lot of formats so check it out at https://github.com/mojombo/chronic

Make sure to pass the :time_class option and to convert to UTC (in the documentation, Chronic sets :time_class before calling parse. I avoid this approach because it might cause other parts across the application not to work)

TimeZone's documentation is at http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html

Humoresque answered 3/4, 2013 at 11:55 Comment(3)
This answer is not correct. parse() does not take a time_class option. It's set on the Chronic class directly. This will eventually change in future versions of Chronic, thoughKelwunn
My bad... I'll remove until this option is available =)Humoresque
Erm... I can't delete an accepted answer. I'll comment above.Humoresque
C
14

I use it the following way:

ruby-1.9.2-head :001 > require 'date'
 => true 
ruby-1.9.2-head :002 > fmt = "%m-%d-%Y %H:%M:%S %Z"
 => "%m-%d-%Y %H:%M:%S %Z" 
ruby-1.9.2-head :003 > DateTime.strptime "10-26-2011 10:16:29 CET", fmt
 => #<DateTime: 2011-10-26T10:16:29+01:00 (212186380589/86400,1/24,2299161)> 
ruby-1.9.2-head :004 > DateTime.strptime "10-26-2011 10:16:29 UTC", fmt
 => #<DateTime: 2011-10-26T10:16:29+00:00 (212186384189/86400,0/1,2299161)> 
ruby-1.9.2-head :005 > DateTime.strptime "10-26-2011 10:16:29 PST", fmt
 => #<DateTime: 2011-10-26T10:16:29-08:00 (212186412989/86400,-1/3,2299161)> 

Is it what you mean?

Crowberry answered 26/10, 2011 at 21:53 Comment(3)
i dont have a string determining the timezone in my parsed string. its 10-26-2011 10:16:29 instead of "10-26-2011 10:16:29 CET"Wideman
You solved my problem, I can just "09-19-2012 11:08:44" + " CST". I think yours is the correct answer.Pendragon
What about when the you move into daylight savings time? Shouldn't this + "CST" be more informed? As per the comment above, it'd be nice if we could pick that based on the time that just got formatted... i'm learning to hate timezones.Offenbach
O
9

This works in Rails 5:

Time.zone.strptime("2017-05-20 18:20:10", "%Y-%m-%d %H:%M:%S")

Returns the time in the specified time zone.

Outrange answered 27/5, 2017 at 19:45 Comment(0)
F
5

At least as of Rails 4.2 (maybe earlier, haven't tested) as long as you use Time#strptime instead of DateTime.strptime, the current time zone is automatically applied:

> DateTime.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')
=> Wed, 28 Dec 2016 17:00:00 +0000

> Time.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')
=> 2016-12-28 17:00:00 -0800
Fondness answered 29/12, 2016 at 0:50 Comment(2)
This uses the timezone of the machine, not the timezone set in Rails, btw.Korns
@Korns Yes, that's true. The workaround is to use Time.zone.strptime for Rails 5+ or Time.zone.local_to_utc(DateTime.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')) for older versions of RailsSignificancy
R
1

I was "strptiming" this string:

19/05/2014 8:13:26 a.m.

A local timestamp, which is in my case is Auckland NZ without a timezone stamp in the string as can be seen.

As best I can tell Time.strptime uses the server timezone as the base.

In my situation, and general good practice, my servers run in UTC timezone so every parse of the string ended up creating a time object, the time to +0000 (UTC):

2014-05-19 08:13:26 +0000

Then converting to in_time_zone(Time.zone) gave:

Mon, 19 May 2014 20:13:26 NZST +12:00

Which as can be seen is 12 hours (the UTC offset) later than the actual time I wanted.

I tried to use the +' Auckland', '...%Z' trick as per above without any change. I then used the + '+1200', '...%Z' trick as per above which worked correctly.

However I was concerned about summer time, then the parsing would be out by an hour, so this is what I've finshed with:

Time.strptime(call_data[:datetime].gsub(/\./, "").gsub(/am/, "AM").gsub(/pm/, "PM") + (Time.zone.now.time_zone.utc_offset/3600).to_s.ljust(4,'0').rjust(6,' +'), '%d/%m/%Y %I:%M:%S %p %Z').in_time_zone(Time.zone)

Result:

Mon, 19 May 2014 08:13:26 NZST +12:00

It's not particularly elegant but it works.

Recompense answered 9/9, 2014 at 2:16 Comment(0)
S
0

You can convert date to timezone with to_time_in_current_zone. For example:

Date.strptime('04/07/1988', '%m/%d/%Y').to_time_in_current_zone
Sweetheart answered 16/6, 2013 at 7:32 Comment(1)
apidock.com/rails/Date/to_time_in_current_zone method is depreciated sorry :(Nova
W
0

I have been battling this same issue trying to parse a date string from a form and save it independently of the servers time. The process I have followed is as such. I assure the RoR and Ruby timezones are set to UTC. It makes it easier if the server is on UTC time as well.

I am storing the users locale using the ActiveSupport:TimeZone format like US/Eastern I have an interpret date function which can account for a date string that doesn't natively contain a timezone or offset

# date_str looks something like this `12/31/2014 6:22 PM`
# tz is a string containing an ActiveSupport::TimeZone name like `US/Eastern`
def interpret_date(date_str, tz)
  Time.use_zone tz do
    parsed_dt = DateTime.strptime(date_str, '%m/%d/%Y %H:%M %p')
    offset = parsed_dt.in_time_zone(tz).utc_offset
    parsed_dt.advance(seconds: -(offset)).in_time_zone(tz)
  end
end

This of course doesn't feel like a perfect solution but it works. The steps to assure the correct timezone are:

  1. Parse the date string according to our format
  2. Extract the current utc offset based upon the time in that timezone (We have to do this if the date you are parsing happens to be in dst while your local time is not dst for eastern time this will assure that the dst is local to the parsed time)
  3. Convert the time to our target locale and allow the time to shift with the correct offset added
Wow answered 22/5, 2016 at 0:56 Comment(0)
D
0

For pre Rails 5, the following will work:

t0 = Time.strptime("2018-05-01", "%Y-%m-%d") # Or whatever
t1 = Time.zone.now.change(year: t0.year, month: t0.month, day: t0.day, hour: t0.hour, min: t0.min, sec: t0.sec, usec: t0.usec)
Diplomate answered 19/6, 2018 at 10:55 Comment(0)
O
0

try this

(date + Rational(5,24)).new_offset(-Rational(5,24))

what u are doing here: suppose that u want to change to timezone 5

date + Rational(5,24)

i'll add 5 hour to your datetime, maintain the time zone.

after, how adjust the offset to recover the original data and get the timezone that u want.

Osteoma answered 14/2, 2023 at 20:39 Comment(0)
H
-3

I can't delete an accepted answer

As @LeeJarvis pointed out in the comment section below, Chronic.parse does not accept a :time_class option. So this answer is buggy and while it looks like it works, it doesn't (unless Chronic allows passing a :time_class option soon.)


The Chronic gem is really powerful.

I use it like this:

Chronic.parse("next 5:00 pm", 
:time_class => ActiveSupport::TimeZone.new(User.first.time_zone)).utc

In my example above, User.first.time_zone is "Pacific Time (US & Canada)".

Chronic supports a lot of formats so check it out at https://github.com/mojombo/chronic

Make sure to pass the :time_class option and to convert to UTC (in the documentation, Chronic sets :time_class before calling parse. I avoid this approach because it might cause other parts across the application not to work)

TimeZone's documentation is at http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html

Humoresque answered 3/4, 2013 at 11:55 Comment(3)
This answer is not correct. parse() does not take a time_class option. It's set on the Chronic class directly. This will eventually change in future versions of Chronic, thoughKelwunn
My bad... I'll remove until this option is available =)Humoresque
Erm... I can't delete an accepted answer. I'll comment above.Humoresque

© 2022 - 2025 — McMap. All rights reserved.