Skip to content
heff

std.localdate

Dates of the ISO calendar — the proleptic Gregorian one, of today, taken back before it was made and on without end — with no time of day and no zone: a date on a calendar on the wall, the 29th of February 2024, which is no instant, as it begins at a different one in each place. NodaTime’s LocalDate is the model. Any year is a year, the year before 1 the year 0 and the one before it -1, and the days are counted, not gone through (Howard Hinnant’s days_from_civil and civil_from_days). A date and a time of day (std.localtime) make a std.localdatetime; std.period counts what lies between two dates. Import it by a name, import std.localdate as LocalDate, as its names are short.

import std.localdate as LocalDate
-- | the last day of the month the date is in
-- | >>> maybe "" (\d -> show (lastOfMonth d)) (LocalDate.parse "2024-02-10")
-- | "2024-02-29"
lastOfMonth : LocalDate.LocalDate -> LocalDate.LocalDate
lastOfMonth d =
LocalDate.plusDays
d
(LocalDate.daysInMonth (LocalDate.year d) (LocalDate.month d)
- LocalDate.day d)

DayOfWeek

data DayOfWeek
= Monday
| Tuesday
| Wednesday
| Thursday
| Friday
| Saturday
| Sunday

A day of the week, ISO 8601’s: Monday first.

instanceEqualityDayOfWeek

instance instanceEqualityDayOfWeek : Equality DayOfWeek

The same day.

instanceDebugDayOfWeek

instance instanceDebugDayOfWeek : Debug DayOfWeek

As its tag: Monday.

instanceShowDayOfWeek

instance instanceShowDayOfWeek : Show DayOfWeek

Its name, in English: Monday.

>>> show (Sunday : DayOfWeek)
"Sunday"

LocalDate

data LocalDate

A date: its year, its month 1 to 12 and its day 1 to the month’s last, as make checks them.

isLeapYear

isLeapYear : Int -> Bool

Whether the year has a February 29: one divided by 4, but not by 100 unless by 400.

>>> List.map isLeapYear [2024, 2023, 2000, 1900, 0, -4, -100]
[True, False, True, False, True, True, False]

daysInMonth

daysInMonth : Int -> Int -> Int

How many days the month 1 to 12 of the year has; a month out of 1 to 12, none.

>>> List.map (daysInMonth 2024) [1, 2, 4, 12, 0, 13]
[31, 29, 30, 31, 0, 0]
>>> daysInMonth 2023 2
28

make

make : Int -> Int -> Int -> Maybe LocalDate

The date of the year, month and day, if the month is 1 to 12 and the day 1 to the month’s last; nothing if not.

>>> make 2024 2 29
Just (MkLocalDate 2024 2 29)
>>> (List.map (\m -> maybe False (\_ -> True) (make 2023 m 29)) [2, 13] : List Bool)
[False, False]
>>> (List.map (\d -> maybe True (\_ -> False) d) [make 2024 0 1, make 2024 4 31, make 2024 1 0, make 2100 2 29] : List Bool)
[True, True, True, True]

year

year : LocalDate -> Int

Its year.

month

month : LocalDate -> Int

Its month, 1 to 12.

day

day : LocalDate -> Int

Its day of the month, 1 to 31.

epochDays

epochDays : LocalDate -> Int

The days from 1970-01-01 to the date; before it, fewer than none (Howard Hinnant’s days_from_civil).

>>> List.map (\d -> maybe 0 epochDays d) [make 1970 1 1, make 2024 2 29, make 1969 12 31, make 0 1 1]
[0, 19782, -1, -719528]

fromEpochDays

fromEpochDays : Int -> LocalDate

The date n days after 1970-01-01, before it for fewer than none: epochDays’ inverse (Howard Hinnant’s civil_from_days).

>>> List.map fromEpochDays [0, 19782, -1, -719529]
[MkLocalDate 1970 1 1, MkLocalDate 2024 2 29, MkLocalDate 1969 12 31, MkLocalDate (-1) 12 31]

instanceEqualityLocalDate

instance instanceEqualityLocalDate : Equality LocalDate

