While working on API integrations with third-party services, I get a timestamp of the event in the request payload.
{ "timestamp": "1583122008", ... }
This timestamp
is the number of seconds that have elapsed since the Unix epoch, i.e., 00:00:00 UTC on 1 January 1970, minus leap seconds. In Ruby, it is very easy to get Unix time for the current time:
puts Time.now.to_i
But how do you take this epoch time and convert it back to a Ruby Time object?
Time::at
to the rescueRuby has a handy method, Time::at
, that can convert Unix epoch time back to a Time object:
ts = Time.now.to_i# Time.at functionputs Time.at(ts)
It prints time in the local time zone, which, in my case, is IST. However, Time::at
also supports timezone arguments, as shown:
ts = Time.now.to_i
puts Time.at(ts, in: "+01:00")
puts Time.at(ts, in: "-02:00")
=> 2020-03-02 05:13:24 +0100 => 2020-03-02 02:13:24 -0200
The in
keyword argument accepts timezones offset in the form of +HH:MM
or -HH:MM
.
The
in
argument was supported from Ruby 2.6 onwards. Before that,Time.at
only accepted one argument.Time.at
is provided by Ruby, not by Rails or Active Support.
While looking at the solution to this parsing problem, I checked the documentation of the Time::at
method on ruby-doc.org. I came across this:
If an argument is given, the result is in that timezone or UTC offset. If a numeric argument is given, the result is in local time.
This led me down to Ruby’s source code to understand what kind of arguments could be passed into Time::at
. After checking the code, I found that the in argument accepts the following:
+HH:MM
or -HH:MM
:ts = Time.now.to_i
Time.at(ts, in: "+01:00")
Time.at(ts, in: "-02:00")
=> 2020-03-02 05:13:24 +0100 => 2020-03-02 02:13:24 -0200
ts = Time.now.to_i
Time.at(ts, in: "UTC")
=> 2020-03-02 04:13:24 UTC
ts = Time.now.to_i
Time.at(ts, in: "E")
Time.at(ts, in: "Z")
=> 2020-03-02 09:13:24 +0500 => 2020-03-02 04:13:24 UTC
If we pass anything else, we get an error message:
ts = Time.now.to_i
Time.at(ts, in: "IST")
Traceback (most recent call last): 2: from (irb):12 1: from (irb):12:in `at' ArgumentError ("+HH:MM", "-HH:MM", "UTC" or "A".."I","K"
This error message is from Ruby 2.7. In Ruby 2.6, the error message did not mention military timezones, it only talked about UTC offset.
I opened a pull request to improve the documentation of Time::at
, and it got merged quickly. The documentation of Time::at
will have all possible combinations for the argument in the next release of Ruby 👏🏻
If you want to perform this same trick in PostgreSQL, read my article on converting Unix epoch time to timestamps in PostgreSQL.
Free Resources