crystal icon indicating copy to clipboard operation
crystal copied to clipboard

Time formatters without support for sub-minute zone offsets

Open straight-shoota opened this issue 5 months ago • 0 comments

Crystal's Time type supports time zone offsets with a resolution of seconds. But not all time formats support such a high resolution. In fact, none of the custom formatters provided in stdlib supports sub-minute zone offsets. Consequently, most of them produce an incorrect result when formatting a Time instance with such a location. A loss of precision in the zone offset means that the formatted time represents a different instant than the original.

location = Time::Location.fixed(3601) # Offset of 1 hour and 1 second
time = Time.local(2014, 1, 2, 3, 4, 5, location: location)

Time::Format::RFC_2822.format(time) # => "Thu, 2 Jan 2014 03:04:05 +0100"
Time::Format::RFC_3339.format(time) # => "2014-01-02T03:04:05+01:00"
Time::Format::ISO_8601_DATE_TIME.format(time) # => "2014-01-02T03:04:05+01:00"
Time::Format::YAML_DATE.format(time) # => "2014-01-02 03:04:05.000000000+01:00

# HTTP_DATE always converts to UTC, so it never presents the original offset. But it always retains the correct instant.
Time::Format::HTTP_DATE.format(time) # => "Thu, 02 Jan 2014 02:04:04 GMT"

This behaviour is surprising and potentially dangerous.

At the very least, these formatters should raise if they're tasked to format a time zone offset they cannot support. In most cases it's impossible because formats such as RFC3339 and ISO8601 only define hours and minutes offsets. This would prevent the formatter deficiency from causing any errors.

Alternatively, we could "round" the time zone offset to the nearest minute and format the date with that. This would result in a slightly different datetime representation, but at least it would keep referring to the correct instant.

In practice, time-zone offsets with fractions of a minute are pretty much irrelevant. So there's not much reason to do any extra work here. But since these offsets are possible, the formatters should be able to handle them sensibly or error.

straight-shoota avatar May 20 '25 21:05 straight-shoota