Reputation: 1430
2.5.0 :071 > "2018-06-16 22:39:09 +0200".to_datetime
=> Sat, 16 Jun 2018 22:39:09 +0200
2.5.0 :072 > "2018-06-16 22:39:09 +0200".to_datetime.utc_offset
=> 7200
2.5.0 :073 > "2018-06-16 22:39:09 +0200".to_datetime.utc
=> 2018-06-16 20:39:09 UTC
How to convert now 2018-06-16 20:39:09 UTC
to 2018-06-16 22:39:09 +0200
again
rails console when trying second solution
Running via Spring preloader in process 9869
Loading development environment (Rails 5.2.0)
2.5.0 :001 > orig = "2018-06-16 22:39:09 +0200".to_datetime
=> Sat, 16 Jun 2018 22:39:09 +0200
2.5.0 :002 > orig_offset = orig.zone # => "+2:00"
=> "+02:00"
2.5.0 :003 >
2.5.0 :004 > new = orig.utc
=> 2018-06-16 20:39:09 UTC
2.5.0 :005 >
2.5.0 :006 > same_as_orig = new.change(offset: orig_offset)
=> 2018-06-16 20:39:09 +0200
2.5.0 :007 > same_as_orig == orig # => true
=> false
2.5.0 :008 >
Upvotes: 0
Views: 1362
Reputation: 110725
Not knowing Rails, I will give a pure-Ruby answer (which may be of interest in its own right). For this reason, I cannot help with the extraction of the time zone name. I understand that can be done with Rails or by installing the tzinfo gem.
We begin with a given string:
str = "2018-06-16 22:39:09 +0200"
In Ruby we will need use of various methods from the classes Time and DateTime, so we must require 'time'
or require 'date'
(not required by Rails, I am told). Note DateTime.superclass #=> Date
.
require 'time'
The first step is to create a DateTime
object from this string. Two ways of doing that are to use DateTime::parse or DateTime::strptime, the latter being the more demanding and therefore more reliable method.
dtp = DateTime.parse(str)
#=> #<DateTime: 2018-06-16T22:39:09+02:00 ((2458286j,74349s,0n),+7200s,2299161j)>
dt = DateTime.strptime(str, '%Y-%m-%d %H:%M:%S %z')
#=> #<DateTime: 2018-06-16T22:39:09+02:00 ((2458286j,74349s,0n),+7200s,2299161j)>
Another approach is to convert the string to an array and then use DateTime::new or Time::new:
*all_but_last, offset = str.split(/[- :]/)
#=> ["2018", "06", "16", "22", "39", "09", "+0200"]
all_but_last
#=> ["2018", "06", "16", "22", "39", "09"]
offset
#=> "+02:00"
arr = [*all_but_last.map(&:to_i), offset.insert(-3, ':')]
#=> [2018, 6, 16, 22, 39, 9, "+02:00"]
DateTime.new(*arr)
#=> #<DateTime: 2018-06-16T22:39:09+02:00 ((2458286j,74349s,0n),+7200s,2299161j)>
Time.new(*arr)
#=> 2018-06-16 22:39:09 +0200
For the time being, trust me that UTC times are in fact instances of Time
.
Browsing the methods of the class Time
we find that it provides all the methods we need to convert between UTC time and local time, namely Time.gmtime, Time#utc_offset (aka, gmt_offset
) and Time#getlocal.
The next step, therefore, is to convert the DateTime
object dt
to a time object, using DateTime#to_time:
t = dt.to_time
#=> 2018-06-16 22:39:09 +0200
We may now convert this Time
instance to a UTC time:
ut = t.gmtime
#=> 2018-06-16 20:39:09 UTC
My earlier assertion that UTC times are Time
instances can now be confirmed:
ut.class
#=> Time
To convert this back to a local time we must save the local time's UTC offset:
offset = t.utc_offset
#=> 7200
This offset is measured in seconds for GMT (7200/3600 = 2 hours).
We may now compute the local time from ut
and offset
:
ut.getlocal(offset)
#=> 2018-06-16 22:39:09 +0200
Upvotes: 3