-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from imclerran/add-date-time-support
Add Date, Time, and DateTime types.
- Loading branch information
Showing
20 changed files
with
1,904 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
interface Date | ||
exposes [ | ||
Date, | ||
fromUtc, | ||
fromYd, | ||
fromYmd, | ||
fromYw, | ||
fromYwd, | ||
toUtc, | ||
unixEpoch, | ||
] | ||
imports [ | ||
Const, | ||
Utc, | ||
Utils.{ | ||
isLeapYear, | ||
numDaysSinceEpoch, | ||
ymdToDaysInYear, | ||
calendarWeekToDaysInYear, | ||
} | ||
] | ||
|
||
Date : { year: I64, dayOfYear: U16 } | ||
|
||
unixEpoch : Date | ||
unixEpoch = { year: 1970, dayOfYear: 1 } | ||
|
||
fromYd : Int *, Int * -> Date | ||
fromYd = \year, dayOfYear -> { year: Num.toI64 year, dayOfYear: Num.toU16 dayOfYear } | ||
|
||
fromYmd : Int *, Int *, Int * -> Date | ||
fromYmd =\year, month, day -> | ||
{ year: Num.toI64 year, dayOfYear: ymdToDaysInYear year month day } | ||
|
||
fromYwd : Int *, Int *, Int * -> Date | ||
fromYwd = \year, week, day -> | ||
daysInYear = if isLeapYear year then 366 else 365 | ||
d = calendarWeekToDaysInYear week year |> Num.add (Num.toU64 day) | ||
if d > daysInYear then | ||
{ year: Num.toI64 (year + 1), dayOfYear: Num.toU16 (d - daysInYear) } | ||
else | ||
{ year: Num.toI64 year, dayOfYear: Num.toU16 d } | ||
|
||
fromYw : Int *, Int * -> Date | ||
fromYw = \year, week -> | ||
fromYwd year week 1 | ||
|
||
fromUtc : Utc.Utc -> Date | ||
fromUtc =\utc -> | ||
days = Utc.toNanosSinceEpoch utc |> Num.divTrunc (Const.nanosPerHour * 24) |> \d -> | ||
if Utc.toNanosSinceEpoch utc |> Num.rem (Const.nanosPerHour * 24) < 0 then d - 1 else d | ||
fromUtcHelper days 1970 | ||
|
||
fromUtcHelper : I128, I64 -> Date | ||
fromUtcHelper =\days, year -> | ||
if days < 0 then | ||
fromUtcHelper (days + if Utils.isLeapYear (year - 1) then 366 else 365) (year - 1) | ||
else | ||
daysInYear = if Utils.isLeapYear year then 366 else 365 | ||
if days >= daysInYear then | ||
fromUtcHelper (days - daysInYear) (year + 1) | ||
else | ||
{ year: year, dayOfYear: days + 1 |> Num.toU16 } | ||
|
||
toUtc : Date -> Utc.Utc | ||
toUtc =\date -> | ||
days = numDaysSinceEpoch {year: date.year |> Num.toU64, month: 1, day: 1} + (date.dayOfYear - 1 |> Num.toI64) | ||
Utc.fromNanosSinceEpoch (days |> Num.toI128 |> Num.mul (Const.nanosPerHour * 24)) | ||
|
||
|
||
# <==== TESTS ====> | ||
# <---- fromYmd ----> | ||
expect fromYmd 1970 1 1 == { year: 1970, dayOfYear: 1 } | ||
expect fromYmd 1970 12 31 == { year: 1970, dayOfYear: 365 } | ||
expect fromYmd 1972 3 1 == { year: 1972, dayOfYear: 61 } | ||
|
||
# <---- fromYwd ----> | ||
expect fromYwd 1970 1 1 == { year: 1970, dayOfYear: 1 } | ||
expect fromYwd 1970 52 5 == { year: 1971, dayOfYear: 1 } | ||
|
||
# <---- fromYw ----> | ||
expect fromYw 1970 1 == { year: 1970, dayOfYear: 1 } | ||
expect fromYw 1971 1 == { year: 1971, dayOfYear: 4 } | ||
|
||
# <---- fromUtc ----> | ||
expect | ||
utc = Utc.fromNanosSinceEpoch 0 | ||
fromUtc utc == { year: 1970, dayOfYear: 1 } | ||
|
||
expect | ||
utc = Utc.fromNanosSinceEpoch (Const.nanosPerHour * 24 * 365) | ||
fromUtc utc == { year: 1971, dayOfYear: 1 } | ||
|
||
expect | ||
utc = Utc.fromNanosSinceEpoch (Const.nanosPerHour * 24 * 365 * 2 + Const.nanosPerHour * 24 * 366) | ||
fromUtc utc == { year: 1973, dayOfYear: 1 } | ||
|
||
expect | ||
utc = Utc.fromNanosSinceEpoch (Const.nanosPerHour * 24 * -1) | ||
fromUtc utc == { year: 1969, dayOfYear: 365 } | ||
|
||
expect | ||
utc = Utc.fromNanosSinceEpoch (Const.nanosPerHour * 24 * -365) | ||
fromUtc utc == { year: 1969, dayOfYear: 1 } | ||
|
||
expect | ||
utc = Utc.fromNanosSinceEpoch (Const.nanosPerHour * 24 * -365 - Const.nanosPerHour * 24 * 366) | ||
fromUtc utc == { year: 1968, dayOfYear: 1 } | ||
|
||
expect | ||
utc = Utc.fromNanosSinceEpoch -1 | ||
fromUtc utc == { year: 1969, dayOfYear: 365 } | ||
|
||
# <---- toUtc ----> | ||
expect | ||
utc = toUtc { year: 1970, dayOfYear: 1 } | ||
utc == Utc.fromNanosSinceEpoch 0 | ||
|
||
expect | ||
utc = toUtc { year: 1970, dayOfYear: 365 } | ||
utc == Utc.fromNanosSinceEpoch (Const.nanosPerHour * 24 * 364) | ||
|
||
expect | ||
utc = toUtc { year: 1973, dayOfYear: 1 } | ||
utc == Utc.fromNanosSinceEpoch (Const.nanosPerHour * 24 * 365 * 2 + Const.nanosPerHour * 24 * 366) | ||
|
||
expect | ||
utc = toUtc { year: 1969, dayOfYear: 365 } | ||
utc == Utc.fromNanosSinceEpoch (Const.nanosPerHour * 24 * -1) | ||
|
||
expect | ||
utc = toUtc { year: 1969, dayOfYear: 1 } | ||
utc == Utc.fromNanosSinceEpoch (Const.nanosPerHour * 24 * -365) | ||
|
||
expect | ||
utc = toUtc { year: 1968, dayOfYear: 1 } | ||
utc == Utc.fromNanosSinceEpoch (Const.nanosPerHour * 24 * -365 - Const.nanosPerHour * 24 * 366) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
interface DateTime | ||
exposes [ | ||
fromUtc, | ||
fromYd, | ||
fromYmd, | ||
fromYw, | ||
fromYwd, | ||
fromYmdhms, | ||
fromYmdhmsn, | ||
toUtc, | ||
unixEpoch, | ||
] | ||
imports [ | ||
Const, | ||
Date, | ||
Time, | ||
Utc, | ||
Utc.{ Utc }, | ||
UtcTime, | ||
] | ||
|
||
DateTime : { date : Date.Date, time : Time.Time } | ||
|
||
unixEpoch : DateTime | ||
unixEpoch = { date: Date.unixEpoch, time: Time.midnight } | ||
|
||
fromYd : Int *, Int * -> DateTime | ||
fromYd = \year, day -> { date: Date.fromYd year day, time: Time.midnight } | ||
|
||
fromYmd : Int *, Int *, Int * -> DateTime | ||
fromYmd = \year, month, day -> { date: Date.fromYmd year month day, time: Time.midnight } | ||
|
||
fromYwd : Int *, Int *, Int * -> DateTime | ||
fromYwd = \year, week, day -> { date: Date.fromYwd year week day, time: Time.midnight } | ||
|
||
fromYw : Int *, Int * -> DateTime | ||
fromYw = \year, week -> { date: Date.fromYw year week, time: Time.midnight } | ||
|
||
fromYmdhms : Int *, Int *, Int *, Int *, Int *, Int * -> DateTime | ||
fromYmdhms = \year, month, day, hour, minute, second -> | ||
{ date: Date.fromYmd year month day, time: Time.fromHms hour minute second } | ||
|
||
fromYmdhmsn : Int *, Int *, Int *, Int *, Int *, Int *, Int * -> DateTime | ||
fromYmdhmsn = \year, month, day, hour, minute, second, nanosecond -> | ||
{ date: Date.fromYmd year month day, time: Time.fromHmsn hour minute second nanosecond } | ||
|
||
toUtc : DateTime -> Utc | ||
toUtc =\ dateTime -> | ||
dateNanos = Date.toUtc dateTime.date |> Utc.toNanosSinceEpoch | ||
timeNanos = Time.toUtcTime dateTime.time |> UtcTime.toNanosSinceMidnight |> Num.toI128 | ||
Utc.fromNanosSinceEpoch (dateNanos + timeNanos) | ||
|
||
expect | ||
utc = toUtc (fromYmdhmsn 1970 12 31 12 34 56 5) | ||
utc == Utc.fromNanosSinceEpoch (364 * 24 * 60 * 60 * 1_000_000_000 + 12 * 60 * 60 * 1_000_000_000 + 34 * 60 * 1_000_000_000 + 56 * 1_000_000_000 + 5) | ||
|
||
fromUtc : Utc -> DateTime | ||
fromUtc = \utc -> | ||
nanos = Utc.toNanosSinceEpoch utc | ||
timeNanos = if nanos < 0 && nanos % (Const.nanosPerHour * 24) != 0 then | ||
nanos % (Const.nanosPerHour * 24) + Const.nanosPerHour * 24 else nanos % (Const.nanosPerHour * 24) | ||
dateNanos = nanos - timeNanos |> Num.toI128 | ||
date = dateNanos |> Num.toI128 |> Utc.fromNanosSinceEpoch |> Date.fromUtc | ||
time = timeNanos |> Num.toI64 |> UtcTime.fromNanosSinceMidnight |> Time.fromUtcTime | ||
{ date, time } | ||
|
||
expect | ||
dateTime = fromUtc (Utc.fromNanosSinceEpoch (364 * 24 * Const.nanosPerHour + 12 * Const.nanosPerHour + 34 * Const.nanosPerMinute + 56 * Const.nanosPerSecond + 5)) | ||
dateTime == fromYmdhmsn 1970 12 31 12 34 56 5 | ||
|
||
expect | ||
dateTime = fromUtc (Utc.fromNanosSinceEpoch (-1)) | ||
dateTime == fromYmdhmsn 1969 12 31 23 59 59 (Const.nanosPerSecond - 1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
hasnept/roc-datetimes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
interface DateTimes.Conversion | ||
exposes [ | ||
daysInAWeek, | ||
daysToSeconds, | ||
hoursInADay, | ||
hoursToSeconds, | ||
microsecondsInAMillisecond, | ||
microsecondsInASecond, | ||
microsecondsToNanoseconds, | ||
microsecondsToWholeMilliseconds, | ||
microsecondsToWholeSeconds, | ||
millisecondsInASecond, | ||
millisecondsToMicroseconds, | ||
millisecondsToNanoseconds, | ||
millisecondsToWholeSeconds, | ||
minutesInAnHour, | ||
minutesToSeconds, | ||
nanosecondsInAMicrosecond, | ||
nanosecondsInAMillisecond, | ||
nanosecondsInASecond, | ||
nanosecondsToWholeMilliseconds, | ||
nanosecondsToWholeSeconds, | ||
nanosecondsToWholeMicroseconds, | ||
secondsInAMinute, | ||
secondsInAWeek, | ||
secondsInADay, | ||
secondsInAnHour, | ||
secondsToMicroseconds, | ||
secondsToMilliseconds, | ||
secondsToNanoseconds, | ||
secondsToWholeDays, | ||
secondsToWholeHours, | ||
secondsToWholeMinutes, | ||
secondsToWholeWeeks, | ||
weeksToSeconds, | ||
] | ||
imports [] | ||
|
||
# Constants | ||
|
||
nanosecondsInAMicrosecond = 1_000 | ||
microsecondsInAMillisecond = 1_000 | ||
millisecondsInASecond = 1_000 | ||
secondsInAMinute = 60 | ||
minutesInAnHour = 60 | ||
hoursInADay = 24 | ||
daysInAWeek = 7 | ||
|
||
microsecondsInASecond = microsecondsInAMillisecond * millisecondsInASecond | ||
nanosecondsInAMillisecond = nanosecondsInAMicrosecond * microsecondsInAMillisecond | ||
nanosecondsInASecond = nanosecondsInAMicrosecond * microsecondsInASecond | ||
secondsInADay = secondsInAMinute * minutesInAnHour * hoursInADay | ||
secondsInAnHour = secondsInAMinute * minutesInAnHour | ||
secondsInAWeek = secondsInAMinute * minutesInAnHour * hoursInADay * daysInAWeek | ||
|
||
# Nanoseconds | ||
|
||
nanosecondsToWholeMilliseconds = \nanoseconds -> nanoseconds // nanosecondsInAMillisecond | ||
nanosecondsToWholeSeconds = \nanoseconds -> nanoseconds // nanosecondsInASecond | ||
nanosecondsToWholeMicroseconds = \nanoseconds -> nanoseconds // nanosecondsInAMicrosecond | ||
|
||
# Microseconds | ||
|
||
microsecondsToNanoseconds = \microseconds -> microseconds * nanosecondsInAMicrosecond | ||
microsecondsToWholeMilliseconds = \microseconds -> microseconds // microsecondsInAMillisecond | ||
microsecondsToWholeSeconds = \microseconds -> microseconds // microsecondsInASecond | ||
|
||
# Milliseconds | ||
|
||
millisecondsToMicroseconds = \milliseconds -> milliseconds * microsecondsInAMillisecond | ||
millisecondsToNanoseconds = \milliseconds -> milliseconds * nanosecondsInAMillisecond | ||
millisecondsToWholeSeconds = \milliseconds -> milliseconds // millisecondsInASecond | ||
|
||
# Seconds | ||
|
||
secondsToMicroseconds = \seconds -> seconds * microsecondsInASecond | ||
secondsToMilliseconds = \seconds -> seconds * millisecondsInASecond | ||
secondsToNanoseconds = \seconds -> seconds * nanosecondsInASecond | ||
secondsToWholeDays = \seconds -> seconds // secondsInADay | ||
secondsToWholeHours = \seconds -> seconds // secondsInAnHour | ||
secondsToWholeMinutes = \seconds -> seconds // secondsInAMinute | ||
secondsToWholeWeeks = \seconds -> seconds // secondsInAWeek | ||
|
||
# Minutes | ||
|
||
minutesToSeconds = \minutes -> minutes * secondsInAMinute | ||
|
||
# Hours | ||
|
||
hoursToSeconds = \hours -> hours * secondsInAnHour | ||
|
||
# Days | ||
|
||
daysToSeconds = \days -> days * secondsInADay | ||
|
||
# Weeks | ||
|
||
weeksToSeconds = \weeks -> (Num.toI64 weeks) * secondsInAWeek |
Oops, something went wrong.