Time in Ruby on Rails

It is already tomorrow in Australia.

“Don’t worry about the world coming to an end today. It is already tomorrow in Australia.” -Charles M. Schulz

We as website developers hold little power over the real world. It’s the only reason the world has not blown up into pieces yet.

If we had absolute powers like we do over our apps, I wouldn’t be suprised if I woke up one day and when I opened the door the sky turned a deep orange, the dogs started howling in the distance and a fierce wind started beating against me, the door shaking as a flash of light rushed and engulfed me and - boom.

In the aftermath the words “Internal Server Error” hangs boringly in the atmosphere.

But what say you?

I’m better than you? More cautious? More professional? More talented? More intelligent?

Well that maybe, but let me tell you a little about Time, especially Time in Rails and how you can use it and make it work for you.

Time is tricky because sometimes you want to use Time.now, other times it’s Time.current and at times you even see Time.new.

Let’s get these out of the way.

What is the difference between Time.(new, now, and current)?

Time.new let’s you create a new time object. You’ll need to pass in a bunch of parameters and keep track of which param maps to what. Was the first param a year? or was it the second one? Yuck!

Don’t worry I’ll show you an easier way to create one at the end of the article.

Time.now always returns the system time. Time.current returns the current application time.

System time is the time kept by your physical computer. Let’s say you open up the rails console in your home computer in Kathmandu and type in Time.now. You’ll get the current time in Kathmandu. Now ssh to a server in America and type in Time.now, it’ll give you the current time there. Both of these are Time objects.

Time.current returns a ActiveSupport::TimeZone object, and the time it’s returns is TimeZone aware i.e it returns the current time specific to a timezone. Which timezone, you ask?

Well the timezone that you’ve set your application to via Time.zone= or config.time_zone

Time.zone
=> 
#<ActiveSupport::TimeZone:0x00007f08c34a72e8
 @name="Kathmandu",
 @TZINFO=#<TZInfo::DataTimezone: Asia/Kathmandu>,
 @utc_offset=nil>

Time.current
=> Sat, 26 Oct 2024 18:14:08.296070265 +0545 +05:45

To change it:

Time.zone = "Darwin"
=> 
#<ActiveSupport::TimeZone:0x00007f11675d24e0 @name="Darwin", 
  @tzinfo=#<TZInfo::DataTimezone: Australia/Darwin>, 
  @utc_offset=nil>

Time.current
=> Sat, 26 Oct 2024 21:58:58.035129061 ACST +09:30

Above you can see that the current time has changed. So to get the current application time we need to use Time.current.

If you just want the date, you use Date.current

If you want to know yesterday’s date, or tomorrow’s use: Time.current.yesterday; Time.current.tomorrow

You can even check whether today is a weekday or a weekend: Time.current.on_weekday?; Time.current.on_weekend?

The above methods are also available on Time objects. However if you’re wondering are there any other helpul method’s like the above for ActiveSupport::TimeZone objects, then you’re in the right place. I picked out a few that I found interesting and useful and in the process I also discovered an easier way to construct Time objects without melting my brain. Enjoy!

Get timezone of a country

ActiveSupport::TimeZone.country_zones(<country_code>)

ActiveSupport::TimeZone.country_zones('np')
=> 
[#<ActiveSupport::TimeZone:0x00007f08c34a72e8
  @name="Kathmandu",
  @tzinfo=#<TZInfo::DataTimezone: Asia/Kathmandu>,
  @utc_offset=nil>]

ActiveSupport::TimeZone.country_zones('in')
=> 
[#<ActiveSupport::TimeZone:0x00007fef14897578
  @name="Chennai",
  @tzinfo=#<TZInfo::DataTimezone: Asia/Kolkata>,
  @utc_offset=nil>,
 #<ActiveSupport::TimeZone:0x00007fef14896308
  @name="Kolkata",
  @tzinfo=#<TZInfo::DataTimezone: Asia/Kolkata>,
  @utc_offset=nil>,
 #<ActiveSupport::TimeZone:0x00007fef14896290
  @name="Mumbai",
  @tzinfo=#<TZInfo::DataTimezone: Asia/Kolkata>,
  @utc_offset=nil>,
 #<ActiveSupport::TimeZone:0x00007fef14896218
  @name="New Delhi",
  @tzinfo=#<TZInfo::DataTimezone: Asia/Kolkata>,
  @utc_offset=nil>]

# To set app's timezone to mumbai
Time.zone = "Mumbai"

Get US timezones

ActiveSupport::TimeZone.us_zones

ActiveSupport::TimeZone.us_zones
=>                                           
[#<ActiveSupport::TimeZone:0x00007f08c3e44d00
  @name="America/Adak",
  @tzinfo=#<TZInfo::DataTimezone: America/Adak>,
  @utc_offset=nil>,
 #<ActiveSupport::TimeZone:0x00007f08c3e449b8
   @name="Hawaii",
   @tzinfo=#<TZInfo::DataTimezone: Pacific/Honolulu>, 
   @utc_offset=nil>
   ...
   ...
 ]

Convert time to another zone

Time.current.in_time_zone("Sydney")
=> Sat, 26 Oct 2024 15:35:41.661123338 +0545 +05:45

View the offset

Time.zone.formatted_offset

Time.zone.formatted_offset
=> "+05:45"

# remove colon 
Time.zone.formatted_offset(false)
=> "+0545"

Creating Time/TimeWithZone objects

There is a hard way and an easy way to do things. I know I’m not a masochist because I had been creating Time objects for a long long time and found no pleasure in it until I found the easy way and ditched suffering completely.

The hard way:

Time.new(1999, 02, 6)
=> Sat, 06 Feb 1999 00:00:00 +0545

Time.zone.local(1999, 02, 6)
=> Sat, 06 Feb 1999 00:00:00.000000000 +0545 +05:45

The easy way:

Time.parse("Feb 6 1999, 2:30am")
=> 1999-02-06 02:30:00 +0545

Time.zone.parse("Feb 6 1999, 2:30am")
=> Sat, 06 Feb 1999 02:30:00.000000000 +0545 +05:45

Using a different zone temporarily

There might be times when you want to set a new Timezone temporarily. You can do this:

t = Time.zone
Time.zone = <new zone>
# code for new timezone
Time.zone = t

That will work but it’ll get flagged in review (if you’re lucky/unlucky to get reviews) because there is a better way.

Time.use_zone(<new zone>) do
# code for new timezone
end

Within the block the timezone changes to the new zone. After you exit the block the timezone is set back to the original zone.

However, use_zone if you noticed doesn’t come from the TimeZone class, it is defined in the Time class.

If you want to know more about Time in Rails in detail. Check out this article. It’s does a great job explaining all this stuff.