Georg Ledermann
Georg Ledermann

Reputation: 2752

Understanding Time#utc?

As I understand, UTC means a time is given in timezone +00:00. But Ruby thinks different in Time#utc?. I've observed this in Ruby 2.5.1:

a = Time.new(2018,6,13, 9,0,0, '+00:00')
# => 2018-06-13 09:00:00 +0000 

b = Time.utc(2018,6,13, 9,0,0)
# => 2018-06-13 09:00:00 UTC 

a == b 
# => true

a.utc? 
# => false (WHY???)

b.utc?
# => true

IMHO, a.utc? should return true. Is there any explanation?

Addition: From the Ruby docs for Time#utc?

Returns true if time represents a time in UTC (GMT).

What exactly means "representing a time in UTC/GMT"? An offset of 0 is not enough, obviously.

Upvotes: 5

Views: 153

Answers (1)

Stefan
Stefan

Reputation: 114188

Implementation-wise, Ruby's (i.e. MRI) internal time structure has a gmt field which specifies the time's type:

PACKED_STRUCT_UNALIGNED(struct time_object {
    wideval_t timew; /* time_t value * TIME_SCALE.  possibly Rational. */
    struct vtm vtm;
    uint8_t gmt:3; /* 0:localtime 1:utc 2:fixoff 3:init */
    uint8_t tm_got:1;
});

The utc? method merely checks whether gmt is 1.

Therefore, a time instance in local time or a time instance with explicit offset will never be utc?, even if your system's timezone offset is UTC+0:

Time.local(2018)      #=> 2018-01-01 00:00:00 +0000
Time.local(2018).utc? #=> false

Time.new(2018)        #=> 2018-01-01 00:00:00 +0000
Time.new(2018).utc?   #=> false

as opposed to a time instance created via utc: (note that the offset is shown as UTC)

Time.utc(2018)        #=> 2018-01-01 00:00:00 UTC
Time.utc(2018).utc?   #=> true

You could check the utc_offset instead:

t = Time.new(2018) #=> 2018-01-01 00:00:00 +0000
t.utc_offset       #=> 0
t.utc_offset.zero? #=> true

Upvotes: 5

Related Questions