Civil.Offset

A fixed offset from UTC, as written in a date-time.

An offset is not a time zone. America/Denver is a time zone: a set of rules saying that the offset is -07:00 in January and -06:00 in June, and those rules have changed several times since 1883. -07:00 is an offset: a plain number of minutes, with no rules and no history behind it. A timestamp records the offset, never the zone. That is why the zone cannot be recovered from a timestamp, and why this module deals only in offsets.

Three ways to write zero

RFC 3339 gives Z, +00:00 and -00:00 three separate meanings, and this module keeps them apart:

  • Z means the time is in UTC.
  • +00:00 is an ordinary offset that happens to be zero.
  • -00:00 means the local offset is unknown (RFC 3339, section 4.3).

All three are zero minutes from UTC, so toMinutes returns 0 for each of them, but == treats them as three different values. To compare offsets by their number rather than their spelling, compare toMinutes.

Range

-23:59 through +23:59, which is what TOML's grammar allows. The constructors return Nothing for anything outside that range.

type Offset

An offset from UTC.

Creating

zulu : Offset

UTC, written Z.

Offset.toString Offset.zulu
--> "Z"
plus : { hours : Int, minutes : Int } -> Maybe Offset

An offset east of UTC, from hours and minutes.

Offset.plus { hours = 5, minutes = 30 }
    |> Maybe.map Offset.toString
--> Just "+05:30"

Nothing if the hours are outside 0-23 or the minutes outside 0-59.

minus : { hours : Int, minutes : Int } -> Maybe Offset

An offset west of UTC, from hours and minutes.

Offset.minus { hours = 7, minutes = 0 }
    |> Maybe.map Offset.toString
--> Just "-07:00"

Note that minus { hours = 0, minutes = 0 } is -00:00, which RFC 3339 reads as "offset unknown" rather than as UTC. If you mean UTC, use zulu.

fromMinutes : Int -> Maybe Offset

An offset from a signed number of minutes east of UTC.

Offset.fromMinutes -420 |> Maybe.map Offset.toString
--> Just "-07:00"

Zero gives +00:00. For Z use zulu, and for -00:00 use minus. Nothing outside -1439 to 1439.

Reading

toMinutes : Offset -> Int

Minutes east of UTC, negative for an offset west of it. 0 for all three spellings of zero.

Offset.fromString "-07:00" |> Maybe.map Offset.toMinutes
--> Just -420
isZulu : Offset -> Bool

Whether this was written Z, rather than as an offset that happens to be zero.

Offset.isZulu Offset.zulu
--> True
isNegative : Offset -> Bool

Whether this was written with a minus sign. True for -00:00; the sign is what tells it apart from +00:00.

Offset.fromString "-00:00" |> Maybe.map Offset.isNegative
--> Just True
hours : Offset -> Int

The hours part, always 0 to 23, without the sign.

minutes : Offset -> Int

The minutes part, always 0 to 59, without the sign.

Strings

fromString : String -> Maybe Offset

Read Z, z, or a signed HH:MM.

Offset.fromString "+12:45" |> Maybe.map Offset.toMinutes
--> Just 765

The whole string has to be the offset, the hours and the minutes have to be two digits each, and the colon is required, so +0900 and +9:00 are both Nothing. RFC 3339's grammar is case insensitive, so z is accepted as well as Z.

toString : Offset -> String

Write Z, or a signed HH:MM with zero padding.

Offset.fromMinutes 765 |> Maybe.map Offset.toString
--> Just "+12:45"

Reading the result back with fromString gives the same value, including for -00:00.