@@ -1,39 +1,47 @@
1−module Data.Intl.DateTimeFormat
1+module Data.Intl.DateTimeFormat
2 ( LocalesOption
2 ( LocalesOption
3 , LocaleMatcher(..)
3 , LocaleMatcher(..)
4 , TimeZone(..)
4 , TimeZone(..)
5 , FormatMatcher(..)
5 , FormatMatcher(..)
6+ , WeekdayYearMonthDayHourMinuteSecond(..)
7+ , WeekdayYearMonthDay(..)
11+ , HourMinuteSecond(..)
6 , DateTimeFormatOptions(..)
15 , DateTimeFormatOptions(..)
7 , DateTimeFormatOptions'
16 , DateTimeFormatOptions'
8 , DateTimeComponents(..)
17 , DateTimeComponents(..)
9− , DateTimeFormat
18+ , DateTimeFormatter
10− , createDateTimeFormat
19+ , createDateTimeFormatter
11 , formatJSDate
20 , formatJSDate
12 , module Data.Intl.DateTimeFormat.Types
21 , module Data.Intl.DateTimeFormat.Types
13 , supportedLocalesOf
22 , supportedLocalesOf
18import Data.Intl.DateTimeFormat.Types
25import Data.Intl.DateTimeFormat.Types
20−import Control.Monad.Error.Class (throwError)
21import Data.Either (Either(..))
27import Data.Either (Either(..))
22−import Data.Foreign (F, Foreign, ForeignError(..), isUndefined, readString)
23−import Data.Foreign.Index ((!))
24−import Data.Function.Uncurried (Fn3, Fn4, runFn3, runFn4)
28+import Data.Function.Uncurried (Fn3, runFn3)
29+import Data.Generic.Rep (class Generic)
25−import Data.Intl.DateTimeFormat.Class (class FormatComponent, FormatComponentRecord(FormatComponentRecord), formatComponent)
30+import Data.Intl.DateTimeFormat.Generic (class FormatComponent, defaultComponentRecord, formatComponent, genericFormatComponent)
26import Data.JSDate (JSDate)
31import Data.JSDate (JSDate)
27−import Data.Maybe (Maybe(..), fromMaybe, maybe)
32+import Data.Maybe (Maybe, fromMaybe, maybe)
28−import Data.Newtype (class Newtype, un)
33+import Data.Newtype (class Newtype)
29import Data.StrMap (union)
34import Data.StrMap (union)
30import Data.Symbol (SProxy(..))
35import Data.Symbol (SProxy(..))
31−import Data.Traversable (sequence)
32−import Data.Variant (Variant, case_, default, on)
36+import Data.Variant (Variant, default, on)
33−import Prelude (class Eq, class Show, Unit, bind, id, pure, show, (#), ($), (<$>), (<<<), (>>=))
37+import Prelude (class Eq, class Show, Unit, id, show, (#), ($))
34import Unsafe.Coerce (unsafeCoerce)
38import Unsafe.Coerce (unsafeCoerce)
36foreign import data LocalesOption' :: Type
40foreign import data LocalesOption' :: Type
41+foreign import data DateTimeFormat :: Type
43+foreign import data Undefined :: Type
44+foreign import undefined :: Undefined
38foreign import dateTimeFormatImpl :: LocalesOption' -> DateTimeFormatOptions_ -> DateTimeFormat
46foreign import dateTimeFormatImpl :: LocalesOption' -> DateTimeFormatOptions_ -> DateTimeFormat
@@ -86,6 +94,85 @@ instance showFormatMatcher :: Show FormatMatcher where
86 show FMBasic = "basic"
94 show FMBasic = "basic"
87 show FMBestFit = "best fit"
95 show FMBestFit = "best fit"
97+newtype WeekdayYearMonthDayHourMinuteSecond = WeekdayYearMonthDayHourMinuteSecond
98+ { weekday :: StringRep
102+ , hour :: NumericRep
103+ , minute :: NumericRep
104+ , second :: NumericRep
107+derive instance genericWeekdayYearMonthDayHourMinuteSecond :: Generic WeekdayYearMonthDayHourMinuteSecond _
109+instance formatComponentWeekdayYearMonthDayHourMinuteSecond :: FormatComponent WeekdayYearMonthDayHourMinuteSecond where
110+ formatComponent = genericFormatComponent
112+newtype WeekdayYearMonthDay = WeekdayYearMonthDay
113+ { weekday :: StringRep
114+ , year :: NumericRep
119+derive instance genericWeekdayYearMonthDay :: Generic WeekdayYearMonthDay _
121+instance formatComponentWeekdayYearMonthDay :: FormatComponent WeekdayYearMonthDay where
122+ formatComponent = genericFormatComponent
124+newtype YearMonthDay = YearMonthDay
125+ { year :: NumericRep
130+derive instance genericYearMonthDay :: Generic YearMonthDay _
132+instance formatComponentYearMonthDay :: FormatComponent YearMonthDay where
133+ formatComponent = genericFormatComponent
135+newtype YearMonth = YearMonth
136+ { year :: NumericRep
140+derive instance genericYearMonth :: Generic YearMonth _
142+instance formatComponentYearMonth :: FormatComponent YearMonth where
143+ formatComponent = genericFormatComponent
145+newtype MonthDay = MonthDay
150+derive instance genericMonthDay :: Generic MonthDay _
152+instance formatComponentMonthDay :: FormatComponent MonthDay where
153+ formatComponent = genericFormatComponent
155+newtype HourMinuteSecond = HourMinuteSecond
156+ { hour :: NumericRep
157+ , minute :: NumericRep
158+ , second :: NumericRep
161+derive instance genericHourMinuteSecond :: Generic HourMinuteSecond _
163+instance formatComponentHourMinuteSecond :: FormatComponent HourMinuteSecond where
164+ formatComponent = genericFormatComponent
166+newtype HourMinute = HourMinute
167+ { hour :: NumericRep
168+ , minute :: NumericRep
171+derive instance genericHourMinute :: Generic HourMinute _
173+instance formatComponentHourMinute :: FormatComponent HourMinute where
174+ formatComponent = genericFormatComponent
89type DateTimeComponents a =
176type DateTimeComponents a =
91 ( weekdayYearMonthDayHourMinuteSecond :: WeekdayYearMonthDayHourMinuteSecond
178 ( weekdayYearMonthDayHourMinuteSecond :: WeekdayYearMonthDayHourMinuteSecond
@@ -120,7 +207,7 @@ formatDateTimeOptions (DateTimeFormatOptions opts comps) = merge opts' (compsCoe
120 , hour12: fromMaybe (unsafeCoerce undefined) opts.hour12
207 , hour12: fromMaybe (unsafeCoerce undefined) opts.hour12
121 , formatMatcher: maybe undefinedString show opts.formatMatcher
208 , formatMatcher: maybe undefinedString show opts.formatMatcher
123− comps' = un FormatComponentRecord $ case_
210+ comps' = default (defaultComponentRecord)
124 # on (SProxy :: SProxy "weekdayYearMonthDayHourMinuteSecond") formatComponent
211 # on (SProxy :: SProxy "weekdayYearMonthDayHourMinuteSecond") formatComponent
125 # on (SProxy :: SProxy "weekdayYearMonthDay") formatComponent
212 # on (SProxy :: SProxy "weekdayYearMonthDay") formatComponent
126 # on (SProxy :: SProxy "yearMonthDay") formatComponent
213 # on (SProxy :: SProxy "yearMonthDay") formatComponent
@@ -186,158 +273,24 @@ formatDateTimeOptions (DateTimeFormatOptions opts comps) = merge opts' (compsCoe
186 -> DateTimeFormatOptions_
273 -> DateTimeFormatOptions_
187 merge a b = unsafeCoerce $ union (unsafeCoerce a) (unsafeCoerce b)
274 merge a b = unsafeCoerce $ union (unsafeCoerce a) (unsafeCoerce b)
189−foreign import data DateTimeFormat :: Type
276+foreign import data DateTimeFormatter :: Type
278+foreign import createDateTimeFormatterImpl
280+ -> DateTimeFormatOptions_
281+ -> DateTimeFormatter
191−foreign import createDateTimeFormatImpl
283+createDateTimeFormatter
193− (forall a. String -> F a)
194− (forall a. a -> F a)
196− DateTimeFormatOptions_
201−-- | import Data.Variant (inj)
203−-- | fmtHourMinute = F DateTimeFormat
204−-- | fmtHourMinute = createDateTimeFormat locale opts
206−-- | locale = inj (SProxy :: SProxy "locale") "en-GB"
207−-- | opts = (DateTimeFormatOptions
208−-- | { localeMatcher: Nothing
209−-- | , timeZone: (Just (TimeZone "Europe/London"))
210−-- | , hour12: Just false
211−-- | , formatMatcher: Nothing
213−-- | (inj (SProxy :: SProxy "hourMinute")
214−-- | (HourMinute {hour: TwoDigit, minute: TwoDigit}))
217−-- | fmtDate :: F DateTimeFormat
218−-- | fmtDate = createDateTimeFormat locale opts
220−-- | locale = inj (SProxy :: SProxy "locale") "en-GB"
221−-- | opts :: DateTimeFormatOptions'
223−-- | (DateTimeFormatOptions
224−-- | { localeMatcher: Nothing
225−-- | , timeZone: (Just (TimeZone "Europe/London"))
226−-- | , hour12: Just true
227−-- | , formatMatcher: Nothing
230−-- | (SProxy :: SProxy "weekdayYearMonthDayHourMinuteSecond")
231−-- | (WeekdayYearMonthDayHourMinuteSecond
232−-- | { weekday: Short
234−-- | , month: MonthLong
237−-- | , minute: Numeric
238−-- | , second: Numeric
244−-- | You have predifined types: `WeekdayYearMonthDayHourMinuteSecond`,
245−-- | `WeekdayYearMonthDay`, `YearMonthDay`, `YearMonth`, `MonthDay`,
246−-- | `HourMinuteSecond`, `HourMinute`. But you can also provide your own by
247−-- | implementing `FormatComponent` class (or by deriving it), e.g.
249−-- | newtype EraYear = EraYear
250−-- | { era :: StringRep
251−-- | , year :: NumericRep
254−-- | derive instance genericEraYear :: Generic EraYear _
256−-- | instance formatComponentEraYear :: FormatComponent EraYear where
257−-- | formatComponent = genericFormatComponent
259−-- | fmtEraYear :: F DateTimeFormat
260−-- | fmtEraYear = createDateTimeFormat locales opts
262−-- | locale = inj (SProxy :: SProxy "locale") "en-GB"
263−-- | opts :: DateTimeFormatOptions EraYear
265−-- | (DateTimeFormatOptions
266−-- | { localeMatcher: Nothing
267−-- | , timeZone: (Just (TimeZone "Europe/London"))
268−-- | , hour12: Just true
269−-- | , formatMatcher: Nothing
272−-- | (SProxy :: SProxy "custom")
282 :: forall a
284 :: forall a
283 .(FormatComponent a)
285 .(FormatComponent a)
284 => LocalesOption
286 => LocalesOption
285 -> DateTimeFormatOptions a
287 -> DateTimeFormatOptions a
286− -> F DateTimeFormat
288+ -> DateTimeFormatter
287−createDateTimeFormat ls opts =
288− runFn4 createDateTimeFormatImpl
289− (throwError <<< pure <<< ForeignError)
292− (formatDateTimeOptions opts)
289+createDateTimeFormatter ls opts = createDateTimeFormatterImpl (toLocale ls) (formatDateTimeOptions opts)
296−-- | formatJSDate (either (const "") id $ runExcept fmtHourMinute) date -- "12:00"
297−-- | formatJSDate (either (const "") id $ fmtDate) date -- "Tue, January 2, 2018, 12:00:00 PM"
298−-- | formatJSDate (either (const "") id $ fmtEraYear) date -- "2018 Anno Domini"
300−foreign import formatJSDate :: DateTimeFormat -> JSDate -> String
302−foreign import supportedLocalesOfImpl
304− (String -> Either String (Array String))
305− (Array String -> Either String (Array String))
307− (Either String (Array String))
309−foreign import formatToPartsImpl :: DateTimeFormat -> JSDate -> Array Foreign
311−formatToParts :: DateTimeFormat -> JSDate -> F (Array FormatParts)
312−formatToParts formatter date = sequence $ readFormatParts <$> formatToPartsImpl formatter date
314−supportedLocalesOf :: Array String -> Either String (Array String)
291+foreign import formatJSDate :: DateTimeFormatter -> JSDate -> String
315−supportedLocalesOf locales = runFn3 supportedLocalesOfImpl Left Right locales
317−foreign import resolvedOptionsImpl :: DateTimeFormat -> Foreign
293+foreign import supportedLocalesOfImpl :: Fn3 (String -> Either String (Array String)) (Array String -> Either String (Array String)) (Array String) (Either String (Array String))
319−resolvedOptions :: DateTimeFormat -> F ResolvedOptions
320−resolvedOptions fmt = do
321− locale <- obj ! "locale" >>= readString
322− calendar <- obj ! "calendar" >>= readString
323− numberingSystem <- obj ! "numberingSystem" >>= readString
324− timeZone <- obj ! "timeZone" >>= readString
325− era <- obj ! "era" >>= readMaybeString
326− weekday <- obj ! "weekday" >>= readMaybeString
327− year <- obj ! "year" >>= readMaybeString
328− day <- obj ! "day" >>= readMaybeString
329− hour <- obj ! "hour" >>= readMaybeString
330− minute <- obj ! "minute" >>= readMaybeString
331− second <- obj ! "second" >>= readMaybeString
332− timeZoneName <- obj ! "timeZoneName" >>= readMaybeString
334− pure $ ResolvedOptions { locale, calendar, numberingSystem, timeZone, era, weekday, year, day, hour, minute, second, timeZoneName }
336− where
295+supportedLocalesOf :: Array String -> Either String (Array String)
337− obj = resolvedOptionsImpl fmt
296+supportedLocalesOf locales = runFn3 supportedLocalesOfImpl Left Right locales
339− readMaybeString :: Foreign -> F (Maybe String)
343− else Just <$> readString f