The same date.

instanceOrderLocalDate

instance instanceOrderLocalDate : Order LocalDate

The earlier first.

>>> (MkLocalDate 2024 2 29 : LocalDate) < MkLocalDate 2024 3 1 && (MkLocalDate (-1) 12 31 : LocalDate) < MkLocalDate 0 1 1
True

instanceDebugLocalDate

instance instanceDebugLocalDate : Debug LocalDate

As show writes it, 2024-02-29, as NodaTime’s and Rust’s chrono’s debug form is.

>>> debug (MkLocalDate 2024 2 29 : LocalDate)
"2024-02-29"

instanceShowLocalDate

instance instanceShowLocalDate : Show LocalDate

As ISO 8601 writes it, 2024-02-29: the year in at least 4 digits, one before year 0 after a - (-0001-12-31), as Go writes them, though parse reads only the years 0000 to 9999.

>>> List.map show ([MkLocalDate 2024 2 29, MkLocalDate 33 1 1, MkLocalDate 0 1 1, MkLocalDate (-1) 12 31, MkLocalDate 10000 1 1] : List LocalDate)
["2024-02-29", "0033-01-01", "0000-01-01", "-0001-12-31", "10000-01-01"]

dayOfWeek

dayOfWeek : LocalDate -> DayOfWeek

The day of the week of the date.

>>> List.map dayOfWeek [MkLocalDate 1970 1 1, MkLocalDate 2024 2 29, MkLocalDate 2024 10 27, MkLocalDate 2000 1 1, MkLocalDate 0 1 1]
[Thursday, Thursday, Sunday, Saturday, Saturday]

dayOfYear

dayOfYear : LocalDate -> Int

The day of the year of the date, 1 to 366.

>>> List.map dayOfYear [MkLocalDate 2024 1 1, MkLocalDate 2024 12 31, MkLocalDate 2023 3 1, MkLocalDate 2024 3 1]
[1, 366, 60, 61]

plusDays

plusDays : LocalDate -> Int -> LocalDate

The date n days after it, before it for fewer than none.

>>> List.map (\n -> show (plusDays (MkLocalDate 2024 2 28) n)) [1, 2, -59, 366]
["2024-02-29", "2024-03-01", "2023-12-31", "2025-02-28"]

plusMonths

plusMonths : LocalDate -> Int -> LocalDate

The date n months after it, before it for fewer than none: the same day of that month, or its last if it has fewer days (January 31 and a month, February 29 in 2024).

>>> List.map (\n -> show (plusMonths (MkLocalDate 2024 1 31) n)) [1, 2, 3, -2, 13, -25]
["2024-02-29", "2024-03-31", "2024-04-30", "2023-11-30", "2025-02-28", "2021-12-31"]

plusYears

plusYears : LocalDate -> Int -> LocalDate

The date n years after it, before it for fewer than none: the same day of the same month, February 29 out of a leap year the 28th.

>>> List.map (\n -> show (plusYears (MkLocalDate 2024 2 29) n)) [1, 4, -1, -2025]
["2025-02-28", "2028-02-29", "2023-02-28", "-0001-02-28"]

parse

parse : String -> Maybe LocalDate

The date ISO 8601 writes as s, extended: 2024-02-29, the year in exactly 4 digits, 0000 to 9999, the month and the day in 2. Nothing if it writes none, or a field is out of its range.

>>> List.map (\s -> maybe "" show (parse s)) ["2024-02-29", "0000-01-01", "9999-12-31"]
["2024-02-29", "0000-01-01", "9999-12-31"]
>>> (List.map (\s -> maybe True (\_ -> False) (parse s)) ["2023-02-29", "2024-13-01", "2024-00-10", "2024-04-31", "2024-1-01", "24-01-01", "-0001-01-01", "10000-01-01", "2024/01/01", "2024-01-01T", "20240101", ""] : List Bool)
[True, True, True, True, True, True, True, True, True, True, True, True]
>>> List.all (\n -> parse (show (fromEpochDays n)) == Just (fromEpochDays n)) [-719528, -1, 0, 19782, 2932896]
True