Crystal: Weird time comparison result

Created on 1 Sep 2017  路  6Comments  路  Source: crystal-lang/crystal

Looking for a way to store exact time to Redis and to be able check it against original. What I've got for now:

t1 = Time.now.to_utc
t2 = Time.epoch_ms(t1.epoch_ms)
p "#{t1.inspect} == #{t2.inspect} = #{t1 == t2}"
# => "2017-09-01 21:28:15 UTC == 2017-09-01 21:28:15 UTC = false"

How should one properly store time to Redis and, important, to test it?

Most helpful comment

The comparison is based on time ticks, so you can store the amount of ticks to instantiate the exact same Time later:
````crystal
t1 = Time.now.to_utc
t2 = Time.new(t1.ticks).to_utc
p "#{t1.inspect} == #{t2.inspect} = #{t1 == t2}"

=> "2017-09-01 22:13:48 UTC == 2017-09-01 22:13:48 UTC = true"

Or if you want/need to store milliseconds you can extract the milliseconds from the diff of the 2 times and check if it's zero: crystal
t1 = Time.now.to_utc
t2 = Time.epoch_ms(t1.epoch_ms)
puts (t1 - t2).milliseconds == 0 #=> true
````

Note that if you instantiate two different Times using the same value for epoch_ms your initial example will work as expected:

t1 = Time.now.to_utc

t2 = Time.epoch_ms(t1.epoch_ms)
t3 = Time.epoch_ms(t1.epoch_ms)

p "#{t2.inspect} == #{t3.inspect} = #{t2 == t3}" #=> "2017-09-01 22:50:55 UTC == 2017-09-01 22:50:55 UTC = true"

All 6 comments

struct Time
  def ==(other : self)
    self.epoch_ms == other.epoch_ms
  end
end

Makes it work. Maybe worths adding to stdlib?

The comparison is based on time ticks, so you can store the amount of ticks to instantiate the exact same Time later:
````crystal
t1 = Time.now.to_utc
t2 = Time.new(t1.ticks).to_utc
p "#{t1.inspect} == #{t2.inspect} = #{t1 == t2}"

=> "2017-09-01 22:13:48 UTC == 2017-09-01 22:13:48 UTC = true"

Or if you want/need to store milliseconds you can extract the milliseconds from the diff of the 2 times and check if it's zero: crystal
t1 = Time.now.to_utc
t2 = Time.epoch_ms(t1.epoch_ms)
puts (t1 - t2).milliseconds == 0 #=> true
````

Note that if you instantiate two different Times using the same value for epoch_ms your initial example will work as expected:

t1 = Time.now.to_utc

t2 = Time.epoch_ms(t1.epoch_ms)
t3 = Time.epoch_ms(t1.epoch_ms)

p "#{t2.inspect} == #{t3.inspect} = #{t2 == t3}" #=> "2017-09-01 22:50:55 UTC == 2017-09-01 22:50:55 UTC = true"

@oesgalha ticks returns an extra-weird values like 636399139551521680, which will look strange for another developer (former Rubyists at least); (t1 - t2).milliseconds == 0 doesn't work for cases when need to assert equality of structs with Time as attribute.

But I see. Comparing by ticks - okay, as creators wish. They lead the way.

Well you have created 2 time instances which don't refer to the same time - you've lost precision by converting to the nearest millisecond with epoch_ms - so obviously they aren't equal.

@RX14 what's the exact precision of a tick?

One tenth of a microsecond, so 100ns. There are 10000 of them in a ms.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

malte-v picture malte-v  路  77Comments

sergey-kucher picture sergey-kucher  路  66Comments

chocolateboy picture chocolateboy  路  87Comments

stugol picture stugol  路  70Comments

asterite picture asterite  路  70Comments