Moved DateTime functionality into separate file
This commit is contained in:
parent
70574329fc
commit
bb5af13ddc
|
@ -5,22 +5,22 @@ let dateDispatch = (call: ExpressionValue.functionCall, env: DistributionOperati
|
||||||
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
||||||
> => {
|
> => {
|
||||||
switch call {
|
switch call {
|
||||||
| ("toString", [EvDate(t)]) => EvString(E.Date.toString(t))->Ok->Some
|
| ("toString", [EvDate(t)]) => EvString(DateTime.Date.toString(t))->Ok->Some
|
||||||
| ("makeDateFromYear", [EvNumber(year)]) =>
|
| ("makeDateFromYear", [EvNumber(year)]) =>
|
||||||
switch E.Date.makeFromYear(year) {
|
switch DateTime.Date.makeFromYear(year) {
|
||||||
| Ok(t) => EvDate(t)->Ok->Some
|
| Ok(t) => EvDate(t)->Ok->Some
|
||||||
| Error(e) => RETodo(e)->Error->Some
|
| Error(e) => RETodo(e)->Error->Some
|
||||||
}
|
}
|
||||||
| ("dateFromNumber", [EvNumber(f)]) => EvDate(E.Date.fromFloat(f))->Ok->Some
|
| ("dateFromNumber", [EvNumber(f)]) => EvDate(DateTime.Date.fromFloat(f))->Ok->Some
|
||||||
| ("toNumber", [EvDate(f)]) => EvNumber(E.Date.toFloat(f))->Ok->Some
|
| ("toNumber", [EvDate(f)]) => EvNumber(DateTime.Date.toFloat(f))->Ok->Some
|
||||||
| ("subtract", [EvDate(d1), EvDate(d2)]) =>
|
| ("subtract", [EvDate(d1), EvDate(d2)]) =>
|
||||||
switch E.Date.subtract(d1, d2) {
|
switch DateTime.Date.subtract(d1, d2) {
|
||||||
| Ok(d) => EvTimeDuration(d)->Ok
|
| Ok(d) => EvTimeDuration(d)->Ok
|
||||||
| Error(e) => Error(RETodo(e))
|
| Error(e) => Error(RETodo(e))
|
||||||
}->Some
|
}->Some
|
||||||
| ("subtract", [EvDate(d1), EvTimeDuration(d2)]) =>
|
| ("subtract", [EvDate(d1), EvTimeDuration(d2)]) =>
|
||||||
EvDate(E.Date.subtractDuration(d1, d2))->Ok->Some
|
EvDate(DateTime.Date.subtractDuration(d1, d2))->Ok->Some
|
||||||
| ("add", [EvDate(d1), EvTimeDuration(d2)]) => EvDate(E.Date.addDuration(d1, d2))->Ok->Some
|
| ("add", [EvDate(d1), EvTimeDuration(d2)]) => EvDate(DateTime.Date.addDuration(d1, d2))->Ok->Some
|
||||||
| _ => None
|
| _ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,23 +29,23 @@ let durationDispatch = (call: ExpressionValue.functionCall, _: DistributionOpera
|
||||||
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
||||||
> => {
|
> => {
|
||||||
switch call {
|
switch call {
|
||||||
| ("toString", [EvTimeDuration(t)]) => EvString(E.Duration.toString(t))->Ok->Some
|
| ("toString", [EvTimeDuration(t)]) => EvString(DateTime.Duration.toString(t))->Ok->Some
|
||||||
| ("hours", [EvNumber(f)]) => EvTimeDuration(E.Duration.fromHours(f))->Ok->Some
|
| ("hours", [EvNumber(f)]) => EvTimeDuration(DateTime.Duration.fromHours(f))->Ok->Some
|
||||||
| ("minutes", [EvNumber(f)]) => EvTimeDuration(E.Duration.fromMinutes(f))->Ok->Some
|
| ("minutes", [EvNumber(f)]) => EvTimeDuration(DateTime.Duration.fromMinutes(f))->Ok->Some
|
||||||
| ("days", [EvNumber(f)]) => EvTimeDuration(E.Duration.fromDays(f))->Ok->Some
|
| ("days", [EvNumber(f)]) => EvTimeDuration(DateTime.Duration.fromDays(f))->Ok->Some
|
||||||
| ("years", [EvNumber(f)]) => EvTimeDuration(E.Duration.fromYears(f))->Ok->Some
|
| ("years", [EvNumber(f)]) => EvTimeDuration(DateTime.Duration.fromYears(f))->Ok->Some
|
||||||
| ("toHours", [EvTimeDuration(f)]) => EvNumber(E.Duration.toHours(f))->Ok->Some
|
| ("toHours", [EvTimeDuration(f)]) => EvNumber(DateTime.Duration.toHours(f))->Ok->Some
|
||||||
| ("toMinutes", [EvTimeDuration(f)]) => EvNumber(E.Duration.toMinutes(f))->Ok->Some
|
| ("toMinutes", [EvTimeDuration(f)]) => EvNumber(DateTime.Duration.toMinutes(f))->Ok->Some
|
||||||
| ("toDays", [EvTimeDuration(f)]) => EvNumber(E.Duration.toDays(f))->Ok->Some
|
| ("toDays", [EvTimeDuration(f)]) => EvNumber(DateTime.Duration.toDays(f))->Ok->Some
|
||||||
| ("toYears", [EvTimeDuration(f)]) => EvNumber(E.Duration.toYears(f))->Ok->Some
|
| ("toYears", [EvTimeDuration(f)]) => EvNumber(DateTime.Duration.toYears(f))->Ok->Some
|
||||||
| ("add", [EvTimeDuration(d1), EvTimeDuration(d2)]) =>
|
| ("add", [EvTimeDuration(d1), EvTimeDuration(d2)]) =>
|
||||||
EvTimeDuration(E.Duration.add(d1, d2))->Ok->Some
|
EvTimeDuration(DateTime.Duration.add(d1, d2))->Ok->Some
|
||||||
| ("subtract", [EvTimeDuration(d1), EvTimeDuration(d2)]) =>
|
| ("subtract", [EvTimeDuration(d1), EvTimeDuration(d2)]) =>
|
||||||
EvTimeDuration(E.Duration.subtract(d1, d2))->Ok->Some
|
EvTimeDuration(DateTime.Duration.subtract(d1, d2))->Ok->Some
|
||||||
| ("multiply", [EvTimeDuration(d1), EvNumber(d2)]) =>
|
| ("multiply", [EvTimeDuration(d1), EvNumber(d2)]) =>
|
||||||
EvTimeDuration(E.Duration.multiply(d1, d2))->Ok->Some
|
EvTimeDuration(DateTime.Duration.multiply(d1, d2))->Ok->Some
|
||||||
| ("divide", [EvTimeDuration(d1), EvNumber(d2)]) =>
|
| ("divide", [EvTimeDuration(d1), EvNumber(d2)]) =>
|
||||||
EvTimeDuration(E.Duration.divide(d1, d2))->Ok->Some
|
EvTimeDuration(DateTime.Duration.divide(d1, d2))->Ok->Some
|
||||||
| _ => None
|
| _ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,8 +53,8 @@ let rec toString = aValue =>
|
||||||
| EvSymbol(aString) => `:${aString}`
|
| EvSymbol(aString) => `:${aString}`
|
||||||
| EvRecord(aRecord) => aRecord->toStringRecord
|
| EvRecord(aRecord) => aRecord->toStringRecord
|
||||||
| EvDistribution(dist) => GenericDist.toString(dist)
|
| EvDistribution(dist) => GenericDist.toString(dist)
|
||||||
| EvDate(date) => E.Date.toString(date)
|
| EvDate(date) => DateTime.Date.toString(date)
|
||||||
| EvTimeDuration(t) => E.Duration.toString(t)
|
| EvTimeDuration(t) => DateTime.Duration.toString(t)
|
||||||
}
|
}
|
||||||
and toStringRecord = aRecord => {
|
and toStringRecord = aRecord => {
|
||||||
let pairs =
|
let pairs =
|
||||||
|
|
79
packages/squiggle-lang/src/rescript/Utility/DateTime.res
Normal file
79
packages/squiggle-lang/src/rescript/Utility/DateTime.res
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
module Duration = {
|
||||||
|
//Stores in Unix milliseconds
|
||||||
|
type t = float
|
||||||
|
let minute = Belt.Float.fromInt(60 * 1000)
|
||||||
|
let hour = Belt.Float.fromInt(60 * 60 * 1000)
|
||||||
|
let day = Belt.Float.fromInt(24 * 60 * 60 * 1000)
|
||||||
|
let year = Belt.Float.fromInt(24 * 60 * 60 * 1000) *. 365.25
|
||||||
|
let fromFloat = (f: float): t => f
|
||||||
|
let toFloat = (d: t): float => d
|
||||||
|
let fromMinutes = (h: float): t => h *. minute
|
||||||
|
let fromHours = (h: float): t => h *. hour
|
||||||
|
let fromDays = (d: float): t => d *. day
|
||||||
|
let fromYears = (y: float): t => y *. year
|
||||||
|
let toMinutes = (t: t): float => t /. minute
|
||||||
|
let toHours = (t: t): float => t /. hour
|
||||||
|
let toDays = (t: t): float => t /. day
|
||||||
|
let toYears = (t: t): float => t /. year
|
||||||
|
|
||||||
|
let toString = (t: t): string => {
|
||||||
|
let shouldPluralize = f => f != 1.0
|
||||||
|
let display = (f: float, s: string) =>
|
||||||
|
`${E.Float.with3DigitsPrecision(f)} ${s}${shouldPluralize(f) ? "s" : ""}`
|
||||||
|
let abs = Js.Math.abs_float(t)
|
||||||
|
if abs >= year {
|
||||||
|
display(t /. year, "year")
|
||||||
|
} else if abs >= day {
|
||||||
|
display(t /. day, "day")
|
||||||
|
} else if abs >= hour {
|
||||||
|
display(t /. hour, "hour")
|
||||||
|
} else if abs >= minute {
|
||||||
|
display(t /. minute, "minute")
|
||||||
|
} else {
|
||||||
|
E.Float.toFixed(t) ++ "ms"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let add = (t1: t, t2: t): t => t1 +. t2
|
||||||
|
let subtract = (t1: t, t2: t): t => t1 -. t2
|
||||||
|
let multiply = (t1: t, t2: float): t => t1 *. t2
|
||||||
|
let divide = (t1: t, t2: float): t => t1 /. t2
|
||||||
|
}
|
||||||
|
|
||||||
|
module Date = {
|
||||||
|
//The Rescript/JS implementation of Date is pretty mediocre. It would be good to improve upon later.
|
||||||
|
type t = Js.Date.t
|
||||||
|
let toFloat = Js.Date.getTime
|
||||||
|
let getFullYear = Js.Date.getFullYear
|
||||||
|
let toString = Js.Date.toDateString
|
||||||
|
let fromFloat = Js.Date.fromFloat
|
||||||
|
let fmap = (t: t, fn: float => float) => t->toFloat->fn->fromFloat
|
||||||
|
let subtract = (t1: t, t2: t) => {
|
||||||
|
let (f1, f2) = (toFloat(t1), toFloat(t2))
|
||||||
|
let diff = f1 -. f2
|
||||||
|
if diff < 0.0 {
|
||||||
|
Error("Cannot subtract a date by one that is in its future")
|
||||||
|
} else {
|
||||||
|
Ok(Duration.fromFloat(diff))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let addDuration = (t: t, duration: Duration.t) => fmap(t, t => t +. duration)
|
||||||
|
let subtractDuration = (t: t, duration: Duration.t) => fmap(t, t => t -. duration)
|
||||||
|
//The Js.Date.makeWithYM function accepts a float, but only treats it as a whole number.
|
||||||
|
//Our version takes an integer to make this distinction clearer.
|
||||||
|
let makeWithYearInt = (y: int): result<t, string> => {
|
||||||
|
if y < 100 {
|
||||||
|
Error("Year must be over 100")
|
||||||
|
} else if y > 200000 {
|
||||||
|
Error("Year must be less than 200000")
|
||||||
|
} else {
|
||||||
|
Ok(Js.Date.makeWithYM(~year=Belt.Float.fromInt(y), ~month=0.0, ()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let makeFromYear = (year: float): result<t, string> => {
|
||||||
|
let floor = year->Js.Math.floor_float
|
||||||
|
makeWithYearInt(Belt.Float.toInt(floor))->E.R2.fmap(earlyDate => {
|
||||||
|
let diff = year -. floor
|
||||||
|
earlyDate->addDuration(diff *. Duration.year)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -832,84 +832,4 @@ module JsArray = {
|
||||||
|> Js.Array.filter(O.isSome)
|
|> Js.Array.filter(O.isSome)
|
||||||
|> Js.Array.map(O.toExn("Warning: This should not have happened"))
|
|> Js.Array.map(O.toExn("Warning: This should not have happened"))
|
||||||
let filter = Js.Array.filter
|
let filter = Js.Array.filter
|
||||||
}
|
}
|
||||||
|
|
||||||
module Duration = {
|
|
||||||
//Stores in Unix milliseconds
|
|
||||||
type t = float
|
|
||||||
let minute = Belt.Float.fromInt(60 * 1000)
|
|
||||||
let hour = Belt.Float.fromInt(60 * 60 * 1000)
|
|
||||||
let day = Belt.Float.fromInt(24 * 60 * 60 * 1000)
|
|
||||||
let year = Belt.Float.fromInt(24 * 60 * 60 * 1000) *. 365.25
|
|
||||||
let fromFloat = (f: float): t => f
|
|
||||||
let toFloat = (d: t): float => d
|
|
||||||
let fromMinutes = (h: float): t => h *. minute
|
|
||||||
let fromHours = (h: float): t => h *. hour
|
|
||||||
let fromDays = (d: float): t => d *. day
|
|
||||||
let fromYears = (y: float): t => y *. year
|
|
||||||
let toMinutes = (t: t): float => t /. minute
|
|
||||||
let toHours = (t: t): float => t /. hour
|
|
||||||
let toDays = (t: t): float => t /. day
|
|
||||||
let toYears = (t: t): float => t /. year
|
|
||||||
|
|
||||||
let toString = (t: t): string => {
|
|
||||||
let shouldPluralize = f => f != 1.0
|
|
||||||
let display = (f: float, s: string) =>
|
|
||||||
`${Float.with3DigitsPrecision(f)} ${s}${shouldPluralize(f) ? "s" : ""}`
|
|
||||||
let abs = Js.Math.abs_float(t)
|
|
||||||
if abs >= year {
|
|
||||||
display(t /. year, "year")
|
|
||||||
} else if abs >= day {
|
|
||||||
display(t /. day, "day")
|
|
||||||
} else if abs >= hour {
|
|
||||||
display(t /. hour, "hour")
|
|
||||||
} else if abs >= minute {
|
|
||||||
display(t /. minute, "minute")
|
|
||||||
} else {
|
|
||||||
Float.toFixed(t) ++ "ms"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let add = (t1: t, t2: t): t => t1 +. t2
|
|
||||||
let subtract = (t1: t, t2: t): t => t1 -. t2
|
|
||||||
let multiply = (t1: t, t2: float): t => t1 *. t2
|
|
||||||
let divide = (t1: t, t2: float): t => t1 /. t2
|
|
||||||
}
|
|
||||||
|
|
||||||
module Date = {
|
|
||||||
//The Rescript/JS implementation of Date is pretty mediocre. It would be good to improve upon later.
|
|
||||||
type t = Js.Date.t
|
|
||||||
let toFloat = Js.Date.getTime
|
|
||||||
let getFullYear = Js.Date.getFullYear
|
|
||||||
let toString = Js.Date.toDateString
|
|
||||||
let fromFloat = Js.Date.fromFloat
|
|
||||||
let fmap = (t: t, fn: float => float) => t->toFloat->fn->fromFloat
|
|
||||||
let subtract = (t1: t, t2: t) => {
|
|
||||||
let (f1, f2) = (toFloat(t1), toFloat(t2))
|
|
||||||
let diff = f1 -. f2
|
|
||||||
if diff < 0.0 {
|
|
||||||
Error("Cannot subtract a date by one that is in its future")
|
|
||||||
} else {
|
|
||||||
Ok(Duration.fromFloat(diff))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let addDuration = (t: t, duration: Duration.t) => fmap(t, t => t +. duration)
|
|
||||||
let subtractDuration = (t: t, duration: Duration.t) => fmap(t, t => t -. duration)
|
|
||||||
//The Js.Date.makeWithYM function accepts a float, but only treats it as a whole number.
|
|
||||||
//Our version takes an integer to make this distinction clearer.
|
|
||||||
let makeWithYearInt = (y: int): result<t, string> => {
|
|
||||||
if y < 100 {
|
|
||||||
Error("Year must be over 100")
|
|
||||||
} else if y > 200000 {
|
|
||||||
Error("Year must be less than 200000")
|
|
||||||
} else {
|
|
||||||
Ok(Js.Date.makeWithYM(~year=Belt.Float.fromInt(y), ~month=0.0, ()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let makeFromYear = (year: float): result<t, string> => {
|
|
||||||
let floor = year->Js.Math.floor_float
|
|
||||||
makeWithYearInt(Belt.Float.toInt(floor))->R2.fmap(earlyDate => {
|
|
||||||
let diff = year -. floor
|
|
||||||
earlyDate->addDuration(diff *. Duration.year)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user