Time library
Time, clocks and calendars. Port of the haskell time library to Lean 4.
SystemTime
SystemTime is time returned by system clock functions. It has a precision of one nanosecond.
structure SystemTime where
sec : Int
nsec : UInt32
-- ⊢ IO IO.FS.SystemTime
#eval getSystemTime
-- { sec := 1680959011, nsec := 928622514 }
DiffTime
DiffTime is a length of time, as measured by a clock. It has a precision of one nanosecond (Fixed 9).
structure Fixed (precision : Nat) where
val : Int
structure DiffTime where
val : Fixed 9
-- ⊢ Sign → ℕ → ℕ → DiffTime
#eval DiffTime.fromSecNsec Sign.Nonneg 1680959011 928622514
-- { val := { val := 1680959011928622514 } }
UTCTime
UTCTime is a representation of UTC. It consists of the day number, and a time offset from midnight.
structure UTCTime where
utctDay : Day
utctDayTime : DiffTime
-- ⊢ IO.FS.SystemTime → UTCTime
#eval UTCTime.toUTCTime { sec := 1680959011, nsec := 928622514 }
-- { utctDay := { modifiedJulianDay := 60042 },
-- utctDayTime := { val := { val := 47011928622514 } } }
Day
The Day data type is an abstract way of referring to a calendar date. The toGregorian and fromGregorian functions will construct and deconstruct a Day from the usual year-month-day format.
structure Day where
modifiedJulianDay : Int
-- ⊢ ℤ → ℤ → ℤ → Day
#eval fromGregorian 2023 2 12
-- { modifiedJulianDay := 59987 }
OrdinalDate
OrdinalDate is an ISO 8601 Ordinal Date.
inductive DayOfYear where
| common : Time.Icc 1 365 -> DayOfYear
| leap : Time.Icc 1 366 -> DayOfYear
structure OrdinalDate where
year : Int
dayOfYear : DayOfYear
isValid : match dayOfYear with
| .common _ => isLeapYear year = false
| .leap _ => isLeapYear year = true
-- ⊢ Day → OrdinalDate
#eval toOrdinalDate { modifiedJulianDay := 59987 }
-- { year := 2023, dayOfYear := Time.DayOfYear.common 43, isValid := __ }
Date
The Date is a calendar date in the proleptic Gregorian calendar.
structure Date where
Year : Int
Month : Time.Icc 1 12
Day : Time.Icc 1 31
IsValid : ∃ m ∈ monthLengths (isLeapYear Year), m.1 = Month ∧ Day ≤ m.2
-- ⊢ Day → Date
#eval toGregorian { modifiedJulianDay := 59987 }
-- { Year := 2023, Month := 2, Day := 12, IsValid := _ }
open Time.Notation
#eval date# 2023-2-12
-- { Year := 2023, Month := 2, Day := 12, IsValid := _ }
TimeOfDay
TimeOfDay consists of an hour of the day, a minute of the hour, and a second of the minute, including fractions of a second up to a resolution of one nanosecond.
structure TimeOfDay where
Hour : Time.Ico 0 24
Minute : Time.Ico 0 60
Second : Time.Ico ⟨0⟩ ⟨60000000000⟩
-- ⊢ DiffTime → TimeOfDay
#eval TimeOfDay.timeToTimeOfDay { val := { val := 47011928622514 } }
-- { Hour := 13, Minute := 3, Second := { val := 31928622514 } }
open Time.Notation
#eval time# 13:3:31.928622514
-- { Hour := 13, Minute := 3, Second := { val := 31928622514 } }
TimeZone
A TimeZone represents an offset from UTC measured in minutes.
structure TimeZone where
timeZoneMinutes : Int
timeZoneSummerOnly : Bool
timeZoneName : String
-- ⊢ IO TimeZone
#eval TimeZone.getTimeZone
-- { timeZoneMinutes := 120, timeZoneSummerOnly := true, timeZoneName := "CEST" }
LocalTime
A Day with a TimeOfDay forms a LocalTime.
structure LocalTime where
localDay : Day
localTimeOfDay : TimeOfDay
-- ⊢ LocalTime
#eval (⟨Time.fromGregorianDate (date% 2024-2-10), time% 12:30⟩ : LocalTime)
-- { localDay := { modifiedJulianDay := 60350 },
-- localTimeOfDay := { Hour := 12, Minute := 30, Second := { val := 0 } } }
ZonedTime
A ZonedTime is a LocalTime together with a TimeZone.
structure ZonedTime where
localTime : LocalTime
timeZone : TimeZone
-- ⊢ LocalTime → TimeZone → ZonedTime
#eval ZonedTime.mk
{ localDay := { modifiedJulianDay := 60042 },
localTimeOfDay := { Hour := ⟨15, (by simp)⟩, Minute := ⟨3, (by simp)⟩,
Second := ⟨⟨31928622514⟩, (by simp)⟩ } }
{ timeZoneMinutes := 120, timeZoneSummerOnly := true, timeZoneName := "CEST" }
-- { localTime :=
-- { localDay := { modifiedJulianDay := 60042 },
-- localTimeOfDay := { Hour := 15, Minute := 3, Second := { val := 31928622514 } } },
-- timeZone := { timeZoneMinutes := 120, timeZoneSummerOnly := true, timeZoneName := "CEST" } }
Parse
Parse a time value (i.e. instance of Time.ParseTime) given a format string.
#eval (parse .defaultTimeLocale "%Y-%m-%dT%H:%M:%S" "2023-02-12T12:24:30"
: Option LocalTime)
-- some
-- { localDay := { modifiedJulianDay := 59987 },
-- localTimeOfDay := { Hour := 12, Minute := 24,
-- Second := { val := 30000000000 } } }
Format
Format a time value (i.e. instance of Time.ToISO8601) to ISO8601.
#eval toISO8601 (default : ZonedTime)
-- "1858-11-17T00:00:00+00:00"