113

If I have d = DateTime.now, how do I convert 'd' into UTC (with the appropriate date)?

Ash
  • 24,276
  • 34
  • 107
  • 152

6 Answers6

179
DateTime.now.new_offset(0)

will work in standard Ruby (i.e. without ActiveSupport).

Greg Campbell
  • 15,182
  • 3
  • 44
  • 45
177

d = DateTime.now.utc

Oops!

That seems to work in Rails, but not vanilla Ruby (and of course that is what the question is asking)

d = Time.now.utc

Does work however.

Is there any reason you need to use DateTime and not Time? Time should include everything you need:

irb(main):016:0> Time.now
=> Thu Apr 16 12:40:44 +0100 2009
DanSingerman
  • 36,066
  • 13
  • 81
  • 92
  • Because I want the correct date for the conversion, ie, for GMT +10 can be ahead the next day... – Ash Apr 16 '09 at 11:29
  • 2
    Time will do that for you just fine. Time includes the date part as well, not just the time of the day. Do Time.now.inspect to take a look. – DanSingerman Apr 16 '09 at 11:32
  • 2
    Oh sweet. So whats the difference between Date, Time and DateTime then? – Ash Apr 16 '09 at 11:40
  • 18
    Time is stored internally as the number of seconds and microseconds since the epoch, January 1, 1970 00:00 UTC. Date, internally, is represented as an Astronomical Julian Day Number, and DateTime is just plain weird (which is probably why Rails overrides it) – DanSingerman Apr 16 '09 at 11:44
10

Unfortunately, the DateTime class doesn't have the convenience methods available in the Time class to do this. You can convert any DateTime object into UTC like this:

d = DateTime.now
d.new_offset(Rational(0, 24))

You can switch back from UTC to localtime using:

d.new_offset(DateTime.now.offset)

where d is a DateTime object in UTC time. If you'd like these as convenience methods, then you can create them like this:

class DateTime
  def localtime
    new_offset(DateTime.now.offset)
  end

  def utc
    new_offset(Rational(0, 24))
  end
end

You can see this in action in the following irb session:

d = DateTime.now.new_offset(Rational(-4, 24))
 => #<DateTime: 106105391484260677/43200000000,-1/6,2299161> 
1.8.7 :185 > d.to_s
 => "2012-08-03T15:42:48-04:00" 
1.8.7 :186 > d.localtime.to_s
 => "2012-08-03T12:42:48-07:00" 
1.8.7 :187 > d.utc.to_s
 => "2012-08-03T19:42:48+00:00" 

As you can see above, the initial DateTime object has a -04:00 offset (Eastern Time). I'm in Pacific Time with a -07:00 offset. Calling localtime as described previously properly converts the DateTime object into local time. Calling utc on the object properly converts it to a UTC offset.

Joel Watson
  • 611
  • 6
  • 4
6

Try this, works in Ruby:

DateTime.now.to_time.utc
EEPAN
  • 69
  • 1
  • 3
5

You can set an ENV if you want your Time.now and DateTime.now to respond in UTC time.

require 'date'
Time.now #=> 2015-11-30 11:37:14 -0800
DateTime.now.to_s #=> "2015-11-30T11:37:25-08:00"
ENV['TZ'] = 'UTC'
Time.now #=> 2015-11-30 19:37:38 +0000
DateTime.now.to_s #=> "2015-11-30T19:37:36+00:00"
jeremywoertink
  • 2,281
  • 1
  • 23
  • 29
2

In irb:

>>d = DateTime.now
=> #<DateTime: 11783702280454271/4800000000,5/12,2299161>
>> "#{d.hour.to_i - d.zone.to_i}:#{d.min}:#{d.sec}"
=> "11:16:41"

will convert the time to the utc. But as posted if it is just Time you can use:

Time.now.utc

and get it straight away.

nitecoder
  • 5,496
  • 1
  • 28
  • 35