pd9333 / elm-time2 / Time2

This package allows us to transfer time zone through the wire easily and tries to observe daylight saving time.

Time

epoch : Time.Posix

Unix epoch

Parts


type Parts

Keep track of each part of time. Use toParts to create parts from posix time.

import Iso8601
import Time

epoch
    |> toParts utc
    |> withYear 2022
    |> withMonth Time.Jul
    |> withDay 22
    |> withHour 14
    |> withMinute 32
    |> withSecond 17
    |> withMillis 678
    |> fromParts utc
    |> Ok
--> Iso8601.toTime "2022-07-22T14:32:17.678Z"

toParts : Zone -> Time.Posix -> Parts

Convert posix time to Parts.

fromParts : Zone -> Parts -> Time.Posix

Convert Parts back to posix time.

import Iso8601
import Time


-- Extract several eras from America/New_York for testing
-- summer : 2022-03-13T02:00:00-05:00 -> 2022-03-13T03:00:00-04:00
-- winter : 2022-11-06T02:00:00-04:00 -> 2022-11-06T01:00:00-05:00
newYork : Zone
newYork =
    customZone ""
        [ { start = 27976740, offset = -240 } -- 2023-03-12T03:00:00-04:00
        , { start = 27795240, offset = -300 } -- 2022-11-06T01:00:00-05:00
        , { start = 27452580, offset = -240 } -- 2022-03-13T03:00:00-04:00
        , { start = 27271080, offset = -300 } -- 2021-11-07T01:00:00-05:00
        ]
        -300

-- Extract several eras from Europe/Paris for testing
-- summer : 2022-03-27T02:00:00+01:00 -> 2022-03-27T03:00:00+02:00
-- winter : 2022-10-30T03:00:00+02:00 -> 2022-10-30T02:00:00+01:00
paris : Time2.Zone
paris =
    customZone ""
        [ { start = 27996540, offset = 120 } -- 2023-03-26T03:00:00+02:00
        , { start = 27784860, offset = 60 } -- 2022-10-30T02:00:00+01:00
        , { start = 27472380, offset = 120 } -- 2022-03-27T03:00:00+02:00
        , { start = 27260700, offset = 60 } -- 2021-10-31T02:00:00+01:00
        ]
        60

epoch
    |> toParts newYork
    |> withYear 2022
    |> withMonth Time.Mar
    |> withDay 13
    |> withHour 1
    |> withMinute 59
    |> withSecond 59
    |> fromParts newYork
    |> Ok
--> Iso8601.toTime "2022-03-13T01:59:59-05:00"

epoch
    |> toParts newYork
    |> withYear 2022
    |> withMonth Time.Mar
    |> withDay 13
    |> withHour 2
    |> fromParts newYork
    |> Ok
--> Iso8601.toTime "2022-03-13T03:00:00-04:00"

epoch
    |> toParts newYork
    |> withYear 2022
    |> withMonth Time.Mar
    |> withDay 13
    |> withHour 3
    |> fromParts newYork
    |> Ok
--> Iso8601.toTime "2022-03-13T03:00:00-04:00"

-- `fromParts` gives the second 01:59:59
epoch
    |> toParts newYork
    |> withYear 2022
    |> withMonth Time.Nov
    |> withDay 6
    |> withHour 1
    |> withMinute 59
    |> withSecond 59
    |> fromParts newYork
    |> Ok
--> Iso8601.toTime "2022-11-06T01:59:59-05:00"

-- `fromParts` gives the second 2022-11-06T02:00:00
epoch
    |> toParts newYork
    |> withYear 2022
    |> withMonth Time.Nov
    |> withDay 6
    |> withHour 2
    |> fromParts newYork
    |> Ok
--> Iso8601.toTime "2022-11-06T02:00:00-05:00"

epoch
    |> toParts paris
    |> withYear 2022
    |> withMonth Time.Mar
    |> withDay 27
    |> withHour 1
    |> withMinute 59
    |> withSecond 59
    |> fromParts paris
    |> Ok
--> Iso8601.toTime "2022-03-27T01:59:59+01:00"

epoch
    |> toParts paris
    |> withYear 2022
    |> withMonth Time.Mar
    |> withDay 27
    |> withHour 2
    |> fromParts paris
    |> Ok
--> Iso8601.toTime "2022-03-27T03:00:00+02:00"

epoch
    |> toParts paris
    |> withYear 2022
    |> withMonth Time.Mar
    |> withDay 27
    |> withHour 3
    |> fromParts paris
    |> Ok
--> Iso8601.toTime "2022-03-27T03:00:00+02:00"

-- `fromParts` gives the second 2022-10-30T02:59:59
epoch
    |> toParts paris
    |> withYear 2022
    |> withMonth Time.Oct
    |> withDay 30
    |> withHour 2
    |> withMinute 59
    |> withSecond 59
    |> fromParts paris
    |> Ok
--> Iso8601.toTime "2022-10-30T02:59:59+01:00"

-- `fromParts` gives the second 2022-10-30T03:00:00
epoch
    |> toParts paris
    |> withYear 2022
    |> withMonth Time.Oct
    |> withDay 30
    |> withHour 3
    |> fromParts paris
    |> Ok
--> Iso8601.toTime "2022-10-30T03:00:00+01:00"

withYear : Basics.Int -> Parts -> Parts

Set year of Parts.

withMonth : Time.Month -> Parts -> Parts

Set month of Parts.

withDay : Basics.Int -> Parts -> Parts

Set day of Parts.

withHour : Basics.Int -> Parts -> Parts

Set hour of Parts.

withMinute : Basics.Int -> Parts -> Parts

Set minute of Parts.

withSecond : Basics.Int -> Parts -> Parts

Set second of Parts.

withMillis : Basics.Int -> Parts -> Parts

Set millis of Parts.

Time Zones


type Zone

A zone is a list of eras sorted by descending order of the starting point of each era.

Note that we don't expose the variants because we don't want to bump major version of the package too often. Use customZone if we want to create a zone manually. Or create a decoder to decode the value encoded by encodeZone if we want to get the raw data, we'll try to keep encodeZone backward compatible.

getZoneName : Zone -> String

Get the name of a zone.

getZoneName utc
--> "Etc/UTC"

customZone : String -> List { start : Basics.Int, offset : Basics.Int } -> Basics.Int -> Zone

Create a zone with name, eras and offsetOfEarliestEra.

utc : Zone

utc

encodeZone : Zone -> Json.Encode.Value

Encode Zone so we can send it through wire.

import Json.Decode

zone : Zone
zone =
    customZone "Zone/Name"
        [ { start = 20, offset = 60 }
        , { start = 10, offset = -120 }
        ]
        30

zone
    |> encodeZone
    |> Json.Decode.decodeValue decoderOfZone
--> Ok zone

decoderOfZone : Json.Decode.Decoder Zone

Decode Json.Encode.Value back to Zone.

compatibility with elm/time

toElmTimeZone : Zone -> Time.Zone

This function converts Time2.Zone to Time.Zone.

import Time

start : Int
start =
    61

zone : Time.Zone
zone =
    customZone "" [ { start = start, offset = 120 } ] 0
        |> toElmTimeZone

Time.millisToPosix (start * 60 * 1000)
    |> Time.toHour zone
--> 3 -- This will be 1 once https://github.com/elm/time/issues/7 is fixed, we then need to fix our implementation

toStandardZone : Zone -> Time.Zone

Deprecated, please use toElmTimeZone as that name is less misleading.