git.iko.soy/purescript-intl
on master help sign in
.gitignore+1
since splitsnapshots
unifiedsplit
@@ -6,3 +6,4 @@ node_modules
6# Generated files
6# Generated files
7.psci
7.psci
8output
8output
9+.purs-repl
.travis.yml+1
@@ -12,6 +12,7 @@ install:
12 - npm install -g bower
12 - npm install -g bower
13 - npm install
13 - npm install
14script:
14script:
15+ - locale
15 - bower install --production
16 - bower install --production
16 - npm run -s build
17 - npm run -s build
17 - bower install
18 - bower install
README.md+2−1
@@ -1,6 +1,7 @@
1# PureScript bindings to Intl - JavaScript Internalisation API
1# PureScript bindings to Intl - JavaScript Internalisation API
2
2
3+[![Maintainer: coot](https://img.shields.io/badge/maintainer-coot-lightgrey.svg)](http://github.com/coot)
3−[![Maintainer: coot](https://img.shields.io/badge/maintainer-coot-lightgrey.svg)](http://github.com/coot) [![documentation](https://pursuit.purescript.org/packages/purescript-intl)](https://pursuit.purescript.org/packages/purescript-intl)
4+[![Documentation](https://pursuit.purescript.org/packages/purescript-intl/badge)](https://pursuit.purescript.org/packages/purescript-intl)
4[![Build Status](https://travis-ci.org/coot/purescript-intl.svg?branch=master)](https://travis-ci.org/coot/purescript-intl)
5[![Build Status](https://travis-ci.org/coot/purescript-intl.svg?branch=master)](https://travis-ci.org/coot/purescript-intl)
5
6
6[Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl)
7[Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl)
bower.json+5
@@ -6,6 +6,11 @@
6 "bower_components",
6 "bower_components",
7 "output"
7 "output"
8 ],
8 ],
9+ "license": "MPL-2.0",
10+ "repository": {
11+ "type": "git",
12+ "url": "git://github.com/coot/purescript-intl.git"
13+ },
9 "dependencies": {
14 "dependencies": {
10 "purescript-prelude": "^3.0.0",
15 "purescript-prelude": "^3.0.0",
11 "purescript-console": "^3.0.0",
16 "purescript-console": "^3.0.0",
src/Data/Intl/DateTimeFormat.js+24−6
@@ -1,17 +1,17 @@
1"use strict";
1"use strict";
2
2
3−exports["undefined"] = undefined;
4−
5exports.dateTimeFormatImpl = function(locales) {
3exports.dateTimeFormatImpl = function(locales) {
6 return function(options) {
4 return function(options) {
7 return new Intl.DateTimeFormat(locales, options);
5 return new Intl.DateTimeFormat(locales, options);
8 };
6 };
9};
7};
10
8
11−exports.createDateTimeFormatterImpl = function(locales) {
9+exports.createDateTimeFormatImpl = function(throwError, pure, locales, opts) {
12− return function(opts) {
10+ try {
13− return Intl.DateTimeFormat(locales, opts);
11+ return pure(Intl.DateTimeFormat(locales, opts));
14− };
12+ } catch (e) {
13+ return throwError(e.message);
14+ }
15};
15};
16
16
17exports.formatJSDate = function(formatter) {
17exports.formatJSDate = function(formatter) {
@@ -19,3 +19,21 @@ exports.formatJSDate = function(formatter) {
19 return formatter.format(date)
19 return formatter.format(date)
20 };
20 };
21};
21};
22+
23+exports.formatToPartsImpl = function(formatter) {
24+ return function(date) {
25+ return formatter.formatToParts(date);
26+ };
27+};
28+
29+exports.supportedLocalesOfImpl = function(Left, Right, locales) {
30+ try {
31+ return Right(Intl.DateTimeFormat.supportedLocalesOf(locales))
32+ } catch (e) {
33+ return Left(e.message)
34+ }
35+}
36+
37+exports.resolvedOptionsImpl = function(formatter) {
38+ return formatter.resolvedOptions();
39+};
src/Data/Intl/DateTimeFormat.purs+167−116
@@ -1,48 +1,39 @@
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(..)
8− , YearMonthDay(..)
9− , YearMonth(..)
10− , MonthDay(..)
11− , HourMinuteSecond(..)
12− , HourMinute(..)
13− , Undefined
14− , undefined
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−
13+ , supportedLocalesOf
23− -- private
14+ , formatToParts
24− , formatDateTimeOptions
15+ , resolvedOptions
25− , DateTimeFormatOptions_
26 ) where
16 ) where
27
17
28import Data.Intl.DateTimeFormat.Types
18import Data.Intl.DateTimeFormat.Types
29
19
30−import Data.Generic.Rep (class Generic)
20+import Control.Monad.Error.Class (throwError)
21+import 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)
31−import Data.Intl.DateTimeFormat.Class (class FormatComponent, defaultComponentRecord, formatComponent, genericFormatComponent)
25+import Data.Intl.DateTimeFormat.Class (class FormatComponent, FormatComponentRecord(FormatComponentRecord), formatComponent)
32import Data.JSDate (JSDate)
26import Data.JSDate (JSDate)
33−import Data.Maybe (Maybe, fromMaybe, maybe)
27+import Data.Maybe (Maybe(..), fromMaybe, maybe)
34−import Data.Newtype (class Newtype)
28+import Data.Newtype (class Newtype, un)
35import Data.StrMap (union)
29import Data.StrMap (union)
36import Data.Symbol (SProxy(..))
30import Data.Symbol (SProxy(..))
31+import Data.Traversable (sequence)
37−import Data.Variant (Variant, default, on)
32+import Data.Variant (Variant, case_, default, on)
38−import Prelude (class Eq, class Show, Unit, id, show, (#), ($))
33+import Prelude (class Eq, class Show, Unit, bind, id, pure, show, (#), ($), (<$>), (<<<), (>>=))
39import Unsafe.Coerce (unsafeCoerce)
34import Unsafe.Coerce (unsafeCoerce)
40
35
41foreign import data LocalesOption' :: Type
36foreign import data LocalesOption' :: Type
42−foreign import data DateTimeFormat :: Type
43−
44−foreign import data Undefined :: Type
45−foreign import undefined :: Undefined
46
37
47foreign import dateTimeFormatImpl :: LocalesOption' -> DateTimeFormatOptions_ -> DateTimeFormat
38foreign import dateTimeFormatImpl :: LocalesOption' -> DateTimeFormatOptions_ -> DateTimeFormat
48
39
@@ -95,85 +86,6 @@ instance showFormatMatcher :: Show FormatMatcher where
95 show FMBasic = "basic"
86 show FMBasic = "basic"
96 show FMBestFit = "best fit"
87 show FMBestFit = "best fit"
97
88
98−newtype WeekdayYearMonthDayHourMinuteSecond = WeekdayYearMonthDayHourMinuteSecond
99− { weekday :: StringRep
100− , year :: NumericRep
101− , month :: MonthRep
102− , day :: NumericRep
103− , hour :: NumericRep
104− , minute :: NumericRep
105− , second :: NumericRep
106− }
107−
108−derive instance genericWeekdayYearMonthDayHourMinuteSecond :: Generic WeekdayYearMonthDayHourMinuteSecond _
109−
110−instance formatComponentWeekdayYearMonthDayHourMinuteSecond :: FormatComponent WeekdayYearMonthDayHourMinuteSecond where
111− formatComponent = genericFormatComponent
112−
113−newtype WeekdayYearMonthDay = WeekdayYearMonthDay
114− { weekday :: StringRep
115− , year :: NumericRep
116− , month :: MonthRep
117− , day :: NumericRep
118− }
119−
120−derive instance genericWeekdayYearMonthDay :: Generic WeekdayYearMonthDay _
121−
122−instance formatComponentWeekdayYearMonthDay :: FormatComponent WeekdayYearMonthDay where
123− formatComponent = genericFormatComponent
124−
125−newtype YearMonthDay = YearMonthDay
126− { year :: NumericRep
127− , month :: MonthRep
128− , day :: NumericRep
129− }
130−
131−derive instance genericYearMonthDay :: Generic YearMonthDay _
132−
133−instance formatComponentYearMonthDay :: FormatComponent YearMonthDay where
134− formatComponent = genericFormatComponent
135−
136−newtype YearMonth = YearMonth
137− { year :: NumericRep
138− , month :: MonthRep
139− }
140−
141−derive instance genericYearMonth :: Generic YearMonth _
142−
143−instance formatComponentYearMonth :: FormatComponent YearMonth where
144− formatComponent = genericFormatComponent
145−
146−newtype MonthDay = MonthDay
147− { month :: MonthRep
148− , day :: NumericRep
149− }
150−
151−derive instance genericMonthDay :: Generic MonthDay _
152−
153−instance formatComponentMonthDay :: FormatComponent MonthDay where
154− formatComponent = genericFormatComponent
155−
156−newtype HourMinuteSecond = HourMinuteSecond
157− { hour :: NumericRep
158− , minute :: NumericRep
159− , second :: NumericRep
160− }
161−
162−derive instance genericHourMinuteSecond :: Generic HourMinuteSecond _
163−
164−instance formatComponentHourMinuteSecond :: FormatComponent HourMinuteSecond where
165− formatComponent = genericFormatComponent
166−
167−newtype HourMinute = HourMinute
168− { hour :: NumericRep
169− , minute :: NumericRep
170− }
171−
172−derive instance genericHourMinute :: Generic HourMinute _
173−
174−instance formatComponentHourMinute :: FormatComponent HourMinute where
175− formatComponent = genericFormatComponent
176−
177type DateTimeComponents a =
89type DateTimeComponents a =
178 Variant
90 Variant
179 ( weekdayYearMonthDayHourMinuteSecond :: WeekdayYearMonthDayHourMinuteSecond
91 ( weekdayYearMonthDayHourMinuteSecond :: WeekdayYearMonthDayHourMinuteSecond
@@ -208,7 +120,7 @@ formatDateTimeOptions (DateTimeFormatOptions opts comps) = merge opts' (compsCoe
208 , hour12: fromMaybe (unsafeCoerce undefined) opts.hour12
120 , hour12: fromMaybe (unsafeCoerce undefined) opts.hour12
209 , formatMatcher: maybe undefinedString show opts.formatMatcher
121 , formatMatcher: maybe undefinedString show opts.formatMatcher
210 }
122 }
211− comps' = default (defaultComponentRecord)
123+ comps' = un FormatComponentRecord $ case_
212 # on (SProxy :: SProxy "weekdayYearMonthDayHourMinuteSecond") formatComponent
124 # on (SProxy :: SProxy "weekdayYearMonthDayHourMinuteSecond") formatComponent
213 # on (SProxy :: SProxy "weekdayYearMonthDay") formatComponent
125 # on (SProxy :: SProxy "weekdayYearMonthDay") formatComponent
214 # on (SProxy :: SProxy "yearMonthDay") formatComponent
126 # on (SProxy :: SProxy "yearMonthDay") formatComponent
@@ -274,19 +186,158 @@ formatDateTimeOptions (DateTimeFormatOptions opts comps) = merge opts' (compsCoe
274 -> DateTimeFormatOptions_
186 -> DateTimeFormatOptions_
275 merge a b = unsafeCoerce $ union (unsafeCoerce a) (unsafeCoerce b)
187 merge a b = unsafeCoerce $ union (unsafeCoerce a) (unsafeCoerce b)
276
188
277−foreign import data DateTimeFormatter :: Type
189+foreign import data DateTimeFormat :: Type
278−
279−foreign import createDateTimeFormatterImpl
280− :: LocalesOption'
281− -> DateTimeFormatOptions_
282− -> DateTimeFormatter
283
190
284−createDateTimeFormatter
191+foreign import createDateTimeFormatImpl
192+ :: Fn4
193+ (forall a. String -> F a)
194+ (forall a. a -> F a)
195+ LocalesOption'
196+ DateTimeFormatOptions_
197+ (F DateTimeFormat)
198+
199+-- | Examples
200+-- | ``` purescript
201+-- | import Data.Variant (inj)
202+-- |
203+-- | fmtHourMinute = F DateTimeFormat
204+-- | fmtHourMinute = createDateTimeFormat locale opts
205+-- | where
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
212+-- | }
213+-- | (inj (SProxy :: SProxy "hourMinute")
214+-- | (HourMinute {hour: TwoDigit, minute: TwoDigit}))
215+-- |
216+-- |
217+-- | fmtDate :: F DateTimeFormat
218+-- | fmtDate = createDateTimeFormat locale opts
219+-- | wher
220+-- | locale = inj (SProxy :: SProxy "locale") "en-GB"
221+-- | opts :: DateTimeFormatOptions'
222+-- | opts =
223+-- | (DateTimeFormatOptions
224+-- | { localeMatcher: Nothing
225+-- | , timeZone: (Just (TimeZone "Europe/London"))
226+-- | , hour12: Just true
227+-- | , formatMatcher: Nothing
228+-- | }
229+-- | (inj
230+-- | (SProxy :: SProxy "weekdayYearMonthDayHourMinuteSecond")
231+-- | (WeekdayYearMonthDayHourMinuteSecond
232+-- | { weekday: Short
233+-- | , year: Numeric
234+-- | , month: MonthLong
235+-- | , day: Numeric
236+-- | , hour: Numeric
237+-- | , minute: Numeric
238+-- | , second: Numeric
239+-- | }
240+-- | )
241+-- | )
242+-- | )
243+-- | ```
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.
248+-- | ``` purescript
249+-- | newtype EraYear = EraYear
250+-- | { era :: StringRep
251+-- | , year :: NumericRep
252+-- | }
253+-- |
254+-- | derive instance genericEraYear :: Generic EraYear _
255+-- |
256+-- | instance formatComponentEraYear :: FormatComponent EraYear where
257+-- | formatComponent = genericFormatComponent
258+-- |
259+-- | fmtEraYear :: F DateTimeFormat
260+-- | fmtEraYear = createDateTimeFormat locales opts
261+-- | where
262+-- | locale = inj (SProxy :: SProxy "locale") "en-GB"
263+-- | opts :: DateTimeFormatOptions EraYear
264+-- | opts =
265+-- | (DateTimeFormatOptions
266+-- | { localeMatcher: Nothing
267+-- | , timeZone: (Just (TimeZone "Europe/London"))
268+-- | , hour12: Just true
269+-- | , formatMatcher: Nothing
270+-- | }
271+-- | (inj
272+-- | (SProxy :: SProxy "custom")
273+-- | (EraYear
274+-- | { era: Long
275+-- | , year: Numeric
276+-- | }
277+-- | )
278+-- | )
279+-- | )
280+-- | ```
281+createDateTimeFormat
285 :: forall a
282 :: forall a
286 .(FormatComponent a)
283 .(FormatComponent a)
287 => LocalesOption
284 => LocalesOption
288 -> DateTimeFormatOptions a
285 -> DateTimeFormatOptions a
289− -> DateTimeFormatter
286+ -> F DateTimeFormat
287+createDateTimeFormat ls opts =
288+ runFn4 createDateTimeFormatImpl
289+ (throwError <<< pure <<< ForeignError)
290+ pure
291+ (toLocale ls)
290−createDateTimeFormatter ls opts = createDateTimeFormatterImpl (toLocale ls) (formatDateTimeOptions opts)
292+ (formatDateTimeOptions opts)
293+
294+-- | Examples
295+-- | ``` purescript
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"
299+-- | ```
300+foreign import formatJSDate :: DateTimeFormat -> JSDate -> String
301+
302+foreign import supportedLocalesOfImpl
303+ :: Fn3
304+ (String -> Either String (Array String))
305+ (Array String -> Either String (Array String))
306+ (Array String)
307+ (Either String (Array String))
308+
309+foreign import formatToPartsImpl :: DateTimeFormat -> JSDate -> Array Foreign
310+
311+formatToParts :: DateTimeFormat -> JSDate -> F (Array FormatParts)
312+formatToParts formatter date = sequence $ readFormatParts <$> formatToPartsImpl formatter date
313+
314+supportedLocalesOf :: Array String -> Either String (Array String)
315+supportedLocalesOf locales = runFn3 supportedLocalesOfImpl Left Right locales
316+
317+foreign import resolvedOptionsImpl :: DateTimeFormat -> Foreign
318+
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
333+
334+ pure $ ResolvedOptions { locale, calendar, numberingSystem, timeZone, era, weekday, year, day, hour, minute, second, timeZoneName }
335+
336+ where
337+ obj = resolvedOptionsImpl fmt
291
338
292−foreign import formatJSDate :: DateTimeFormatter -> JSDate -> String
339+ readMaybeString :: Foreign -> F (Maybe String)
340+ readMaybeString f =
341+ if isUndefined f
342+ then pure Nothing
343+ else Just <$> readString f
src/Data/Intl/DateTimeFormat/Class.purs+18−89
@@ -1,12 +1,10 @@
1module Data.Intl.DateTimeFormat.Class where
1module Data.Intl.DateTimeFormat.Class where
2
2
3−import Data.Generic.Rep (class Generic, Constructor(Constructor), Field(..), NoConstructors, Product(..), Rec(..), from)
4−import Data.Intl.DateTimeFormat.Types (MonthRep, NumericRep, TimeZoneNameRep, StringRep)
5import Data.Maybe (Maybe(..))
3import Data.Maybe (Maybe(..))
6−import Data.StrMap (StrMap, lookup, singleton, union)
4+import Data.Newtype (class Newtype)
7−import Prelude (Unit, show)
5+import Prelude (class Eq, Unit)
8
6
9−type FormatComponentRecord =
7+newtype FormatComponentRecord = FormatComponentRecord
10 { era :: Maybe String
8 { era :: Maybe String
11 , weekday :: Maybe String
9 , weekday :: Maybe String
12 , year :: Maybe String
10 , year :: Maybe String
@@ -18,95 +16,26 @@ type FormatComponentRecord =
18 , timeZoneName :: Maybe String
16 , timeZoneName :: Maybe String
19 }
17 }
20
18
19+derive instance newtypeFormatComponentRecord :: Newtype FormatComponentRecord _
20+
21+derive instance eqFormatComponentRecord :: Eq FormatComponentRecord
22+
21defaultComponentRecord :: FormatComponentRecord
23defaultComponentRecord :: FormatComponentRecord
22−defaultComponentRecord =
24+defaultComponentRecord = FormatComponentRecord
23− { era : Nothing
25+ { era: Nothing
24− , weekday : Nothing
26+ , weekday: Nothing
25− , year : Nothing
27+ , year: Nothing
26− , month : Nothing
28+ , month: Nothing
27− , day : Nothing
29+ , day: Nothing
28− , hour : Nothing
30+ , hour: Nothing
29− , minute : Nothing
31+ , minute: Nothing
30− , second : Nothing
32+ , second: Nothing
31− , timeZoneName : Nothing
33+ , timeZoneName: Nothing
32 }
34 }
33
35
36+
34class FormatComponent a where
37class FormatComponent a where
35 formatComponent :: a -> FormatComponentRecord
38 formatComponent :: a -> FormatComponentRecord
36
39
37instance unitFormatComponent :: FormatComponent Unit where
40instance unitFormatComponent :: FormatComponent Unit where
38 formatComponent _ = defaultComponentRecord
41 formatComponent _ = defaultComponentRecord
39−
40−class GenericFormatComponent a where
41− genericFormatComponent' :: a -> FormatComponentRecord
42−
43−class GenericFormatComponentFields a where
44− genericFormatComponentFields :: a -> StrMap String
45−
46−instance genericFormatComponentNoConsturctors :: GenericFormatComponent NoConstructors where
47− genericFormatComponent' a = { era: Nothing, weekday: Nothing, year: Nothing, month: Nothing, day: Nothing, hour: Nothing, minute: Nothing, second: Nothing, timeZoneName: Nothing }
48−
49−instance genericFormatComponentConstructor :: (GenericFormatComponent a) => GenericFormatComponent (Constructor name a) where
50− genericFormatComponent' (Constructor a) = genericFormatComponent' a
51−
52−instance genericFormatComponentFieldsEra
53− :: GenericFormatComponentFields (Field "era" StringRep) where
54− genericFormatComponentFields (Field a) = singleton "era" (show a)
55−
56−instance genericFormatComponentFieldsWeekday
57− :: GenericFormatComponentFields (Field "weekday" StringRep) where
58− genericFormatComponentFields (Field a) = singleton "weekday" (show a)
59−
60−instance genericFormatComponentFieldsYear
61− :: GenericFormatComponentFields (Field "year" NumericRep) where
62− genericFormatComponentFields (Field a) = singleton "year" (show a)
63−
64−instance genericFormatComponentFieldsMonth
65− :: GenericFormatComponentFields (Field "month" MonthRep) where
66− genericFormatComponentFields (Field a) = singleton "month" (show a)
67−
68−instance genericFormatComponentFieldsDay
69− :: GenericFormatComponentFields (Field "day" NumericRep) where
70− genericFormatComponentFields (Field a) = singleton "day" (show a)
71−
72−instance genericFormatComponentFieldsHour
73− :: GenericFormatComponentFields (Field "hour" NumericRep) where
74− genericFormatComponentFields (Field a) = singleton "hour" (show a)
75−
76−instance genericFormatComponentFieldsMinute
77− :: GenericFormatComponentFields (Field "minute" NumericRep) where
78− genericFormatComponentFields (Field a) = singleton "minute" (show a)
79−
80−instance genericFormatComponentFieldsSecond
81− :: GenericFormatComponentFields (Field "second" NumericRep) where
82− genericFormatComponentFields (Field a) = singleton "second" (show a)
83−
84−instance genericFormatComponentFieldsTimeZoneName
85− :: GenericFormatComponentFields (Field "timeZoneName" TimeZoneNameRep) where
86− genericFormatComponentFields (Field a) = singleton "timeZoneName" (show a)
87−
88−instance genericFormatComponentFieldsProduct
89− :: (GenericFormatComponentFields a, GenericFormatComponentFields b)
90− => GenericFormatComponentFields (Product a b) where
91− genericFormatComponentFields (Product a b) =
92− union (genericFormatComponentFields a) (genericFormatComponentFields b)
93−
94−instance genericFormatComponentRec
95− :: (GenericFormatComponentFields a)
96− => GenericFormatComponent (Rec a) where
97− genericFormatComponent' (Rec a) =
98− { era: "era" `lookup` u
99− , weekday: "weekday" `lookup` u
100− , year: "year" `lookup` u
101− , month: "month" `lookup` u
102− , day: "day" `lookup` u
103− , hour: "hour" `lookup` u
104− , minute: "minute" `lookup` u
105− , second: "second" `lookup` u
106− , timeZoneName: "timeZoneName" `lookup` u
107− }
108− where
109− u = genericFormatComponentFields a
110−
111−genericFormatComponent :: forall a rep. Generic a rep => GenericFormatComponent rep => a -> FormatComponentRecord
112−genericFormatComponent a = genericFormatComponent' (from a)
src/Data/Intl/DateTimeFormat/Generic.pursnew file+98
@@ -0,0 +1,98 @@
1+module Data.Intl.DateTimeFormat.Generic
2+ ( class GenericFormatComponent
3+ , genericFormatComponent'
4+ , genericFormatComponent
5+ , class GenericFormatComponentFields
6+ , genericFormatComponentFields
7+ ) where
8+
9+import Data.Generic.Rep (class Generic, Constructor(Constructor), Field(..), NoConstructors, Product(..), Rec(..), from)
10+import Data.Intl.DateTimeFormat.Class (FormatComponentRecord(..))
11+import Data.Intl.DateTimeFormat.Types (MonthRep, NumericRep, TimeZoneNameRep, StringRep)
12+import Data.Maybe (Maybe(..))
13+import Data.StrMap (StrMap, lookup, singleton, union)
14+import Prelude (show)
15+
16+class GenericFormatComponent a where
17+ genericFormatComponent' :: a -> FormatComponentRecord
18+
19+class GenericFormatComponentFields a where
20+ genericFormatComponentFields :: a -> StrMap String
21+
22+instance genericFormatComponentNoConsturctors :: GenericFormatComponent NoConstructors where
23+ genericFormatComponent' a = FormatComponentRecord
24+ { era: Nothing
25+ , weekday: Nothing
26+ , year: Nothing
27+ , month: Nothing
28+ , day: Nothing
29+ , hour: Nothing
30+ , minute: Nothing
31+ , second: Nothing
32+ , timeZoneName: Nothing
33+ }
34+
35+instance genericFormatComponentConstructor :: (GenericFormatComponent a) => GenericFormatComponent (Constructor name a) where
36+ genericFormatComponent' (Constructor a) = genericFormatComponent' a
37+
38+instance genericFormatComponentFieldsEra
39+ :: GenericFormatComponentFields (Field "era" StringRep) where
40+ genericFormatComponentFields (Field a) = singleton "era" (show a)
41+
42+instance genericFormatComponentFieldsWeekday
43+ :: GenericFormatComponentFields (Field "weekday" StringRep) where
44+ genericFormatComponentFields (Field a) = singleton "weekday" (show a)
45+
46+instance genericFormatComponentFieldsYear
47+ :: GenericFormatComponentFields (Field "year" NumericRep) where
48+ genericFormatComponentFields (Field a) = singleton "year" (show a)
49+
50+instance genericFormatComponentFieldsMonth
51+ :: GenericFormatComponentFields (Field "month" MonthRep) where
52+ genericFormatComponentFields (Field a) = singleton "month" (show a)
53+
54+instance genericFormatComponentFieldsDay
55+ :: GenericFormatComponentFields (Field "day" NumericRep) where
56+ genericFormatComponentFields (Field a) = singleton "day" (show a)
57+
58+instance genericFormatComponentFieldsHour
59+ :: GenericFormatComponentFields (Field "hour" NumericRep) where
60+ genericFormatComponentFields (Field a) = singleton "hour" (show a)
61+
62+instance genericFormatComponentFieldsMinute
63+ :: GenericFormatComponentFields (Field "minute" NumericRep) where
64+ genericFormatComponentFields (Field a) = singleton "minute" (show a)
65+
66+instance genericFormatComponentFieldsSecond
67+ :: GenericFormatComponentFields (Field "second" NumericRep) where
68+ genericFormatComponentFields (Field a) = singleton "second" (show a)
69+
70+instance genericFormatComponentFieldsTimeZoneName
71+ :: GenericFormatComponentFields (Field "timeZoneName" TimeZoneNameRep) where
72+ genericFormatComponentFields (Field a) = singleton "timeZoneName" (show a)
73+
74+instance genericFormatComponentFieldsProduct
75+ :: (GenericFormatComponentFields a, GenericFormatComponentFields b)
76+ => GenericFormatComponentFields (Product a b) where
77+ genericFormatComponentFields (Product a b) =
78+ union (genericFormatComponentFields a) (genericFormatComponentFields b)
79+
80+instance genericFormatComponentRec
81+ :: (GenericFormatComponentFields a)
82+ => GenericFormatComponent (Rec a) where
83+ genericFormatComponent' (Rec a) = FormatComponentRecord
84+ { era: "era" `lookup` u
85+ , weekday: "weekday" `lookup` u
86+ , year: "year" `lookup` u
87+ , month: "month" `lookup` u
88+ , day: "day" `lookup` u
89+ , hour: "hour" `lookup` u
90+ , minute: "minute" `lookup` u
91+ , second: "second" `lookup` u
92+ , timeZoneName: "timeZoneName" `lookup` u
93+ }
94+ where
95+ u = genericFormatComponentFields a
96+
97+genericFormatComponent :: forall a rep. Generic a rep => GenericFormatComponent rep => a -> FormatComponentRecord
98+genericFormatComponent a = genericFormatComponent' (from a)
src/Data/Intl/DateTimeFormat/Types.jsnew file+3
@@ -0,0 +1,3 @@
1+"use strict";
2+
3+exports["undefined"] = undefined;
src/Data/Intl/DateTimeFormat/Types.purs+216−2
@@ -1,9 +1,37 @@
1−module Data.Intl.DateTimeFormat.Types where
1+module Data.Intl.DateTimeFormat.Types
2+ ( StringRep(..)
3+ , NumericRep(..)
4+ , MonthRep(..)
5+ , TimeZoneNameRep(..)
6+ , FormatParts(..)
7+ , readFormatParts
8+ , ResolvedOptions(..)
9+ , WeekdayYearMonthDayHourMinuteSecond(..)
10+ , WeekdayYearMonthDay(..)
11+ , YearMonthDay(..)
12+ , YearMonth(..)
13+ , MonthDay(..)
14+ , HourMinuteSecond(..)
15+ , HourMinute(..)
16+ , Undefined
17+ , undefined
18+ ) where
2
19
20+import Data.Foreign (F, Foreign, ForeignError(..), fail, readString)
21+import Data.Foreign.Index ((!))
22+import Data.Intl.DateTimeFormat.Class (class FormatComponent, FormatComponentRecord(..), defaultComponentRecord)
23+import Data.Maybe (Maybe(..))
24+import Data.Newtype (class Newtype, over)
3−import Prelude (class Show)
25+import Prelude (class Eq, class Show, bind, pure, show, ($), (<>), (>>=))
26+
27+foreign import data Undefined :: Type
28+
29+foreign import undefined :: Undefined
4
30
5data StringRep = Narrow | Short | Long
31data StringRep = Narrow | Short | Long
6
32
33+derive instance eqStringRep :: Eq StringRep
34+
7instance showStringRep :: Show StringRep where
35instance showStringRep :: Show StringRep where
8 show Narrow = "narrow"
36 show Narrow = "narrow"
9 show Short = "short"
37 show Short = "short"
@@ -11,12 +39,16 @@ instance showStringRep :: Show StringRep where
11
39
12data NumericRep = Numeric | TwoDigit
40data NumericRep = Numeric | TwoDigit
13
41
42+derive instance eqNumericRep :: Eq NumericRep
43+
14instance showNumericRep :: Show NumericRep where
44instance showNumericRep :: Show NumericRep where
15 show Numeric = "numeric"
45 show Numeric = "numeric"
16 show TwoDigit = "2-digit"
46 show TwoDigit = "2-digit"
17
47
18data MonthRep = MonthNumeric | MonthTwoDigit | MonthNarrow | MonthShort | MonthLong
48data MonthRep = MonthNumeric | MonthTwoDigit | MonthNarrow | MonthShort | MonthLong
19
49
50+derive instance eqMonthRep :: Eq MonthRep
51+
20instance showMonthRep :: Show MonthRep where
52instance showMonthRep :: Show MonthRep where
21 show MonthNumeric = "numeric"
53 show MonthNumeric = "numeric"
22 show MonthTwoDigit = "2-digit"
54 show MonthTwoDigit = "2-digit"
@@ -26,7 +58,189 @@ instance showMonthRep :: Show MonthRep where
26
58
27data TimeZoneNameRep = TimeZoneNameShort | TimeZoneNameLong
59data TimeZoneNameRep = TimeZoneNameShort | TimeZoneNameLong
28
60
61+derive instance eqTimeZoneNameRep :: Eq TimeZoneNameRep
62+
29instance showTimeZoneRep :: Show TimeZoneNameRep where
63instance showTimeZoneRep :: Show TimeZoneNameRep where
30 show TimeZoneNameShort = "short"
64 show TimeZoneNameShort = "short"
31 show TimeZoneNameLong = "long"
65 show TimeZoneNameLong = "long"
32
66
67+data FormatParts
68+ = Era String
69+ | Year String
70+ | Month String
71+ | Weekday String
72+ | Day String
73+ | Hour String
74+ | Minute String
75+ | DayPeriod String
76+ | Literal String
77+
78+derive instance eqFormatParts :: Eq FormatParts
79+
80+readFormatParts :: Foreign -> F FormatParts
81+readFormatParts val = do
82+ type_ <- val ! "type" >>= readString
83+ value <- val ! "value" >>= readString
84+ case type_ of
85+ "era" -> pure $ Era value
86+ "year" -> pure $ Year value
87+ "month" -> pure $ Month value
88+ "weekday" -> pure $ Weekday value
89+ "month" -> pure $ Month value
90+ "day" -> pure $ Day value
91+ "hour" -> pure $ Hour value
92+ "minute" -> pure $ Minute value
93+ "dayperiod" -> pure $ DayPeriod value
94+ "literal" -> pure $ Literal value
95+ _ -> fail $ ForeignError ("type " <> type_ <> " is not supported by purescript-intl")
96+
97+newtype ResolvedOptions = ResolvedOptions
98+ { locale :: String
99+ , numberingSystem :: String
100+ , calendar :: String
101+ , timeZone :: String
102+ , era :: Maybe String
103+ , weekday :: Maybe String
104+ , year :: Maybe String
105+ , day :: Maybe String
106+ , hour :: Maybe String
107+ , minute :: Maybe String
108+ , second :: Maybe String
109+ , timeZoneName :: Maybe String
110+ }
111+
112+derive instance newtypeResolvedOptions :: Newtype ResolvedOptions _
113+
114+derive instance eqResolvedOptions :: Eq ResolvedOptions
115+
116+newtype WeekdayYearMonthDayHourMinuteSecond = WeekdayYearMonthDayHourMinuteSecond
117+ { weekday :: StringRep
118+ , year :: NumericRep
119+ , month :: MonthRep
120+ , day :: NumericRep
121+ , hour :: NumericRep
122+ , minute :: NumericRep
123+ , second :: NumericRep
124+ }
125+
126+derive instance newtypeWeekdayYearMonthDayHourMinuteSecond :: Newtype WeekdayYearMonthDayHourMinuteSecond _
127+
128+derive instance eqWeekdayYearMonthDayHourMinuteSecond :: Eq WeekdayYearMonthDayHourMinuteSecond
129+
130+instance formatComponentWeekdayYearMonthDayHourMinuteSecond :: FormatComponent WeekdayYearMonthDayHourMinuteSecond where
131+ formatComponent (WeekdayYearMonthDayHourMinuteSecond { weekday, year, month, day, hour, minute, second }) = over FormatComponentRecord
132+ (\r -> r { weekday = Just (show weekday)
133+ , year = Just (show year)
134+ , month = Just (show month)
135+ , day = Just (show day)
136+ , hour = Just (show hour)
137+ , minute = Just (show minute)
138+ , second = Just (show second)
139+ }
140+ ) defaultComponentRecord
141+
142+newtype WeekdayYearMonthDay = WeekdayYearMonthDay
143+ { weekday :: StringRep
144+ , year :: NumericRep
145+ , month :: MonthRep
146+ , day :: NumericRep
147+ }
148+
149+derive instance newtypeWeekdayYearMonthDay :: Newtype WeekdayYearMonthDay _
150+
151+derive instance eqWeekdayYearMonthDay :: Eq WeekdayYearMonthDay
152+
153+instance formatComponentWeekdayYearMonthDay :: FormatComponent WeekdayYearMonthDay where
154+ formatComponent (WeekdayYearMonthDay { weekday, year, month, day }) = over FormatComponentRecord
155+ (\r -> r { weekday = Just (show weekday)
156+ , year = Just (show year)
157+ , month = Just (show month)
158+ , day = Just (show day)
159+ }
160+ ) defaultComponentRecord
161+
162+
163+newtype YearMonthDay = YearMonthDay
164+ { year :: NumericRep
165+ , month :: MonthRep
166+ , day :: NumericRep
167+ }
168+
169+derive instance newtypeYearMonthDay :: Newtype YearMonthDay _
170+
171+derive instance eqYearMonthDay :: Eq YearMonthDay
172+
173+instance formatComponentYearMonthDay :: FormatComponent YearMonthDay where
174+ formatComponent (YearMonthDay { year, month, day }) = over FormatComponentRecord
175+ (\r -> r { year = Just (show year)
176+ , month = Just (show month)
177+ , day = Just (show day)
178+ }
179+ ) defaultComponentRecord
180+
181+
182+newtype YearMonth = YearMonth
183+ { year :: NumericRep
184+ , month :: MonthRep
185+ }
186+
187+derive instance newtypeYearMonth :: Newtype YearMonth _
188+
189+derive instance eqYearMonth :: Eq YearMonth
190+
191+instance formatComponentYearMonth :: FormatComponent YearMonth where
192+ formatComponent (YearMonth { year, month }) = over FormatComponentRecord
193+ (\r -> r { year = Just (show year)
194+ , month = Just (show month)
195+ }
196+ ) defaultComponentRecord
197+
198+newtype MonthDay = MonthDay
199+ { month :: MonthRep
200+ , day :: NumericRep
201+ }
202+
203+derive instance newtypeMonthDay :: Newtype MonthDay _
204+
205+derive instance eqMonthDay :: Eq MonthDay
206+
207+instance formatComponentMonthDay :: FormatComponent MonthDay where
208+ formatComponent (MonthDay { month, day }) = over FormatComponentRecord
209+ (\r -> r { month = Just (show month)
210+ , day = Just (show day)
211+ }
212+ ) defaultComponentRecord
213+
214+newtype HourMinuteSecond = HourMinuteSecond
215+ { hour :: NumericRep
216+ , minute :: NumericRep
217+ , second :: NumericRep
218+ }
219+
220+derive instance newtypeHourMinuteSecond :: Newtype HourMinuteSecond _
221+
222+derive instance eqHourMinuteSecond :: Eq HourMinuteSecond
223+
224+instance formatComponentHourMinuteSecond :: FormatComponent HourMinuteSecond where
225+ formatComponent (HourMinuteSecond { hour, minute, second }) = over FormatComponentRecord
226+ (\r -> r { hour = Just (show hour)
227+ , minute = Just (show minute)
228+ , second = Just (show second)
229+ }
230+ ) defaultComponentRecord
231+
232+newtype HourMinute = HourMinute
233+ { hour :: NumericRep
234+ , minute :: NumericRep
235+ }
236+
237+derive instance newtypeHourMinute :: Newtype HourMinute _
238+
239+derive instance eqHourMinute :: Eq HourMinute
240+
241+instance formatComponentHourMinute :: FormatComponent HourMinute where
242+ formatComponent (HourMinute { hour, minute }) = over FormatComponentRecord
243+ (\r -> r { hour = Just (show hour)
244+ , minute = Just (show minute)
245+ }
246+ ) defaultComponentRecord
test/Test/Main.purs+109−44
@@ -3,19 +3,24 @@ module Test.Main where
3import Prelude
3import Prelude
4
4
5import Control.Monad.Eff (Eff)
5import Control.Monad.Eff (Eff)
6−import Control.Monad.Eff.Console (CONSOLE, log)
6+import Control.Monad.Eff.Console (CONSOLE)
7+import Control.Monad.Except (runExcept)
7import Data.DateTime (Date, DateTime(..), Month(..), canonicalDate)
8import Data.DateTime (Date, DateTime(..), Month(..), canonicalDate)
9+import Data.Either (Either(..), fromRight, isLeft)
8import Data.Enum (toEnum)
10import Data.Enum (toEnum)
11+import Data.Foldable (intercalate)
12+import Data.Foreign (F, renderForeignError)
9import Data.Generic.Rep (class Generic)
13import Data.Generic.Rep (class Generic)
10−import Data.Intl.DateTimeFormat (DateTimeFormatOptions(..), DateTimeFormatOptions', HourMinute(HourMinute), HourMinuteSecond(HourMinuteSecond), LocalesOption, MonthDay(..), MonthRep(..), NumericRep(Numeric, TwoDigit), StringRep(..), TimeZone(TimeZone), WeekdayYearMonthDay(..), WeekdayYearMonthDayHourMinuteSecond(WeekdayYearMonthDayHourMinuteSecond), YearMonth(..), YearMonthDay(..), createDateTimeFormatter, formatJSDate)
14+import Data.Intl.DateTimeFormat (DateTimeFormatOptions(DateTimeFormatOptions), DateTimeFormatOptions', HourMinute(HourMinute), HourMinuteSecond(HourMinuteSecond), LocalesOption, MonthDay(MonthDay), MonthRep(MonthTwoDigit, MonthNumeric, MonthNarrow, MonthShort, MonthLong), NumericRep(Numeric, TwoDigit), ResolvedOptions(..), StringRep(Short, Long), TimeZone(TimeZone), WeekdayYearMonthDay(WeekdayYearMonthDay), WeekdayYearMonthDayHourMinuteSecond(WeekdayYearMonthDayHourMinuteSecond), YearMonth(YearMonth), YearMonthDay(YearMonthDay), createDateTimeFormat, formatJSDate, resolvedOptions, supportedLocalesOf)
11−import Data.Intl.DateTimeFormat.Class (class FormatComponent, genericFormatComponent)
15+import Data.Intl.DateTimeFormat.Class (class FormatComponent, FormatComponentRecord(..))
16+import Data.Intl.DateTimeFormat.Generic (genericFormatComponent)
12import Data.JSDate (JSDate, fromDateTime)
17import Data.JSDate (JSDate, fromDateTime)
13−import Data.Maybe (Maybe(..))
18+import Data.Maybe (Maybe(..), isJust, isNothing)
14import Data.Symbol (SProxy(..))
19import Data.Symbol (SProxy(..))
15import Data.Time (Time(..))
20import Data.Time (Time(..))
16import Data.Variant (inj)
21import Data.Variant (inj)
17−import Partial.Unsafe (unsafeCrashWith)
22+import Partial.Unsafe (unsafeCrashWith, unsafePartial)
18−import Test.Assert (ASSERT, assert)
23+import Test.Assert (ASSERT, assert')
19
24
20type Tests = Eff (console :: CONSOLE, assert :: ASSERT) Unit
25type Tests = Eff (console :: CONSOLE, assert :: ASSERT) Unit
21
26
@@ -32,7 +37,7 @@ instance formatComponentEraYear :: FormatComponent EraYear where
32newtype Era = Era StringRep
37newtype Era = Era StringRep
33
38
34instance formatComponentEra :: FormatComponent Era where
39instance formatComponentEra :: FormatComponent Era where
35− formatComponent (Era r) =
40+ formatComponent (Era r) = FormatComponentRecord
36 { era: Just (show r)
41 { era: Just (show r)
37 , weekday: Nothing
42 , weekday: Nothing
38 , year: Nothing
43 , year: Nothing
@@ -48,11 +53,28 @@ main :: Tests
48main = do
53main = do
49 let
54 let
50
55
56+ unsafeFromF :: forall a. F a -> a
57+ unsafeFromF = unsafePartial fromRight <<< runExcept
58+
51 locales :: LocalesOption
59 locales :: LocalesOption
52− locales = inj (SProxy :: SProxy "locale") "en-GB"
60+ locales = inj (SProxy :: SProxy "locale") "en-US"
61+
62+ fmtError =
63+ createDateTimeFormat (inj (SProxy :: SProxy "locale") "") opts
64+ where
65+ opts :: DateTimeFormatOptions'
66+ opts =
67+ (DateTimeFormatOptions
68+ { localeMatcher: Nothing
69+ , timeZone: (Just (TimeZone "Europe/London"))
70+ , hour12: Just false
71+ , formatMatcher: Nothing
72+ }
73+ (inj (SProxy :: SProxy "hourMinute") (HourMinute {hour: TwoDigit, minute: TwoDigit}))
74+ )
53
75
54− fmtHourMinute =
76+ fmtHourMinute = unsafeFromF $
55− createDateTimeFormatter locales opts
77+ createDateTimeFormat locales opts
56 where
78 where
57 opts :: DateTimeFormatOptions'
79 opts :: DateTimeFormatOptions'
58 opts =
80 opts =
@@ -65,8 +87,8 @@ main = do
65 (inj (SProxy :: SProxy "hourMinute") (HourMinute {hour: TwoDigit, minute: TwoDigit}))
87 (inj (SProxy :: SProxy "hourMinute") (HourMinute {hour: TwoDigit, minute: TwoDigit}))
66 )
88 )
67
89
68− fmtHourMinuteSecond =
90+ fmtHourMinuteSecond = unsafeFromF $
69− createDateTimeFormatter locales opts
91+ createDateTimeFormat locales opts
70 where
92 where
71 opts :: DateTimeFormatOptions'
93 opts :: DateTimeFormatOptions'
72 opts =
94 opts =
@@ -79,8 +101,8 @@ main = do
79 (inj (SProxy :: SProxy "hourMinuteSecond") (HourMinuteSecond {hour: Numeric, minute: Numeric, second: Numeric}))
101 (inj (SProxy :: SProxy "hourMinuteSecond") (HourMinuteSecond {hour: Numeric, minute: Numeric, second: Numeric}))
80 )
102 )
81
103
82− fmtWeekdayYearMonthDayHourMinuteSecond =
104+ fmtWeekdayYearMonthDayHourMinuteSecond = unsafeFromF $
83− createDateTimeFormatter locales opts
105+ createDateTimeFormat locales opts
84 where
106 where
85 opts :: DateTimeFormatOptions'
107 opts :: DateTimeFormatOptions'
86 opts =
108 opts =
@@ -105,8 +127,8 @@ main = do
105 )
127 )
106 )
128 )
107
129
108− fmtWeekdayYearMonthDay =
130+ fmtWeekdayYearMonthDay = unsafeFromF $
109− createDateTimeFormatter locales opts
131+ createDateTimeFormat locales opts
110 where
132 where
111 opts :: DateTimeFormatOptions'
133 opts :: DateTimeFormatOptions'
112 opts =
134 opts =
@@ -128,8 +150,8 @@ main = do
128 )
150 )
129 )
151 )
130
152
131− fmtYearMonthDay =
153+ fmtYearMonthDay = unsafeFromF $
132− createDateTimeFormatter locales opts
154+ createDateTimeFormat locales opts
133 where
155 where
134 opts :: DateTimeFormatOptions'
156 opts :: DateTimeFormatOptions'
135 opts =
157 opts =
@@ -150,8 +172,8 @@ main = do
150 )
172 )
151 )
173 )
152
174
153− fmtYearMonth =
175+ fmtYearMonth = unsafeFromF $
154− createDateTimeFormatter locales opts
176+ createDateTimeFormat locales opts
155 where
177 where
156 opts :: DateTimeFormatOptions'
178 opts :: DateTimeFormatOptions'
157 opts =
179 opts =
@@ -171,8 +193,8 @@ main = do
171 )
193 )
172 )
194 )
173
195
174− fmtMonthDay =
196+ fmtMonthDay = unsafeFromF $
175− createDateTimeFormatter locales opts
197+ createDateTimeFormat locales opts
176 where
198 where
177 opts :: DateTimeFormatOptions'
199 opts :: DateTimeFormatOptions'
178 opts =
200 opts =
@@ -192,8 +214,8 @@ main = do
192 )
214 )
193 )
215 )
194
216
195− fmtEraYear =
217+ fmtEraYear = unsafeFromF $
196− createDateTimeFormatter locales opts
218+ createDateTimeFormat locales opts
197 where
219 where
198 opts :: DateTimeFormatOptions EraYear
220 opts :: DateTimeFormatOptions EraYear
199 opts =
221 opts =
@@ -213,8 +235,8 @@ main = do
213 )
235 )
214 )
236 )
215
237
216− fmtEra =
238+ fmtEra = unsafeFromF $
217− createDateTimeFormatter locales opts
239+ createDateTimeFormat locales opts
218 where
240 where
219 opts :: DateTimeFormatOptions Era
241 opts :: DateTimeFormatOptions Era
220 opts =
242 opts =
@@ -258,21 +280,64 @@ main = do
258 case jsDate of
280 case jsDate of
259 Nothing -> unsafeCrashWith "jsDate not parsed"
281 Nothing -> unsafeCrashWith "jsDate not parsed"
260 Just d -> do
282 Just d -> do
261− log "fmtWeekdayYearMonthDayHourMinuteSecond"
283+
284+ assert' "fmtError expected to return error" $ isLeft (runExcept fmtError)
285+
262− assert $ formatJSDate fmtWeekdayYearMonthDayHourMinuteSecond d == "Tue, 2 January 2018, 12:00:00 pm"
286+ let fmtDate1 = formatJSDate fmtWeekdayYearMonthDayHourMinuteSecond d
263− log "fmtWeekdayYearMonthDay"
287+ fmtDate1Expected = "Tue, January 2, 2018, 12:00:00 PM"
288+ assert' ("fmtWeekdayYearMonthDayHourMinuteSecond: got: '" <> fmtDate1 <> "' expected: '" <> fmtDate1Expected <> "'")
289+ $ fmtDate1 == fmtDate1Expected
264− assert $ formatJSDate fmtWeekdayYearMonthDay d == "Tuesday, 02 Jan 18"
290+ let fmtDate2 = formatJSDate fmtWeekdayYearMonthDay d
265− log "fmtYearMonthDay"
291+ fmtDate2Expected = "Tuesday, Jan 02, 18"
292+ assert' ("fmtWeekdayYearMonthDayString: got '" <> fmtDate2 <> "' expected: '" <> fmtDate2Expected <> "'")
293+ $ fmtDate2 == fmtDate2Expected
266− assert $ formatJSDate fmtYearMonthDay d == "02 J 18"
294+ let fmtDate3 = formatJSDate fmtYearMonthDay d
267− log "fmtYearMonth"
295+ fmtDate3Expected = "J 02, 18"
296+ assert' ("fmtYearMonthDayString: got '" <> fmtDate3 <> "' expected: '" <> fmtDate3Expected <> "'")
297+ $ fmtDate3 == fmtDate3Expected
268− assert $ formatJSDate fmtYearMonth d == "01/2018"
298+ let fmtDate4 = formatJSDate fmtYearMonth d
269− log "fmtMonthDay"
299+ fmtDate4Expected = "1/2018"
300+ assert' ("fmtYearMonthString: got '" <> fmtDate4 <> "' expected: '" <> fmtDate4Expected <> "'")
301+ $ fmtDate4 == fmtDate4Expected
270− assert $ formatJSDate fmtMonthDay d == "02/01"
302+ let fmtDate5 = formatJSDate fmtMonthDay d
271− log "fmtHourMinuteSecond"
303+ fmtDate5Expected = "01/02"
304+ assert' ("fmtMonthDayString: got '" <> fmtDate5 <> "' expected: '" <> fmtDate5Expected <> "'")
305+ $ fmtDate5 == fmtDate5Expected
272− assert $ formatJSDate fmtHourMinuteSecond d == "12:00:00"
306+ let fmtDate6 = formatJSDate fmtHourMinuteSecond d
273− log "fmtHourMinute"
307+ fmtDate6Expected = "12:00:00"
308+ assert' ("fmtHourMinuteSecondString: got '" <> fmtDate6 <> "' expected: '" <> fmtDate6Expected <> "'")
309+ $ fmtDate6 == fmtDate6Expected
274− assert $ formatJSDate fmtHourMinute d == "12:00"
310+ let fmtDate7 = formatJSDate fmtHourMinute d
275− log "fmtEraYear"
311+ fmtDate7Expected = "12:00"
312+ assert' ("fmtHourMinuteString: got '" <> fmtDate7 <> "' expected: '" <> fmtDate7Expected <> "'")
313+ $ fmtDate7 == fmtDate7Expected
276− assert $ formatJSDate fmtEraYear d == "2018 Anno Domini"
314+ let fmtDate8 = formatJSDate fmtEraYear d
277− log "fmtEra"
315+ fmtDate8Expected = "2018 Anno Domini"
316+ assert' ("fmtEraYear: got '" <> fmtDate8 <> "' expected: '" <> fmtDate8Expected <> "'")
317+ $ fmtDate8 == fmtDate8Expected
278− assert $ formatJSDate fmtEra d == "2 1 2018 AD"
318+ let fmtDate9 = formatJSDate fmtEra d
319+ fmtDate9Expected = "1 2, 2018 AD"
320+ assert' ("fmtEra: got '" <> fmtDate9 <> "' expected: '" <> fmtDate9Expected <> "'")
321+ $ fmtDate9 == fmtDate9Expected
322+
323+ let slocs = supportedLocalesOf ["en-US", "jp-JP"]
324+ assert' ("supportedLocalesOf: got: " <> show slocs) $ slocs == Right ["en-US"]
325+
326+ let err = supportedLocalesOf ["en_US"]
327+ assert' ("supportedLocalesOf got: " <> show err) $ isLeft err
328+
329+ -- formatToParts is not supported in node
330+ -- let parts = runExcept $ formatToParts fmtHourMinute d
331+ -- assert' ("") $ isRight parts
332+
333+ case runExcept (resolvedOptions fmtHourMinuteSecond) of
334+ Left errs-> assert' ("resolvedOptions error: " <> (intercalate "; " $ renderForeignError <$> errs)) false
335+ Right (ResolvedOptions {locale, year, day, weekday, hour, minute, second}) -> do
336+ assert' ("resolvedOptions locale: got: " <> locale) $ (locale == "en-US") || (locale == "en")
337+ assert' ("resolvedOptions year: got Just") $ isNothing year
338+ assert' ("resolvedOptions day: got Just") $ isNothing day
339+ assert' ("resolvedOptions weekday: got Just") $ isNothing weekday
340+ assert' ("resolvedOptions hour: got Nothing") $ isJust hour
341+ assert' ("resolvedOptions minute: got Nothing") $ isJust minute
342+ assert' ("resolvedOptions second: got Nothing") $ isJust second
343+