crystal icon indicating copy to clipboard operation
crystal copied to clipboard

Improve format for `Time#inspect`

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

Time#inspect produces a format that is roughly equivalent to to_s("%F %T.%N %::z %Z").

But there are some special cases:

  • automatically trims insignificant digits of nanoseconds
  • omits seconds in the time zone offset if zero
  • omits the location if the offset is fixed
    • unless the location is UTC, then omits the offset and prints UTC instead

These special cases make the format more concise, which is a good thing.

But the special cases for offset and location causes some inconsistencies. Sometimes there's an offset, sometimes an offset plus location and sometimes only a location 🤷

To simplify this, I suggest changing the format to always print the offset, and always omit the location when it's fixed. For a UTC offset, we can use the Z identifier from ISO 8601/RFC 3339 which results in an even more concise format.

An additional consideration is to standardize on the Internet Extended Date/Time Format (IXDTF, RFC 9557), which defines a pretty standardized format for representing time instances with additional information. For our use case, it would be equivalent to an RFC3339 format[^1] plus an extended information tag identifying the location.

# Time.utc(2014, 1, 2, 3, 4, 5, nanosecond: 123_456_789).inspect
-2014-01-02 03:04:05.123456789 UTC
+2014-01-02 03:04:05.123456789Z

# Time.local(2014, 1, 2, 3, 4, 5, nanosecond: 123_456_789, location: Time::Location.load("Europe/Berlin")).inspect
-2014-01-02 03:04:05.123456789 +01:00 Europe/Berlin
+2014-01-02T03:04:05.123456789+01:00[Europe/Berlin]

# Time.local(2014, 1, 2, 3, 4, 5, nanosecond: 123_456_789, location: Time::Location.fixed(3600)).inspect
-2014-01-02 03:04:05.123456789 +01:00
+2014-01-02T03:04:05.123456789+01:00

The results are very similar to what we have right now, just a bit more refined. Length is usually identical, but slightly shorter for fixed locations. Changing the separator between date and time from white space to T may reduce human readbility, but it improves technical precision and interoperability.

The major benefit of following a standardized format is interoperability: it makes it easy to copy and paste the output into other systems without format conversion. On that note, I hope to introduce a generic parse method which parses the output format of Time#inspect into a new Time instance, for easy (de-)serialization.

Related:

  • Original discussion about time zone support: #4556
  • Previous update to Time#inspect: #5794

[^1]: Technically it would not be 100% conform to RFC3339 which does not support offsets with a fraction of a minute (see #15807).

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