miso-1.12.0.0: src/Miso/Date.hs
-----------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-----------------------------------------------------------------------------
-- |
-- Module : Miso.Date
-- Copyright : (C) 2016-2026 David M. Johnson
-- License : BSD3-style (see the file LICENSE)
-- Maintainer : David M. Johnson <code@dmj.io>
-- Stability : experimental
-- Portability : non-portable
--
-- = Overview
--
-- "Miso.Date" is a Haskell wrapper around the JavaScript
-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date Date>
-- object. A 'Date' value lives in JavaScript memory and represents a single
-- point in time. All operations run in 'IO' and call through to the
-- underlying JS object.
--
-- Import qualified to avoid clashing with 'Prelude':
--
-- @
-- import qualified "Miso.Date" as D
-- @
--
-- = Quick start
--
-- @
-- import qualified "Miso.Date" as D
--
-- example :: IO ()
-- example = do
-- now <- D.'new'
-- iso <- D.'toISOString' now -- e.g. \"2026-06-23T12:00:00.000Z\"
-- year <- D.'getFullYear' now -- e.g. 2026
-- ms <- D.'valueOf' now -- milliseconds since Unix epoch
-- pure ()
-- @
--
-- = API groups
--
-- * __Construction__: 'new'
-- * __Conversion__ (strings): 'toDateString', 'toISOString', 'toJSON',
-- 'toLocaleDateString', 'toLocaleString', 'toLocaleTimeString',
-- 'toString', 'toTimeString', 'toUTCString'
-- * __Conversion__ (numeric): 'valueOf' (ms since epoch)
-- * __Local getters__: 'getDate', 'getDay', 'getFullYear', 'getHours',
-- 'getMilliseconds', 'getMinutes', 'getMonth', 'getSeconds',
-- 'getTime', 'getTimezoneOffset'
-- * __UTC getters__: 'getUTCDate', 'getUTCDay', 'getUTCFullYear',
-- 'getUTCHours', 'getUTCMilliseconds', 'getUTCMinutes',
-- 'getUTCMonth', 'getUTCSeconds'
-- * __Local setters__: 'setDate', 'setFullYear', 'setHours',
-- 'setMilliseconds', 'setMinutes', 'setMonth', 'setSeconds', 'setTime'
-- * __UTC setters__: 'setUTCDate', 'setUTCFullYear', 'setUTCHours',
-- 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds'
--
-- __Note__: JavaScript months are __0-indexed__ (January = 0, December = 11).
-- All getter and setter functions in this module follow that convention.
-- Setter functions return the new timestamp as milliseconds since the Unix
-- epoch (a 'Double'), mirroring the JavaScript return value.
--
-- = See also
--
-- * "Miso.DSL" — 'Miso.DSL.JSVal' and marshaling used internally
-----------------------------------------------------------------------------
module Miso.Date
( -- * Type
Date
-- * Construction
, new
-- * Conversion
, toDateString
, toISOString
, toJSON
, toLocaleDateString
, toLocaleString
, toLocaleTimeString
, toString
, toTimeString
, toUTCString
, valueOf
-- * Getters
, getDate
, getDay
, getFullYear
, getHours
, getMilliseconds
, getMinutes
, getMonth
, getSeconds
, getTime
, getTimezoneOffset
, getUTCDate
, getUTCDay
, getUTCFullYear
, getUTCHours
, getUTCMilliseconds
, getUTCMinutes
, getUTCMonth
, getUTCSeconds
-- * Setters
, setDate
, setFullYear
, setHours
, setMilliseconds
, setMinutes
, setMonth
, setSeconds
, setTime
, setUTCDate
, setUTCFullYear
, setUTCHours
, setUTCMilliseconds
, setUTCMinutes
, setUTCMonth
, setUTCSeconds
) where
-----------------------------------------------------------------------------
import Data.Maybe (catMaybes)
-----------------------------------------------------------------------------
import Miso.DSL (jsg, JSVal, ToJSVal, FromJSVal, ToObject)
import qualified Miso.DSL as DSL
import Miso.FFI (callFunction)
import Miso.String (MisoString)
-----------------------------------------------------------------------------
newtype Date = Date JSVal deriving (FromJSVal, ToJSVal, ToObject, Eq)
-----------------------------------------------------------------------------
-- | Constructs a new JS [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) in t'IO'.
--
new :: IO Date
new = Date <$> DSL.new (jsg "Date") ([] :: [JSVal])
-----------------------------------------------------------------------------
call0 :: FromJSVal a => Date -> MisoString -> IO a
call0 (Date d) name = DSL.fromJSValUnchecked =<< callFunction d name ([] :: [JSVal])
-----------------------------------------------------------------------------
callArgs :: FromJSVal a => Date -> MisoString -> [JSVal] -> IO a
callArgs (Date d) name args = DSL.fromJSValUnchecked =<< callFunction d name args
-----------------------------------------------------------------------------
-- | Returns a human-readable date string.
--
-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toDateString>
--
toDateString :: Date -> IO MisoString
toDateString date = call0 date "toDateString"
-----------------------------------------------------------------------------
-- | Returns an ISO 8601 string.
--
-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString>
--
toISOString :: Date -> IO MisoString
toISOString date = call0 date "toISOString"
-----------------------------------------------------------------------------
-- | Returns the JSON representation of the date.
--
-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toJSON>
--
toJSON :: Date -> IO MisoString
toJSON date = call0 date "toJSON"
-----------------------------------------------------------------------------
-- | Returns a locale-sensitive date string.
--
-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString>
--
toLocaleDateString :: Date -> IO MisoString
toLocaleDateString date = call0 date "toLocaleDateString"
-----------------------------------------------------------------------------
-- | Returns a locale-sensitive date and time string.
--
-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString>
--
toLocaleString :: Date -> IO MisoString
toLocaleString date = call0 date "toLocaleString"
-----------------------------------------------------------------------------
-- | Returns a locale-sensitive time string.
--
-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString>
--
toLocaleTimeString :: Date -> IO MisoString
toLocaleTimeString date = call0 date "toLocaleTimeString"
-----------------------------------------------------------------------------
-- | Returns the full date string.
--
-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toString>
--
toString :: Date -> IO MisoString
toString date = call0 date "toString"
-----------------------------------------------------------------------------
-- | Returns a time string.
--
-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toTimeString>
--
toTimeString :: Date -> IO MisoString
toTimeString date = call0 date "toTimeString"
-----------------------------------------------------------------------------
-- | Returns a UTC string.
--
-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toUTCString>
--
toUTCString :: Date -> IO MisoString
toUTCString date = call0 date "toUTCString"
-----------------------------------------------------------------------------
-- | Returns the primitive value (milliseconds since epoch).
--
-- <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/valueOf>
--
valueOf :: Date -> IO Double
valueOf date = call0 date "valueOf"
-----------------------------------------------------------------------------
-- | Returns the day of the month.
--
getDate :: Date -> IO Int
getDate date = call0 date "getDate"
-----------------------------------------------------------------------------
-- | Returns the day of the week.
--
getDay :: Date -> IO Int
getDay date = call0 date "getDay"
-----------------------------------------------------------------------------
-- | Returns the full year.
--
getFullYear :: Date -> IO Int
getFullYear date = call0 date "getFullYear"
-----------------------------------------------------------------------------
-- | Returns the hour.
--
getHours :: Date -> IO Int
getHours date = call0 date "getHours"
-----------------------------------------------------------------------------
-- | Returns the milliseconds.
--
getMilliseconds :: Date -> IO Int
getMilliseconds date = call0 date "getMilliseconds"
-----------------------------------------------------------------------------
-- | Returns the minutes.
--
getMinutes :: Date -> IO Int
getMinutes date = call0 date "getMinutes"
-----------------------------------------------------------------------------
-- | Returns the month (0-11).
--
getMonth :: Date -> IO Int
getMonth date = call0 date "getMonth"
-----------------------------------------------------------------------------
-- | Returns the seconds.
--
getSeconds :: Date -> IO Int
getSeconds date = call0 date "getSeconds"
-----------------------------------------------------------------------------
-- | Returns milliseconds since epoch.
--
getTime :: Date -> IO Double
getTime date = call0 date "getTime"
-----------------------------------------------------------------------------
-- | Returns the time zone offset in minutes.
--
getTimezoneOffset :: Date -> IO Int
getTimezoneOffset date = call0 date "getTimezoneOffset"
-----------------------------------------------------------------------------
-- | Returns the UTC day of the month.
--
getUTCDate :: Date -> IO Int
getUTCDate date = call0 date "getUTCDate"
-----------------------------------------------------------------------------
-- | Returns the UTC day of the week.
--
getUTCDay :: Date -> IO Int
getUTCDay date = call0 date "getUTCDay"
-----------------------------------------------------------------------------
-- | Returns the UTC full year.
--
getUTCFullYear :: Date -> IO Int
getUTCFullYear date = call0 date "getUTCFullYear"
-----------------------------------------------------------------------------
-- | Returns the UTC hour.
--
getUTCHours :: Date -> IO Int
getUTCHours date = call0 date "getUTCHours"
-----------------------------------------------------------------------------
-- | Returns the UTC milliseconds.
--
getUTCMilliseconds :: Date -> IO Int
getUTCMilliseconds date = call0 date "getUTCMilliseconds"
-----------------------------------------------------------------------------
-- | Returns the UTC minutes.
--
getUTCMinutes :: Date -> IO Int
getUTCMinutes date = call0 date "getUTCMinutes"
-----------------------------------------------------------------------------
-- | Returns the UTC month (0-11).
--
getUTCMonth :: Date -> IO Int
getUTCMonth date = call0 date "getUTCMonth"
-----------------------------------------------------------------------------
-- | Returns the UTC seconds.
--
getUTCSeconds :: Date -> IO Int
getUTCSeconds date = call0 date "getUTCSeconds"
-----------------------------------------------------------------------------
-- | Sets the day of the month.
--
setDate
:: Int
-- ^ Day of the month (1–31)
-> Date
-- ^ Date object to modify
-> IO Double
setDate day (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setDate" [day]
-----------------------------------------------------------------------------
-- | Sets the full year, with optional month and day.
--
setFullYear
:: Int
-- ^ Full year (e.g. 2026)
-> Maybe Int
-- ^ Optional month (0-indexed: 0 = January)
-> Maybe Int
-- ^ Optional day of the month (1–31)
-> Date
-- ^ Date object to modify
-> IO Double
setFullYear year month day (Date d) = do
y <- DSL.toJSVal year
m <- traverse DSL.toJSVal month
d' <- traverse DSL.toJSVal day
callArgs (Date d) "setFullYear" (catMaybes [Just y, m, d'])
-----------------------------------------------------------------------------
-- | Sets the hour, with optional minutes, seconds, and milliseconds.
--
setHours
:: Int
-- ^ Hour (0–23)
-> Maybe Int
-- ^ Optional minutes (0–59)
-> Maybe Int
-- ^ Optional seconds (0–59)
-> Maybe Int
-- ^ Optional milliseconds (0–999)
-> Date
-- ^ Date object to modify
-> IO Double
setHours hours minutes seconds millis (Date d) = do
h <- DSL.toJSVal hours
m <- traverse DSL.toJSVal minutes
s <- traverse DSL.toJSVal seconds
ms <- traverse DSL.toJSVal millis
callArgs (Date d) "setHours" (catMaybes [Just h, m, s, ms])
-----------------------------------------------------------------------------
-- | Sets the milliseconds.
--
setMilliseconds
:: Int
-- ^ Milliseconds (0–999)
-> Date
-- ^ Date object to modify
-> IO Double
setMilliseconds ms (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setMilliseconds" [ms]
-----------------------------------------------------------------------------
-- | Sets the minutes, with optional seconds and milliseconds.
--
setMinutes
:: Int
-- ^ Minutes (0–59)
-> Maybe Int
-- ^ Optional seconds (0–59)
-> Maybe Int
-- ^ Optional milliseconds (0–999)
-> Date
-- ^ Date object to modify
-> IO Double
setMinutes minutes seconds millis (Date d) = do
m <- DSL.toJSVal minutes
s <- traverse DSL.toJSVal seconds
ms <- traverse DSL.toJSVal millis
callArgs (Date d) "setMinutes" (catMaybes [Just m, s, ms])
-----------------------------------------------------------------------------
-- | Sets the month, with optional day of the month.
--
setMonth
:: Int
-- ^ Month (0-indexed: 0 = January, 11 = December)
-> Maybe Int
-- ^ Optional day of the month (1–31)
-> Date
-- ^ Date object to modify
-> IO Double
setMonth month day (Date d) = do
m <- DSL.toJSVal month
d' <- traverse DSL.toJSVal day
callArgs (Date d) "setMonth" (catMaybes [Just m, d'])
-----------------------------------------------------------------------------
-- | Sets the seconds, with optional milliseconds.
--
setSeconds
:: Int
-- ^ Seconds (0–59)
-> Maybe Int
-- ^ Optional milliseconds (0–999)
-> Date
-- ^ Date object to modify
-> IO Double
setSeconds seconds millis (Date d) = do
s <- DSL.toJSVal seconds
ms <- traverse DSL.toJSVal millis
callArgs (Date d) "setSeconds" (catMaybes [Just s, ms])
-----------------------------------------------------------------------------
-- | Sets the time in milliseconds since epoch.
--
setTime
:: Double
-- ^ Milliseconds since the Unix epoch (1 January 1970 00:00:00 UTC)
-> Date
-- ^ Date object to modify
-> IO Double
setTime time (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setTime" [time]
-----------------------------------------------------------------------------
-- | Sets the UTC day of the month.
--
setUTCDate
:: Int
-- ^ Day of the month in UTC (1–31)
-> Date
-- ^ Date object to modify
-> IO Double
setUTCDate day (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setUTCDate" [day]
-----------------------------------------------------------------------------
-- | Sets the UTC full year, with optional month and day.
--
setUTCFullYear
:: Int
-- ^ Full year in UTC (e.g. 2026)
-> Maybe Int
-- ^ Optional month in UTC (0-indexed)
-> Maybe Int
-- ^ Optional day in UTC (1–31)
-> Date
-- ^ Date object to modify
-> IO Double
setUTCFullYear year month day (Date d) = do
y <- DSL.toJSVal year
m <- traverse DSL.toJSVal month
d' <- traverse DSL.toJSVal day
callArgs (Date d) "setUTCFullYear" (catMaybes [Just y, m, d'])
-----------------------------------------------------------------------------
-- | Sets the UTC hour, with optional minutes, seconds, and milliseconds.
--
setUTCHours
:: Int
-- ^ Hour in UTC (0–23)
-> Maybe Int
-- ^ Optional minutes (0–59)
-> Maybe Int
-- ^ Optional seconds (0–59)
-> Maybe Int
-- ^ Optional milliseconds (0–999)
-> Date
-- ^ Date object to modify
-> IO Double
setUTCHours hours minutes seconds millis (Date d) = do
h <- DSL.toJSVal hours
m <- traverse DSL.toJSVal minutes
s <- traverse DSL.toJSVal seconds
ms <- traverse DSL.toJSVal millis
callArgs (Date d) "setUTCHours" (catMaybes [Just h, m, s, ms])
-----------------------------------------------------------------------------
-- | Sets the UTC milliseconds.
--
setUTCMilliseconds
:: Int
-- ^ Milliseconds in UTC (0–999)
-> Date
-- ^ Date object to modify
-> IO Double
setUTCMilliseconds ms (Date d) = DSL.fromJSValUnchecked =<< callFunction d "setUTCMilliseconds" [ms]
-----------------------------------------------------------------------------
-- | Sets the UTC minutes, with optional seconds and milliseconds.
--
setUTCMinutes
:: Int
-- ^ Minutes in UTC (0–59)
-> Maybe Int
-- ^ Optional seconds (0–59)
-> Maybe Int
-- ^ Optional milliseconds (0–999)
-> Date
-- ^ Date object to modify
-> IO Double
setUTCMinutes minutes seconds millis (Date d) = do
m <- DSL.toJSVal minutes
s <- traverse DSL.toJSVal seconds
ms <- traverse DSL.toJSVal millis
callArgs (Date d) "setUTCMinutes" (catMaybes [Just m, s, ms])
-----------------------------------------------------------------------------
-- | Sets the UTC month, with optional day of the month.
--
setUTCMonth
:: Int
-- ^ Month in UTC (0-indexed: 0 = January)
-> Maybe Int
-- ^ Optional day in UTC (1–31)
-> Date
-- ^ Date object to modify
-> IO Double
setUTCMonth month day (Date d) = do
m <- DSL.toJSVal month
d' <- traverse DSL.toJSVal day
callArgs (Date d) "setUTCMonth" (catMaybes [Just m, d'])
-----------------------------------------------------------------------------
-- | Sets the UTC seconds, with optional milliseconds.
--
setUTCSeconds
:: Int
-- ^ Seconds in UTC (0–59)
-> Maybe Int
-- ^ Optional milliseconds (0–999)
-> Date
-- ^ Date object to modify
-> IO Double
setUTCSeconds seconds millis (Date d) = do
s <- DSL.toJSVal seconds
ms <- traverse DSL.toJSVal millis
callArgs (Date d) "setUTCSeconds" (catMaybes [Just s, ms])
-----------------------------------------------------------------------------