isaacseymour / deprecated-time / Time.Date

This module defines a timezone-independent Date type which can represent any date of the proleptic Gregorian calendar.

Dates


type Date

Date is the opaque type for all Date values. Values of this type are guaranteed to represent valid proleptic Gregorian calendar dates.

Constructing Dates

date : Basics.Int -> Basics.Int -> Basics.Int -> Date

date constructs a Date value given a year, a month and a day. Invalid values are clamped to the nearest valid date.

d : Date
d =
    date 2018 5 29

year d --> 2018
month d --> 5
day d --> 29

fromTuple : ( Basics.Int, Basics.Int, Basics.Int ) -> Date

fromTuple converts a (year, month, day) tuple into a Date value.

(2018, 5, 26)
|> fromTuple
--> date 2018 5 26

toTuple : Date -> ( Basics.Int, Basics.Int, Basics.Int )

toTuple converts a Date value into a (year, month, day) tuple. This is useful if you want to use Dates as Dict keys.

date 2018 5 26
|> toTuple
--> (2018, 5, 26)

Inspecting Dates

year : Date -> Basics.Int

year returns a Date's year as an Int.

year (date 2018 5 26)
--> 2018

month : Date -> Basics.Int

month returns a Date's month as an Int. Guaranteed to be in the range [1, 12].

month (date 2018 13 26) -- Note month will be clamped
--> 12

day : Date -> Basics.Int

day returns a Date's year as an Int. Guaranteed to be valid for the Date's (year, month) pair and in the range [1, 31].

day (date 2018 2 28)
--> 28

day (date 2018 2 29)
--> 28    -- observed clamped

day (date 2000 2 29)
--> 29    -- leap year


type Weekday
    = Mon
    | Tue
    | Wed
    | Thu
    | Fri
    | Sat
    | Sun

Data type used to represent the days of the week.

weekday : Date -> Weekday

weekday returns the day of week for a given Date.

This uses Sakamoto's method to determine the day of week.

weekday (date 2018 5 26)
--> Sat

Manipulating Dates

setYear : Basics.Int -> Date -> Date

setYear updates a Date's year. Invalid values are clamped to the nearest valid date.

date 2000 5 26
|> setYear 2016
|> year
--> 2016

setMonth : Basics.Int -> Date -> Date

setMonth updates a Date's month. Invalid values are clamped to the nearest valid date.

date 2016 5 26
|> setMonth 6
|> month
--> 6

date 2016 5 26
|> setMonth 13 -- will be clamped
|> month
--> 12

setDay : Basics.Int -> Date -> Date

setDay updates a Date's day. Invalid values are clamped to the nearest valid date.

date 2016 2 26
|> setDay 28
|> day
--> 28

date 2016 2 28
|> setDay 29    -- leap year
|> day
--> 29

date 2015 2 28
|> setDay 29    -- clamped
|> day
--> 28

addYears : Basics.Int -> Date -> Date

addYears adds a relative number (positive or negative) of years to a Date, ensuring that the return value represents a valid Date. If the new date is not valid, days are subtracted from it until a valid Date can be produced.

date 2000 2 29
|> addYears -1  -- will no longer be leap year
|> day
--> 28

addMonths : Basics.Int -> Date -> Date

addMonths adds a relative number (positive or negative) of months to a Date, ensuring that the return value represents a valid Date. Its semantics are the same as addYears.

date 2018 3 31
|> addMonths -1 -- Switch to Feb
|> day
--> 28

addDays : Basics.Int -> Date -> Date

days adds an exact number (positive or negative) of days to a Date. Adding or subtracting days always produces a valid Date so there is no fuzzing logic here like there is in add{Months,Years}.

date 2018 2 28
|> addDays 1
|> month
--> 3 -- March

Comparing Dates

compare : Date -> Date -> Basics.Order

compare two Dates.

Note: since this conflicts with Basics.compare, have to preface with Time.Date.; see this example:

date 2018 1 28
|> addYears -1
|> addMonths 1
|> Time.Date.compare (date 2017 2 29)
--> EQ


type alias DateDelta =
{ years : Basics.Int
, months : Basics.Int
, days : Basics.Int 
}

DateDelta represents a delta between two dates.

delta : Date -> Date -> DateDelta

delta returns the relative number of years, months and days between two Dates.

Each field is accumulative by itself. That is, days not only shows the difference caused by the two day entries in the two Date arguments, but also the added days caused by differences in months and years. For months and years, is the count across month and year change boundaries respectively; illustrated by last example below.

-- 3 examples showing that, if the `year` and `month`
-- are the same in the two `Date` values, then the
-- `years` and `months` result values remain constant
-- in spite of large differences in the two inputs'
-- `day` setting:

delta (date 2019 1 1) (date 2018 1 1)
--> { years = 1
--> , months = 12
--> , days = 365
--> }

delta (date 2019 1 31) (date 2018 1 1)
--> { years = 1
--> , months = 12
--> , days = 395
--> }

delta (date 2019 1 1) (date 2018 1 31)
--> { years = 1
--> , months = 12
--> , days = 335
--> }

-- 1 day apart but from last day of year to first
-- day of next year:

delta (date 2019 1 1) (date 2018 12 31)
--> { years = 1
--> , months = 1
--> , days = 1
--> }

Helper functions

isValidDate : Basics.Int -> Basics.Int -> Basics.Int -> Basics.Bool

isValidDate returns True if the given year, month and day represent a valid date.

NOTE: when you create a Date using date, it does not validate the year, month, or day used; rather it just clamps out-of-range values to "legal" values without notifying you. If you are worried about complete validation, pass the 3 values to this method first and it will validate it. This gives you a chance to abort creating a "bad" Date.

isValidDate 2016 12 31
--> True

isValidDate 2016 12 32
--> False

isValidDate 2016 2 29 -- leap year
--> True

isValidDate 2018 2 29 -- not leap year
--> False

isLeapYear : Basics.Int -> Basics.Bool

isLeapYear returns True if the given year is a leap year. The rules for leap years are as follows:

daysInMonth : Basics.Int -> Basics.Int -> Basics.Int

daysInMonth returns the number of days in a month given a specific year, taking leap years into account.