# Adventures in Daylight Saving, Norfolk Island, and Time Zone Math (in Ruby)

DevFeed: [Adventures in Daylight Saving, Norfolk Island, and Time Zone Math (in Ruby)](<https://devfeed.tech/articles/adventures-in-daylight-saving-norfolk-island-and-time-zone-math-in-ruby-20534.md>)

Original publisher: [Read original article](<https://code.dblock.org/2026/08/28/adventures-in-daylight-saving-norfolk-island-and-time-zone-math-in-ruby.html>)

Author: Daniel Doubrovkine (dblock@dblock.org)

Published: 2026-08-28T00:00:00Z

Content type: article

Language: en

Sources: [Daniel Doubrovkine](<https://devfeed.tech/sources/daniel-doubrovkine.md>)

Topics: [Ruby](<https://devfeed.tech/topics/ruby.md>), [DateTime](<https://devfeed.tech/topics/datetime.md>), [bug](<https://devfeed.tech/topics/bug.md>)

Tags: [bug](<https://devfeed.tech/tags/bug.md>), [code](<https://devfeed.tech/tags/code.md>), [open-source](<https://devfeed.tech/tags/open-source.md>), [ruby](<https://devfeed.tech/tags/ruby.md>), [time](<https://devfeed.tech/tags/time.md>)

## AI overview

This article explains how several bugs in the Ruby gem distance_of_time_in_words were caused by incorrect assumptions about daylight-saving transitions and time-zone offsets. Fixes replaced DST checks and one-hour special cases with comparisons of actual UTC offsets, handling Europe/Dublin and Norfolk Island correctly.

## Source excerpt

distance_of_time_in_words is a small Ruby gem that turns two Time objects into a human-readable string like "3 days and 4 hours". Several separate bug reports against it turned out to be variations on the same theme: computing a duration between two timestamps is not the trivial subtraction it looks like, the moment time zones are involved. The first two fixes shipped in dotiw 5.6.0; four more followed shortly after in dotiw 5.6.1. Bug 1: dst? Lies When You Least Expect It #63 reported that a duration of one minute was rendered as "less than 1 second" for users in Europe/Dublin. The gem's TimeHash had a DST correction that looked reasonable: d = largest - smallest d -= 1.hour if smallest.dst? && !largest.dst? d += 1.hour if !smallest.dst? && largest.dst? The idea: if a DST transition happened between the two times, Time subtraction already accounts for the wall-clock jump, so cancel it back out before splitting the duration into calendar units. That works everywhere except Ireland. Europe/Dublin uses an inverted DST scheme: its winter time is legally defined as "standard time minus one hour" rather than the more common "standard time is winter, summer is +1". Depending on whether a Time was constructed via Time.at(seconds) or datetime.to_time, dst? could report different values for the exact same instant, even though utc_offset agreed. The correction fired when it shouldn't have, and a real one-minute gap got silently zeroed out. Reproducing it doesn't even require mocking dst? -- just running the example with the right TZ set is enough: ENV['TZ'] = 'Europe/Dublin' start = Time.at(DateTime.now) finish = DateTime.now + 1.minute # => "less than 1 second" # expected: "1 minute" distance_of_time_in_words(start, finish) The fix (PR #152) was to stop asking "is this DST?" and just compare the actual offsets: def offset_decreased?(smallest, largest) smallest.utc_offset > largest.utc_offset end def offset_increased?(smallest, largest) smallest.utc_offset < largest.utc_offset