@@ -1,22 +1,13 @@
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(..)
15 , DateTimeFormatOptions(..)
6 , DateTimeFormatOptions(..)
16 , DateTimeFormatOptions'
7 , DateTimeFormatOptions'
17 , DateTimeComponents(..)
8 , DateTimeComponents(..)
18− , DateTimeFormatter
9+ , DateTimeFormat
19− , createDateTimeFormatter
10+ , createDateTimeFormat
20 , formatJSDate
11 , formatJSDate
21 , module Data.Intl.DateTimeFormat.Types
12 , module Data.Intl.DateTimeFormat.Types
22 , supportedLocalesOf
13 , supportedLocalesOf
@@ -26,27 +17,23 @@ module Data.Intl.DateTimeFormat
27import Data.Intl.DateTimeFormat.Types
18import Data.Intl.DateTimeFormat.Types
20+import Control.Monad.Error.Class (throwError)
29import Data.Either (Either(..))
21import Data.Either (Either(..))
30−import Data.Foreign (F, Foreign, isUndefined, readString)
22+import Data.Foreign (F, Foreign, ForeignError(..), isUndefined, readString)
31import Data.Foreign.Index ((!))
23import Data.Foreign.Index ((!))
32−import Data.Function.Uncurried (Fn3, runFn3)
24+import Data.Function.Uncurried (Fn3, Fn4, runFn3, runFn4)
33−import Data.Generic.Rep (class Generic)
34−import Data.Intl.DateTimeFormat.Generic (class FormatComponent, defaultComponentRecord, formatComponent, genericFormatComponent)
25+import Data.Intl.DateTimeFormat.Class (class FormatComponent, FormatComponentRecord(FormatComponentRecord), formatComponent)
35import Data.JSDate (JSDate)
26import Data.JSDate (JSDate)
36import Data.Maybe (Maybe(..), fromMaybe, maybe)
27import Data.Maybe (Maybe(..), fromMaybe, maybe)
37−import Data.Newtype (class Newtype)
28+import Data.Newtype (class Newtype, un)
38import Data.StrMap (union)
29import Data.StrMap (union)
39import Data.Symbol (SProxy(..))
30import Data.Symbol (SProxy(..))
40import Data.Traversable (sequence)
31import Data.Traversable (sequence)
41−import Data.Variant (Variant, default, on)
32+import Data.Variant (Variant, case_, default, on)
42−import Prelude (class Eq, class Show, Unit, bind, id, pure, show, (#), ($), (<$>), (>>=))
33+import Prelude (class Eq, class Show, Unit, bind, id, pure, show, (#), ($), (<$>), (<<<), (>>=))
43import Unsafe.Coerce (unsafeCoerce)
34import Unsafe.Coerce (unsafeCoerce)
45foreign import data LocalesOption' :: Type
36foreign import data LocalesOption' :: Type
46−foreign import data DateTimeFormat :: Type
48−foreign import data Undefined :: Type
49−foreign import undefined :: Undefined
51foreign import dateTimeFormatImpl :: LocalesOption' -> DateTimeFormatOptions_ -> DateTimeFormat
38foreign import dateTimeFormatImpl :: LocalesOption' -> DateTimeFormatOptions_ -> DateTimeFormat
@@ -99,85 +86,6 @@ instance showFormatMatcher :: Show FormatMatcher where
99 show FMBasic = "basic"
86 show FMBasic = "basic"
100 show FMBestFit = "best fit"
87 show FMBestFit = "best fit"
102−newtype WeekdayYearMonthDayHourMinuteSecond = WeekdayYearMonthDayHourMinuteSecond
103− { weekday :: StringRep
104− , year :: NumericRep
107− , hour :: NumericRep
108− , minute :: NumericRep
109− , second :: NumericRep
112−derive instance genericWeekdayYearMonthDayHourMinuteSecond :: Generic WeekdayYearMonthDayHourMinuteSecond _
114−instance formatComponentWeekdayYearMonthDayHourMinuteSecond :: FormatComponent WeekdayYearMonthDayHourMinuteSecond where
115− formatComponent = genericFormatComponent
117−newtype WeekdayYearMonthDay = WeekdayYearMonthDay
118− { weekday :: StringRep
119− , year :: NumericRep
124−derive instance genericWeekdayYearMonthDay :: Generic WeekdayYearMonthDay _
126−instance formatComponentWeekdayYearMonthDay :: FormatComponent WeekdayYearMonthDay where
127− formatComponent = genericFormatComponent
129−newtype YearMonthDay = YearMonthDay
130− { year :: NumericRep
135−derive instance genericYearMonthDay :: Generic YearMonthDay _
137−instance formatComponentYearMonthDay :: FormatComponent YearMonthDay where
138− formatComponent = genericFormatComponent
140−newtype YearMonth = YearMonth
141− { year :: NumericRep
145−derive instance genericYearMonth :: Generic YearMonth _
147−instance formatComponentYearMonth :: FormatComponent YearMonth where
148− formatComponent = genericFormatComponent
150−newtype MonthDay = MonthDay
155−derive instance genericMonthDay :: Generic MonthDay _
157−instance formatComponentMonthDay :: FormatComponent MonthDay where
158− formatComponent = genericFormatComponent
160−newtype HourMinuteSecond = HourMinuteSecond
161− { hour :: NumericRep
162− , minute :: NumericRep
163− , second :: NumericRep
166−derive instance genericHourMinuteSecond :: Generic HourMinuteSecond _
168−instance formatComponentHourMinuteSecond :: FormatComponent HourMinuteSecond where
169− formatComponent = genericFormatComponent
171−newtype HourMinute = HourMinute
172− { hour :: NumericRep
173− , minute :: NumericRep
176−derive instance genericHourMinute :: Generic HourMinute _
178−instance formatComponentHourMinute :: FormatComponent HourMinute where
179− formatComponent = genericFormatComponent
181type DateTimeComponents a =
89type DateTimeComponents a =
183 ( weekdayYearMonthDayHourMinuteSecond :: WeekdayYearMonthDayHourMinuteSecond
91 ( weekdayYearMonthDayHourMinuteSecond :: WeekdayYearMonthDayHourMinuteSecond
@@ -212,7 +120,7 @@ formatDateTimeOptions (DateTimeFormatOptions opts comps) = merge opts' (compsCoe
212 , hour12: fromMaybe (unsafeCoerce undefined) opts.hour12
120 , hour12: fromMaybe (unsafeCoerce undefined) opts.hour12
213 , formatMatcher: maybe undefinedString show opts.formatMatcher
121 , formatMatcher: maybe undefinedString show opts.formatMatcher
215− comps' = default (defaultComponentRecord)
123+ comps' = un FormatComponentRecord $ case_
216 # on (SProxy :: SProxy "weekdayYearMonthDayHourMinuteSecond") formatComponent
124 # on (SProxy :: SProxy "weekdayYearMonthDayHourMinuteSecond") formatComponent
217 # on (SProxy :: SProxy "weekdayYearMonthDay") formatComponent
125 # on (SProxy :: SProxy "weekdayYearMonthDay") formatComponent
218 # on (SProxy :: SProxy "yearMonthDay") formatComponent
126 # on (SProxy :: SProxy "yearMonthDay") formatComponent
@@ -278,36 +186,137 @@ formatDateTimeOptions (DateTimeFormatOptions opts comps) = merge opts' (compsCoe
278 -> DateTimeFormatOptions_
186 -> DateTimeFormatOptions_
279 merge a b = unsafeCoerce $ union (unsafeCoerce a) (unsafeCoerce b)
187 merge a b = unsafeCoerce $ union (unsafeCoerce a) (unsafeCoerce b)
281−foreign import data DateTimeFormatter :: Type
189+foreign import data DateTimeFormat :: Type
283−foreign import createDateTimeFormatterImpl
285− -> DateTimeFormatOptions_
286− -> DateTimeFormatter
288−createDateTimeFormatter
191+foreign import createDateTimeFormatImpl
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")
289 :: forall a
282 :: forall a
290 .(FormatComponent a)
283 .(FormatComponent a)
291 => LocalesOption
284 => LocalesOption
292 -> DateTimeFormatOptions a
285 -> DateTimeFormatOptions a
293− -> DateTimeFormatter
286+ -> F DateTimeFormat
287+createDateTimeFormat ls opts =
288+ runFn4 createDateTimeFormatImpl
289+ (throwError <<< pure <<< ForeignError)
294−createDateTimeFormatter ls opts = createDateTimeFormatterImpl (toLocale ls) (formatDateTimeOptions opts)
292+ (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"
296−foreign import formatJSDate :: DateTimeFormatter -> JSDate -> String
300+foreign import formatJSDate :: DateTimeFormat -> JSDate -> String
298−foreign import supportedLocalesOfImpl :: Fn3 (String -> Either String (Array String)) (Array String -> Either String (Array String)) (Array String) (Either String (Array String))
302+foreign import supportedLocalesOfImpl
304+ (String -> Either String (Array String))
305+ (Array String -> Either String (Array String))
307+ (Either String (Array String))
300−foreign import formatToPartsImpl :: DateTimeFormatter -> JSDate -> Array Foreign
309+foreign import formatToPartsImpl :: DateTimeFormat -> JSDate -> Array Foreign
302−formatToParts :: DateTimeFormatter -> JSDate -> F (Array FormatParts)
311+formatToParts :: DateTimeFormat -> JSDate -> F (Array FormatParts)
303formatToParts formatter date = sequence $ readFormatParts <$> formatToPartsImpl formatter date
312formatToParts formatter date = sequence $ readFormatParts <$> formatToPartsImpl formatter date
305supportedLocalesOf :: Array String -> Either String (Array String)
314supportedLocalesOf :: Array String -> Either String (Array String)
306supportedLocalesOf locales = runFn3 supportedLocalesOfImpl Left Right locales
315supportedLocalesOf locales = runFn3 supportedLocalesOfImpl Left Right locales
308−foreign import resolvedOptionsImpl :: DateTimeFormatter -> Foreign
317+foreign import resolvedOptionsImpl :: DateTimeFormat -> Foreign
310−resolvedOptions :: DateTimeFormatter -> F ResolvedOptions
319+resolvedOptions :: DateTimeFormat -> F ResolvedOptions
311resolvedOptions fmt = do
320resolvedOptions fmt = do
312 locale <- obj ! "locale" >>= readString
321 locale <- obj ! "locale" >>= readString
313 calendar <- obj ! "calendar" >>= readString
322 calendar <- obj ! "calendar" >>= readString