Purescript library to handle the formatting of dates and times.

Add sources

+3123
+282
.eslintrc.json
··· 1 + { 2 + "ignorePatterns": [ 3 + "dist/*.js", 4 + "output/**/*.js" 5 + ], 6 + "env": { 7 + "browser": true, 8 + "es2021": true 9 + }, 10 + "extends": "eslint:recommended", 11 + "parserOptions": { 12 + "ecmaVersion": 12, 13 + "sourceType": "module" 14 + }, 15 + "rules": { 16 + "accessor-pairs": "error", 17 + "array-bracket-newline": "error", 18 + "array-bracket-spacing": [ 19 + "error", 20 + "never" 21 + ], 22 + "array-callback-return": "error", 23 + "array-element-newline": "off", 24 + "arrow-body-style": "error", 25 + "arrow-parens": "error", 26 + "arrow-spacing": [ 27 + "error", 28 + { 29 + "after": true, 30 + "before": true 31 + } 32 + ], 33 + "block-scoped-var": "error", 34 + "block-spacing": "error", 35 + "brace-style": "error", 36 + "camelcase": "error", 37 + "capitalized-comments": [ 38 + "error", 39 + "always" 40 + ], 41 + "class-methods-use-this": "error", 42 + "comma-dangle": "off", 43 + "comma-spacing": [ 44 + "error", 45 + { 46 + "after": true, 47 + "before": false 48 + } 49 + ], 50 + "comma-style": [ 51 + "error", 52 + "last" 53 + ], 54 + "complexity": "error", 55 + "computed-property-spacing": "error", 56 + "consistent-return": "error", 57 + "consistent-this": "error", 58 + "curly": "error", 59 + "default-case": "error", 60 + "default-case-last": "error", 61 + "default-param-last": "error", 62 + "dot-location": [ 63 + "error", 64 + "property" 65 + ], 66 + "dot-notation": "error", 67 + "eol-last": "error", 68 + "eqeqeq": "error", 69 + "func-call-spacing": "error", 70 + "func-name-matching": "error", 71 + "func-names": "off", 72 + "func-style": [ 73 + "error", 74 + "declaration" 75 + ], 76 + "function-paren-newline": [ 77 + "error", 78 + "consistent" 79 + ], 80 + "generator-star-spacing": "error", 81 + "grouped-accessor-pairs": "error", 82 + "guard-for-in": "error", 83 + "id-denylist": "error", 84 + "id-length": [ 85 + "error", 86 + { 87 + "min": 1, 88 + "max": 50 89 + } 90 + ], 91 + "id-match": "error", 92 + "implicit-arrow-linebreak": "off", 93 + "indent": [ 94 + "error", 95 + 4, 96 + { 97 + "SwitchCase": 1 98 + } 99 + ], 100 + "init-declarations": "error", 101 + "jsx-quotes": "error", 102 + "key-spacing": "error", 103 + "keyword-spacing": "error", 104 + "line-comment-position": "error", 105 + "linebreak-style": [ 106 + "error", 107 + "unix" 108 + ], 109 + "lines-around-comment": "error", 110 + "lines-between-class-members": "error", 111 + "max-classes-per-file": "error", 112 + "max-depth": "error", 113 + "max-len": "off", 114 + "max-lines": "error", 115 + "max-lines-per-function": "error", 116 + "max-nested-callbacks": "error", 117 + "max-params": "error", 118 + "max-statements": "error", 119 + "max-statements-per-line": "error", 120 + "multiline-comment-style": [ 121 + "error", 122 + "separate-lines" 123 + ], 124 + "multiline-ternary": [ 125 + "error", 126 + "always-multiline" 127 + ], 128 + "new-cap": "error", 129 + "new-parens": "error", 130 + "newline-per-chained-call": "error", 131 + "no-alert": "error", 132 + "no-array-constructor": "error", 133 + "no-await-in-loop": "error", 134 + "no-bitwise": "error", 135 + "no-caller": "error", 136 + "no-confusing-arrow": "error", 137 + "no-console": "error", 138 + "no-constructor-return": "error", 139 + "no-continue": "error", 140 + "no-div-regex": "error", 141 + "no-duplicate-imports": "error", 142 + "no-else-return": "off", 143 + "no-empty-function": "error", 144 + "no-eq-null": "error", 145 + "no-eval": "error", 146 + "no-extend-native": "error", 147 + "no-extra-bind": "error", 148 + "no-extra-label": "error", 149 + "no-extra-parens": "error", 150 + "no-floating-decimal": "error", 151 + "no-implicit-coercion": "error", 152 + "no-implicit-globals": "error", 153 + "no-implied-eval": "error", 154 + "no-inline-comments": "error", 155 + "no-invalid-this": "error", 156 + "no-iterator": "error", 157 + "no-label-var": "error", 158 + "no-labels": "error", 159 + "no-lone-blocks": "error", 160 + "no-lonely-if": "error", 161 + "no-loop-func": "error", 162 + "no-loss-of-precision": "error", 163 + "no-magic-numbers": "error", 164 + "no-mixed-operators": "error", 165 + "no-multi-assign": "error", 166 + "no-multi-spaces": "error", 167 + "no-multi-str": "error", 168 + "no-multiple-empty-lines": "error", 169 + "no-negated-condition": "error", 170 + "no-nested-ternary": "error", 171 + "no-new": "error", 172 + "no-new-func": "error", 173 + "no-new-object": "error", 174 + "no-new-wrappers": "error", 175 + "no-nonoctal-decimal-escape": "error", 176 + "no-octal-escape": "error", 177 + "no-param-reassign": "error", 178 + "no-plusplus": "error", 179 + "no-promise-executor-return": "error", 180 + "no-proto": "error", 181 + "no-restricted-exports": "error", 182 + "no-restricted-globals": "error", 183 + "no-restricted-imports": "error", 184 + "no-restricted-properties": "error", 185 + "no-restricted-syntax": "error", 186 + "no-return-assign": "error", 187 + "no-return-await": "error", 188 + "no-script-url": "error", 189 + "no-self-compare": "error", 190 + "no-sequences": "error", 191 + "no-shadow": "error", 192 + "no-tabs": "error", 193 + "no-template-curly-in-string": "error", 194 + "no-ternary": "off", 195 + "no-throw-literal": "error", 196 + "no-trailing-spaces": "error", 197 + "no-undef-init": "error", 198 + "no-undefined": "error", 199 + "no-underscore-dangle": "error", 200 + "no-unmodified-loop-condition": "error", 201 + "no-unneeded-ternary": "error", 202 + "no-unreachable-loop": "error", 203 + "no-unsafe-optional-chaining": "error", 204 + "no-unused-expressions": "error", 205 + "no-use-before-define": "off", 206 + "no-useless-backreference": "error", 207 + "no-useless-call": "error", 208 + "no-useless-computed-key": "error", 209 + "no-useless-concat": "error", 210 + "no-useless-constructor": "error", 211 + "no-useless-rename": "error", 212 + "no-useless-return": "error", 213 + "no-var": "error", 214 + "no-void": "error", 215 + "no-warning-comments": "error", 216 + "no-whitespace-before-property": "error", 217 + "nonblock-statement-body-position": "error", 218 + "object-curly-newline": "error", 219 + "object-curly-spacing": [ 220 + "error", 221 + "always" 222 + ], 223 + "object-shorthand": "error", 224 + "one-var": "off", 225 + "one-var-declaration-per-line": "error", 226 + "operator-assignment": "error", 227 + "operator-linebreak": "error", 228 + "padded-blocks": "off", 229 + "padding-line-between-statements": "error", 230 + "prefer-arrow-callback": "off", 231 + "prefer-const": "off", 232 + "prefer-destructuring": "error", 233 + "prefer-exponentiation-operator": "error", 234 + "prefer-named-capture-group": "off", 235 + "prefer-numeric-literals": "error", 236 + "prefer-object-spread": "error", 237 + "prefer-promise-reject-errors": "error", 238 + "prefer-regex-literals": "error", 239 + "prefer-rest-params": "error", 240 + "prefer-spread": "error", 241 + "prefer-template": "off", 242 + "quote-props": "off", 243 + "quotes": "off", 244 + "radix": "error", 245 + "require-atomic-updates": "error", 246 + "require-await": "off", 247 + "require-unicode-regexp": "error", 248 + "rest-spread-spacing": "error", 249 + "semi": "off", 250 + "semi-spacing": "error", 251 + "semi-style": "error", 252 + "sort-imports": "error", 253 + "sort-keys": "off", 254 + "sort-vars": "error", 255 + "space-before-blocks": "error", 256 + "space-before-function-paren": "off", 257 + "space-in-parens": [ 258 + "error", 259 + "never" 260 + ], 261 + "space-infix-ops": "error", 262 + "space-unary-ops": "error", 263 + "spaced-comment": "off", 264 + "strict": "error", 265 + "switch-colon-spacing": "error", 266 + "symbol-description": "error", 267 + "template-curly-spacing": [ 268 + "error", 269 + "never" 270 + ], 271 + "template-tag-spacing": "error", 272 + "unicode-bom": [ 273 + "error", 274 + "never" 275 + ], 276 + "vars-on-top": "error", 277 + "wrap-iife": "error", 278 + "wrap-regex": "error", 279 + "yield-star-spacing": "error", 280 + "yoda": "error" 281 + } 282 + }
+18
.gitattributes
··· 1 + # Set line endings to auto. 2 + * text=auto eol=lf 3 + 4 + # Force batch scripts to always use CRLF line endings so that if a repo is accessed 5 + # in Windows via a file share from Linux, the scripts will work. 6 + *.{cmd,[cC][mM][dD]} text eol=crlf 7 + *.{bat,[bB][aA][tT]} text eol=crlf 8 + 9 + # Force bash scripts to always use LF line endings so that if a repo is accessed 10 + # in Unix via a file share from Windows, the scripts will work. 11 + *.sh text eol=lf 12 + 13 + # Force Haskell hs files to LF. 14 + *.hs text eol=lf 15 + 16 + # treat these as binary files 17 + *.png binary 18 + *.jpg binary
+10
.gitignore
··· 1 + node_modules/ 2 + .spago/ 3 + .cache/ 4 + output/ 5 + packages.dhall/ 6 + /.psc-ide-port 7 + dist/ 8 + bla.txt 9 + generated-docs/ 10 + Pipfile.lock
+12
.prettierrc.json
··· 1 + { 2 + "bracketSameLine": true, 3 + "tabWidth": 4, 4 + "useTabs": false, 5 + "htmlWhitespaceSensitivity": "ignore", 6 + "semi": false, 7 + "bracketSpacing": true, 8 + "arrowParens": "always", 9 + "endOfLine": "lf", 10 + "proseWrap": "preserve", 11 + "singleQuote": false 12 + }
+162
src/Data/CalendarFormat.purs
··· 1 + -- SPDX-License-Identifier: MIT 2 + -- Copyright (C) 2022 Roland Csaszar 3 + -- 4 + -- Project: purescript-datetimeformat 5 + -- File: CalendarFormat.purs 6 + -- Date: 12.Feb.2022 7 + -- 8 + -- ============================================================================== 9 + -- | Module Data.CalendarFormat, the type of the format of a calendar. 10 + module Data.CalendarFormat 11 + ( CalendarFormat(..) 12 + , calendarFormatToString 13 + , toString 14 + ) where 15 + 16 + import Prelude 17 + import Data.Argonaut (class DecodeJson, class EncodeJson) 18 + import Data.Argonaut.Decode.Generic (genericDecodeJson) 19 + import Data.Argonaut.Encode.Generic (genericEncodeJson) 20 + import Data.Generic.Rep (class Generic) 21 + import Data.Show.Generic (genericShow) 22 + import Test.QuickCheck (class Arbitrary, arbitrary) 23 + 24 + {------------------------------------------------------------------------------- 25 + | The calendar format. 26 + | 27 + | The calendar "islamicc" is deprecated, use `IslamicCivil` ("islamic-civil") 28 + | instead. 29 + | 30 + | See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/calendar#unicode_calendar_keys 31 + | 32 + | One of 33 + | * Buddhist - Thai Buddhist calendar 34 + | * Chinese - Traditional Chinese calendar 35 + | * Coptic - Coptic calendar 36 + | * Dangi - Traditional Korean calendar 37 + | * Ethioaa - Ethiopic calendar, Amete Alem (epoch approx. 5493 B.C.E) 38 + | * Ethiopic - Ethiopic calendar, Amete Mihret (epoch approx, 8 C.E.) 39 + | * Gregory - Gregorian calendar 40 + | * Hebrew - Traditional Hebrew calendar 41 + | * Indian - Indian calendar 42 + | * Islamic - Islamic calendar 43 + | * IslamicUmalqura - Islamic calendar, Umm al-Qura 44 + | * IslamicTbla - Islamic calendar, tabular (intercalary years [2,5,7,10,13,16,18,21,24,26,29] - astronomical epoch) 45 + | * IslamicCivil - Islamic calendar, tabular (intercalary years [2,5,7,10,13,16,18,21,24,26,29] - civil epoch) 46 + | * IslamicRgsa - Islamic calendar, Saudi Arabia sighting 47 + | * Iso8601 - ISO calendar (Gregorian calendar using the ISO 8601 calendar week rules) 48 + | * Japanese - Japanese Imperial calendar 49 + | * Persian - Persian calendar 50 + | * Roc - Civil (algorithmic) Arabic calendar 51 + -} 52 + data CalendarFormat 53 + = Buddhist 54 + | Chinese 55 + | Coptic 56 + | Dangi 57 + | Ethioaa 58 + | Ethiopic 59 + | Gregory 60 + | Hebrew 61 + | Indian 62 + | Islamic 63 + | IslamicUmalqura 64 + | IslamicTbla 65 + | IslamicCivil 66 + | IslamicRgsa 67 + | Iso8601 68 + | Japanese 69 + | Persian 70 + | Roc 71 + 72 + {------------------------------------------------------------------------------- 73 + | Return the string representation of a `CalendarFormat`. 74 + | 75 + | A shorter alias for `calendarFormatToString`. 76 + -} 77 + toString ∷ CalendarFormat → String 78 + toString = calendarFormatToString 79 + 80 + {------------------------------------------------------------------------------- 81 + | Return the string representation of a `CalendarFormat`. 82 + -} 83 + calendarFormatToString :: CalendarFormat -> String 84 + calendarFormatToString Buddhist = "buddhist" 85 + 86 + calendarFormatToString Chinese = "chinese" 87 + 88 + calendarFormatToString Coptic = "coptic" 89 + 90 + calendarFormatToString Dangi = "dangi" 91 + 92 + calendarFormatToString Ethioaa = "ethioaa" 93 + 94 + calendarFormatToString Ethiopic = "ethiopic" 95 + 96 + calendarFormatToString Gregory = "gregory" 97 + 98 + calendarFormatToString Hebrew = "hebrew" 99 + 100 + calendarFormatToString Indian = "indian" 101 + 102 + calendarFormatToString Islamic = "islamic" 103 + 104 + calendarFormatToString IslamicUmalqura = "islamic-umalqura" 105 + 106 + calendarFormatToString IslamicTbla = "islamic-tbla" 107 + 108 + calendarFormatToString IslamicCivil = "islamic-civil" 109 + 110 + calendarFormatToString IslamicRgsa = "islamic-rgsa" 111 + 112 + calendarFormatToString Iso8601 = "iso8601" 113 + 114 + calendarFormatToString Japanese = "japanese" 115 + 116 + calendarFormatToString Persian = "persian" 117 + 118 + calendarFormatToString Roc = "roc" 119 + 120 + derive instance eqCalendarFormat :: Eq CalendarFormat 121 + 122 + derive instance ordCalendarFormat :: Ord CalendarFormat 123 + 124 + derive instance genericCalendarFormat :: Generic CalendarFormat _ 125 + 126 + instance decodeJsonCalendarFormat :: DecodeJson CalendarFormat where 127 + decodeJson = genericDecodeJson 128 + 129 + instance encodeJsonCalendarFormat :: EncodeJson CalendarFormat where 130 + encodeJson = genericEncodeJson 131 + 132 + instance showCalendarFormat :: Show CalendarFormat where 133 + show = genericShow 134 + 135 + {------------------------------------------------------------------------------- 136 + ATTENTION: 18 is the number of values of `CalendarFormat`. 137 + -} 138 + instance arbitraryCalendarFormat :: Arbitrary CalendarFormat where 139 + arbitrary = map intToCalendarFormat arbitrary 140 + where 141 + intToCalendarFormat :: Int -> CalendarFormat 142 + intToCalendarFormat n 143 + | n >= 0 = case n `mod` 18 of 144 + 0 -> Buddhist 145 + 1 -> Chinese 146 + 2 -> Coptic 147 + 3 -> Dangi 148 + 4 -> Ethioaa 149 + 5 -> Ethiopic 150 + 6 -> Gregory 151 + 7 -> Hebrew 152 + 8 -> Indian 153 + 9 -> Islamic 154 + 10 -> IslamicUmalqura 155 + 11 -> IslamicTbla 156 + 12 -> IslamicCivil 157 + 13 -> IslamicRgsa 158 + 14 -> Iso8601 159 + 15 -> Japanese 160 + 16 -> Persian 161 + _ -> Roc 162 + | otherwise = intToCalendarFormat (-n)
+239
src/Data/DateTimeFormat.js
··· 1 + // SPDX-License-Identifier: MIT 2 + // Copyright (C) 2022 Roland Csaszar 3 + // 4 + // Project: purescript-datetimeformat 5 + // File: DateTimeFormat.js 6 + // Date: 12.Feb.2022 7 + // 8 + // ============================================================================== 9 + /* eslint-disable max-params */ 10 + /* eslint-disable no-undef */ 11 + /* eslint-disable no-undefined */ 12 + /* eslint-disable max-lines-per-function */ 13 + /* eslint-disable max-statements */ 14 + /* eslint-disable complexity */ 15 + 16 + // eslint-disable-next-line strict 17 + "use strict" 18 + 19 + exports.defaultDateTimeFormat = defaultDateTimeFormat 20 + exports.isoDateTimeNow = isoDateTimeNow 21 + exports.isoDateTimeJS = isoDateTimeJS 22 + exports.formatDateTimeNow = formatDateTimeNow 23 + exports.formatDateJS = formatDateJS 24 + exports.formatDateTimeJS = formatDateTimeJS 25 + exports.getDateTimeFormatJS = getDateTimeFormatJS 26 + 27 + /** 28 + * Return the default `DateTimeFormat` object of the current locale. 29 + * 30 + * @returns The default `DateTimeFormat` object of the current locale. 31 + */ 32 + function defaultDateTimeFormat() { 33 + return function () { 34 + return new Intl.DateTimeFormat() 35 + } 36 + } 37 + 38 + /** 39 + * Return the formatter with the given locale and options. 40 + * 41 + * @param {string[]} locales - The array of locales. 42 + * @param {DateTimeFormatOptionsJS} options - The options of 43 + * `Intl.DateTimeFormat` 44 + * @returns The formatter with the given options and locale. 45 + */ 46 + 47 + function getDateTimeFormatJS( 48 + locales, 49 + { 50 + dateStyle, 51 + timeStyle, 52 + calendar, 53 + dayPeriod, 54 + numberingSystem, 55 + localeMatcher, 56 + timeZone, 57 + hour12, 58 + hourCycle, 59 + formatMatcher, 60 + weekDay, 61 + era, 62 + year, 63 + month, 64 + day, 65 + hour, 66 + minute, 67 + second, 68 + fractionalSecondDigits, 69 + timeZoneNameStyle, 70 + } 71 + ) { 72 + let options = {} 73 + if (dateStyle !== undefined) { 74 + const optionsAdd = { dateStyle } 75 + options = Object.assign(options, optionsAdd) 76 + } 77 + if (timeStyle !== undefined) { 78 + const optionsAdd = { timeStyle } 79 + options = Object.assign(options, optionsAdd) 80 + } 81 + if (calendar !== undefined) { 82 + const optionsAdd = { calendar } 83 + options = Object.assign(options, optionsAdd) 84 + } 85 + if (dayPeriod !== undefined) { 86 + const optionsAdd = { dayPeriod } 87 + options = Object.assign(options, optionsAdd) 88 + } 89 + if (numberingSystem !== undefined) { 90 + const optionsAdd = { numberingSystem } 91 + options = Object.assign(options, optionsAdd) 92 + } 93 + if (localeMatcher !== undefined) { 94 + const optionsAdd = { localeMatcher } 95 + options = Object.assign(options, optionsAdd) 96 + } 97 + if (timeZone !== undefined) { 98 + const optionsAdd = { timeZone } 99 + options = Object.assign(options, optionsAdd) 100 + } 101 + if (hour12 !== undefined) { 102 + const optionsAdd = { hour12 } 103 + options = Object.assign(options, optionsAdd) 104 + } 105 + if (hourCycle !== undefined) { 106 + const optionsAdd = { hourCycle } 107 + options = Object.assign(options, optionsAdd) 108 + } 109 + if (formatMatcher !== undefined) { 110 + const optionsAdd = { formatMatcher } 111 + options = Object.assign(options, optionsAdd) 112 + } 113 + if (weekDay !== undefined) { 114 + const optionsAdd = { weekDay } 115 + options = Object.assign(options, optionsAdd) 116 + } 117 + if (era !== undefined) { 118 + const optionsAdd = { era } 119 + options = Object.assign(options, optionsAdd) 120 + } 121 + if (year !== undefined) { 122 + const optionsAdd = { year } 123 + options = Object.assign(options, optionsAdd) 124 + } 125 + if (month !== undefined) { 126 + const optionsAdd = { month } 127 + options = Object.assign(options, optionsAdd) 128 + } 129 + if (day !== undefined) { 130 + const optionsAdd = { day } 131 + options = Object.assign(options, optionsAdd) 132 + } 133 + if (hour !== undefined) { 134 + const optionsAdd = { hour } 135 + options = Object.assign(options, optionsAdd) 136 + } 137 + if (minute !== undefined) { 138 + const optionsAdd = { minute } 139 + options = Object.assign(options, optionsAdd) 140 + } 141 + if (second !== undefined) { 142 + const optionsAdd = { second } 143 + options = Object.assign(options, optionsAdd) 144 + } 145 + if (fractionalSecondDigits !== undefined) { 146 + const optionsAdd = { fractionalSecondDigits } 147 + options = Object.assign(options, optionsAdd) 148 + } 149 + if (timeZoneNameStyle !== undefined) { 150 + const optionsAdd = { timeZoneNameStyle } 151 + options = Object.assign(options, optionsAdd) 152 + } 153 + 154 + return new Intl.DateTimeFormat(locales, options) 155 + } 156 + 157 + /** 158 + * Return the current date and time as ISO ISO 8601 string as UTC. 159 + * 160 + * @returns The current date and time as ISO ISO 8601 string as UTC. 161 + */ 162 + function isoDateTimeNow() { 163 + return function () { 164 + const today = new Date() 165 + 166 + return today.toISOString() 167 + } 168 + } 169 + 170 + /** 171 + * Return the given date and time as ISO ISO 8601 string as UTC. 172 + * @param {number} year - The Year 173 + * @param {number} monthIdx - The index of the month, starting at 0 (January) 174 + * @param {number} day - The day of the month (starting at 1) 175 + * @param {number} hour - The hour 176 + * @param {number} minutes - The minutes 177 + * @param {number} seconds - The seconds 178 + * @returns The given date and time as ISO ISO 8601 string as UTC. 179 + */ 180 + function isoDateTimeJS(year, monthIdx, day, hour, minutes, seconds) { 181 + const date = new Date(year, monthIdx, day, hour, minutes, seconds) 182 + return date.toISOString() 183 + } 184 + 185 + /** 186 + * Return a string of the current date and time formatted using the given 187 + * formatter object. 188 + * 189 + * @param {Intl.DateTimeFormat} formatter - The format to use to format the 190 + * output. 191 + * @returns A string of the current date and time formatted using the given 192 + * formatter object. 193 + */ 194 + function formatDateTimeNow(formatter) { 195 + return function () { 196 + const today = new Date() 197 + 198 + return formatter.format(today) 199 + } 200 + } 201 + 202 + /** 203 + * Return the given local date formatted by the given formatter. 204 + * 205 + * @param {Intl.DateTimeFormat} formatter - The formatter to use 206 + * @param {number} year - The Year 207 + * @param {number} monthIdx - The index of the month, starting at 0 (January) 208 + * @param {number} day - The day of the month (starting at 1) 209 + * @returns The given date formatted by the given formatter. 210 + */ 211 + function formatDateJS(formatter, year, monthIdx, day) { 212 + const date = new Date(year, monthIdx, day) 213 + return formatter.format(date) 214 + } 215 + 216 + /** 217 + * Return the given local date and time formatted by the given formatter. 218 + * 219 + * @param {Intl.DateTimeFormat} formatter - The formatter to use 220 + * @param {number} year - The Year 221 + * @param {number} monthIdx - The index of the month, starting at 0 (January) 222 + * @param {number} day - The day of the month (starting at 1) 223 + * @param {number} hour - The hour 224 + * @param {number} minutes - The minutes 225 + * @param {number} seconds - The seconds 226 + * @returns The given date and time formatted by the given formatter. 227 + */ 228 + function formatDateTimeJS( 229 + formatter, 230 + year, 231 + monthIdx, 232 + day, 233 + hour, 234 + minutes, 235 + seconds 236 + ) { 237 + const date = new Date(year, monthIdx, day, hour, minutes, seconds) 238 + return formatter.format(date) 239 + }
+1900
src/Data/DateTimeFormat.purs
··· 1 + -- SPDX-License-Identifier: MIT 2 + -- Copyright (C) 2022 Roland Csaszar 3 + -- 4 + -- Project: purescript-datetimeformat 5 + -- File: DateTimeFormat.purs 6 + -- Date: 12.Feb.2022 7 + -- 8 + -- ============================================================================== 9 + -- | Module Data.DateTimeFormat, to set the locale and format of a date or time. 10 + -- | See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat 11 + module Data.DateTimeFormat 12 + ( DateStyle(..) 13 + , DateTimeFormat 14 + , DateTimeFormatOptions(..) 15 + , DayFormat(..) 16 + , DayPeriod(..) 17 + , EraFormat(..) 18 + , FormatMatcher(..) 19 + , FractionalSecondDigits(..) 20 + , Hour12(..) 21 + , HourCycle(..) 22 + , HourFormat(..) 23 + , Locale(..) 24 + , LocaleMatcher(..) 25 + , MinuteFormat(..) 26 + , MonthFormat(..) 27 + , SecondFormat(..) 28 + , TimeStyle(..) 29 + , TimeZone(..) 30 + , TimeZoneNameStyle(..) 31 + , WeekDayFormat(..) 32 + , YearFormat(..) 33 + , dateTimeFormat 34 + , defaultDateTimeFormat 35 + , emptyDateTimeFormatOptions 36 + , formatDate 37 + , formatDateInts 38 + , formatDateIntsUnsafe 39 + , formatDateTime 40 + , formatDateTimeInts 41 + , formatDateTimeIntsUnsafe 42 + , formatDateTimeNow 43 + , isoDateTime 44 + , isoDateTimeInts 45 + , isoDateTimeIntsUnsafe 46 + , isoDateTimeNow 47 + , localeToString 48 + , setCalendarFormat 49 + , setDateStyle 50 + , setDayFormat 51 + , setDayPeriod 52 + , setEraFormat 53 + , setFormatMatcher 54 + , setFractionalSecondDigits 55 + , setHour12 56 + , setHourCycle 57 + , setHourFormat 58 + , setLocaleMatcher 59 + , setMinuteFormat 60 + , setMonthFormat 61 + , setNumberingSystem 62 + , setSecondFormat 63 + , setTimeStyle 64 + , setTimeZone 65 + , setTimeZoneNameStyle 66 + , setWeekDayFormat 67 + , setYearFormat 68 + , stringToLocale 69 + , stringToLocaleUnsafe 70 + , stringToTimeZone 71 + , timeZoneToString 72 + ) where 73 + 74 + import Prelude 75 + import Data.Argonaut (class DecodeJson, class EncodeJson) 76 + import Data.Argonaut.Decode.Generic (genericDecodeJson) 77 + import Data.Argonaut.Encode.Generic (genericEncodeJson) 78 + import Data.CalendarFormat (CalendarFormat, calendarFormatToString) 79 + import Data.Date (Date, canonicalDate, day, month, year) 80 + import Data.DateTime (DateTime(..), Time(..), hour, minute, second) 81 + import Data.Enum (fromEnum, toEnum) 82 + import Data.Function.Uncurried (Fn2, Fn4, Fn6, Fn7, runFn2, runFn4, runFn6, runFn7) 83 + import Data.Generic.Rep (class Generic) 84 + import Data.Maybe (Maybe(..)) 85 + import Data.Newtype (class Newtype, unwrap, wrap) 86 + import Data.NumberingSystem (NumberingSystem, numberingSystemToString) 87 + import Data.Show.Generic (genericShow) 88 + import Data.String (trim) 89 + import Data.String.Regex (Regex, match) 90 + import Data.String.Regex.Flags (unicode) 91 + import Data.String.Regex.Unsafe (unsafeRegex) 92 + import Effect (Effect) 93 + import Test.QuickCheck (class Arbitrary, arbitrary) 94 + import Test.QuickCheck.Arbitrary (genericArbitrary) 95 + import Untagged.Castable (cast) 96 + import Untagged.Union (UndefinedOr) 97 + 98 + {------------------------------------------------------------------------------- 99 + | Type to hold the locale and formatting options of a date or a time. 100 + -} 101 + foreign import data DateTimeFormat :: Type 102 + 103 + {------------------------------------------------------------------------------- 104 + | The type of a locale. 105 + | 106 + | This is a wrapped BCP 47 with Unicode extensions ('Extension U') locale tag. 107 + | 108 + | Examples of valid locale strings: 109 + | 110 + | "en", "zh", "de" 111 + | "eng", "zho", "deu" 112 + | "en-US", "zh-cn", "de-AT" 113 + | "en-US-u-ca-buddhist", "gsw-u-sd-chzh", "he-IL-u-ca-hebrew-tz-jeruslm" 114 + -} 115 + newtype Locale 116 + = Locale String 117 + 118 + derive newtype instance eqLocale :: Eq Locale 119 + 120 + derive newtype instance ordLocale :: Ord Locale 121 + 122 + derive newtype instance showLocale :: Show Locale 123 + 124 + derive newtype instance decodeJsonLocale :: DecodeJson Locale 125 + 126 + derive newtype instance encodeJsonLocale :: EncodeJson Locale 127 + 128 + derive instance genericLocale :: Generic Locale _ 129 + 130 + derive instance newtypeLocale :: Newtype Locale _ 131 + 132 + derive newtype instance arbitraryLocale :: Arbitrary Locale 133 + 134 + {------------------------------------------------------------------------------- 135 + | Convert a `Locale` to a `String`. 136 + | 137 + | * `locale` - The `Locale` to convert to a `String`. 138 + -} 139 + localeToString :: Locale -> String 140 + localeToString = unwrap 141 + 142 + {------------------------------------------------------------------------------- 143 + | Convert a BCP 47 language tag `String` to a `Locale`. 144 + | 145 + | The given `String` is not validated, every non-empty String containing any 146 + | non-whitespace character returns a `Locale`! 147 + | 148 + | * `str` - The `String` to convert to a `Locale`. 149 + -} 150 + stringToLocale :: String -> Maybe Locale 151 + stringToLocale "" = Nothing 152 + 153 + stringToLocale str = case match notOnlyWhitespaceRegex str of 154 + Nothing -> Nothing 155 + _ -> Just $ wrap $ trim str 156 + 157 + {------------------------------------------------------------------------------- 158 + | Convert a BCP 47 language tag `String` to a `Locale`. 159 + | 160 + | The given `String` is not validated, every String returns a `Locale`! 161 + | 162 + | * `str` - The `String` to convert to a `Locale`. 163 + -} 164 + stringToLocaleUnsafe :: String -> Locale 165 + stringToLocaleUnsafe = wrap 166 + 167 + {------------------------------------------------------------------------------- 168 + | A empty `DateTimeFormatOptions` object, with all fields set to `Nothing`. 169 + | 170 + | This is also the `Monoid`s `mempty`. 171 + -} 172 + emptyDateTimeFormatOptions ∷ DateTimeFormatOptions 173 + emptyDateTimeFormatOptions = 174 + DateTimeFormatOptions 175 + { dateStyle: Nothing 176 + , timeStyle: Nothing 177 + , calendar: Nothing 178 + , dayPeriod: Nothing 179 + , numberingSystem: Nothing 180 + , localeMatcher: Nothing 181 + , timeZone: Nothing 182 + , hour12: Nothing 183 + , hourCycle: Nothing 184 + , formatMatcher: Nothing 185 + , weekDay: Nothing 186 + , era: Nothing 187 + , year: Nothing 188 + , month: Nothing 189 + , day: Nothing 190 + , hour: Nothing 191 + , minute: Nothing 192 + , second: Nothing 193 + , fractionalSecondDigits: Nothing 194 + , timeZoneNameStyle: Nothing 195 + } 196 + 197 + {------------------------------------------------------------------------------- 198 + | Set the `dateStyle` field of the given `DateTimeFormatOptions` to the given 199 + | value. 200 + -} 201 + setDateStyle :: DateStyle -> DateTimeFormatOptions -> DateTimeFormatOptions 202 + setDateStyle style (DateTimeFormatOptions options) = DateTimeFormatOptions options { dateStyle = Just style } 203 + 204 + {------------------------------------------------------------------------------- 205 + | Set the `timeStyle` field of the given `DateTimeFormatOptions` to the given 206 + | value. 207 + -} 208 + setTimeStyle :: TimeStyle -> DateTimeFormatOptions -> DateTimeFormatOptions 209 + setTimeStyle style (DateTimeFormatOptions options) = DateTimeFormatOptions options { timeStyle = Just style } 210 + 211 + {------------------------------------------------------------------------------- 212 + | Set the `calendar` field of the given `DateTimeFormatOptions` to the given 213 + | value. 214 + -} 215 + setCalendarFormat :: CalendarFormat -> DateTimeFormatOptions -> DateTimeFormatOptions 216 + setCalendarFormat style (DateTimeFormatOptions options) = DateTimeFormatOptions options { calendar = Just style } 217 + 218 + {------------------------------------------------------------------------------- 219 + | Set the `dayPeriod` field of the given `DateTimeFormatOptions` to the given 220 + | value. 221 + -} 222 + setDayPeriod :: DayPeriod -> DateTimeFormatOptions -> DateTimeFormatOptions 223 + setDayPeriod style (DateTimeFormatOptions options) = DateTimeFormatOptions options { dayPeriod = Just style } 224 + 225 + {------------------------------------------------------------------------------- 226 + | Set the `numberingSystem` field of the given `DateTimeFormatOptions` to the given 227 + | value. 228 + -} 229 + setNumberingSystem :: NumberingSystem -> DateTimeFormatOptions -> DateTimeFormatOptions 230 + setNumberingSystem style (DateTimeFormatOptions options) = DateTimeFormatOptions options { numberingSystem = Just style } 231 + 232 + {------------------------------------------------------------------------------- 233 + | Set the `localeMatcher` field of the given `DateTimeFormatOptions` to the given 234 + | value. 235 + -} 236 + setLocaleMatcher :: LocaleMatcher -> DateTimeFormatOptions -> DateTimeFormatOptions 237 + setLocaleMatcher style (DateTimeFormatOptions options) = DateTimeFormatOptions options { localeMatcher = Just style } 238 + 239 + {------------------------------------------------------------------------------- 240 + | Set the `timeZone` field of the given `DateTimeFormatOptions` to the given 241 + | value. 242 + -} 243 + setTimeZone :: TimeZone -> DateTimeFormatOptions -> DateTimeFormatOptions 244 + setTimeZone style (DateTimeFormatOptions options) = DateTimeFormatOptions options { timeZone = Just style } 245 + 246 + {------------------------------------------------------------------------------- 247 + | Set the `hour12` field of the given `DateTimeFormatOptions` to the given 248 + | value. 249 + -} 250 + setHour12 :: Hour12 -> DateTimeFormatOptions -> DateTimeFormatOptions 251 + setHour12 style (DateTimeFormatOptions options) = DateTimeFormatOptions options { hour12 = Just style } 252 + 253 + {------------------------------------------------------------------------------- 254 + | Set the `hourCycle` field of the given `DateTimeFormatOptions` to the given 255 + | value. 256 + -} 257 + setHourCycle :: HourCycle -> DateTimeFormatOptions -> DateTimeFormatOptions 258 + setHourCycle style (DateTimeFormatOptions options) = DateTimeFormatOptions options { hourCycle = Just style } 259 + 260 + {------------------------------------------------------------------------------- 261 + | Set the `formatMatcher` field of the given `DateTimeFormatOptions` to the given 262 + | value. 263 + -} 264 + setFormatMatcher :: FormatMatcher -> DateTimeFormatOptions -> DateTimeFormatOptions 265 + setFormatMatcher style (DateTimeFormatOptions options) = DateTimeFormatOptions options { formatMatcher = Just style } 266 + 267 + {------------------------------------------------------------------------------- 268 + | Set the `weekDay` field of the given `DateTimeFormatOptions` to the given 269 + | value. 270 + -} 271 + setWeekDayFormat :: WeekDayFormat -> DateTimeFormatOptions -> DateTimeFormatOptions 272 + setWeekDayFormat style (DateTimeFormatOptions options) = DateTimeFormatOptions options { weekDay = Just style } 273 + 274 + {------------------------------------------------------------------------------- 275 + | Set the `era` field of the given `DateTimeFormatOptions` to the given 276 + | value. 277 + -} 278 + setEraFormat :: EraFormat -> DateTimeFormatOptions -> DateTimeFormatOptions 279 + setEraFormat style (DateTimeFormatOptions options) = DateTimeFormatOptions options { era = Just style } 280 + 281 + {------------------------------------------------------------------------------- 282 + | Set the `year` field of the given `DateTimeFormatOptions` to the given 283 + | value. 284 + -} 285 + setYearFormat :: YearFormat -> DateTimeFormatOptions -> DateTimeFormatOptions 286 + setYearFormat style (DateTimeFormatOptions options) = DateTimeFormatOptions options { year = Just style } 287 + 288 + {------------------------------------------------------------------------------- 289 + | Set the `month` field of the given `DateTimeFormatOptions` to the given 290 + | value. 291 + -} 292 + setMonthFormat :: MonthFormat -> DateTimeFormatOptions -> DateTimeFormatOptions 293 + setMonthFormat style (DateTimeFormatOptions options) = DateTimeFormatOptions options { month = Just style } 294 + 295 + {------------------------------------------------------------------------------- 296 + | Set the `day` field of the given `DateTimeFormatOptions` to the given 297 + | value. 298 + -} 299 + setDayFormat :: DayFormat -> DateTimeFormatOptions -> DateTimeFormatOptions 300 + setDayFormat style (DateTimeFormatOptions options) = DateTimeFormatOptions options { day = Just style } 301 + 302 + {------------------------------------------------------------------------------- 303 + | Set the `hour` field of the given `DateTimeFormatOptions` to the given 304 + | value. 305 + -} 306 + setHourFormat :: HourFormat -> DateTimeFormatOptions -> DateTimeFormatOptions 307 + setHourFormat style (DateTimeFormatOptions options) = DateTimeFormatOptions options { hour = Just style } 308 + 309 + {------------------------------------------------------------------------------- 310 + | Set the `minute` field of the given `DateTimeFormatOptions` to the given 311 + | value. 312 + -} 313 + setMinuteFormat :: MinuteFormat -> DateTimeFormatOptions -> DateTimeFormatOptions 314 + setMinuteFormat style (DateTimeFormatOptions options) = DateTimeFormatOptions options { minute = Just style } 315 + 316 + {------------------------------------------------------------------------------- 317 + | Set the `second` field of the given `DateTimeFormatOptions` to the given 318 + | value. 319 + -} 320 + setSecondFormat :: SecondFormat -> DateTimeFormatOptions -> DateTimeFormatOptions 321 + setSecondFormat style (DateTimeFormatOptions options) = DateTimeFormatOptions options { second = Just style } 322 + 323 + {------------------------------------------------------------------------------- 324 + | Set the `fractionalSecondDigits` field of the given `DateTimeFormatOptions` to the given 325 + | value. 326 + -} 327 + setFractionalSecondDigits :: FractionalSecondDigits -> DateTimeFormatOptions -> DateTimeFormatOptions 328 + setFractionalSecondDigits style (DateTimeFormatOptions options) = DateTimeFormatOptions options { fractionalSecondDigits = Just style } 329 + 330 + {------------------------------------------------------------------------------- 331 + | Set the `timeZoneNameStyle` field of the given `DateTimeFormatOptions` to the given 332 + | value. 333 + -} 334 + setTimeZoneNameStyle :: TimeZoneNameStyle -> DateTimeFormatOptions -> DateTimeFormatOptions 335 + setTimeZoneNameStyle style (DateTimeFormatOptions options) = DateTimeFormatOptions options { timeZoneNameStyle = Just style } 336 + 337 + {------------------------------------------------------------------------------- 338 + | The options of a `DateTimeFormat`. 339 + | 340 + | You can set the fields of `DateTimeFormat` using `Monoid`s `append` `<>`, or by 341 + | chaining calls to the `set...` functions using `#`. 342 + | 343 + | Example: 344 + | 345 + | ```purescript 346 + | formatOpts = setDateStyle (DateStyle Long) mempty <> setTimeStyle (TimeStyle MediumT) mempty 347 + | 348 + | formatOpts = mempty # setDateStyle (DateStyle Long) # setTimeStyle (TimeStyle MediumT) 349 + | ``` 350 + | 351 + | See MDN for more information of the fields: 352 + | https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat 353 + -} 354 + newtype DateTimeFormatOptions 355 + = DateTimeFormatOptions 356 + { dateStyle :: Maybe DateStyle 357 + , timeStyle :: Maybe TimeStyle 358 + , calendar :: Maybe CalendarFormat 359 + , dayPeriod :: Maybe DayPeriod 360 + , numberingSystem :: Maybe NumberingSystem 361 + , localeMatcher :: Maybe LocaleMatcher 362 + , timeZone :: Maybe TimeZone 363 + , hour12 :: Maybe Hour12 364 + , hourCycle :: Maybe HourCycle 365 + , formatMatcher :: Maybe FormatMatcher 366 + , weekDay :: Maybe WeekDayFormat 367 + , era :: Maybe EraFormat 368 + , year :: Maybe YearFormat 369 + , month :: Maybe MonthFormat 370 + , day :: Maybe DayFormat 371 + , hour :: Maybe HourFormat 372 + , minute :: Maybe MinuteFormat 373 + , second :: Maybe SecondFormat 374 + , fractionalSecondDigits :: Maybe FractionalSecondDigits 375 + , timeZoneNameStyle :: Maybe TimeZoneNameStyle 376 + } 377 + 378 + derive instance eqDateTimeFormatOptions :: Eq DateTimeFormatOptions 379 + 380 + derive instance ordDateTimeFormatOptions :: Ord DateTimeFormatOptions 381 + 382 + derive instance genericDateTimeFormatOptions :: Generic DateTimeFormatOptions _ 383 + 384 + instance decodeJsonDateTimeFormatOptions :: DecodeJson DateTimeFormatOptions where 385 + decodeJson = genericDecodeJson 386 + 387 + instance encodeJsonDateTimeFormatOptions :: EncodeJson DateTimeFormatOptions where 388 + encodeJson = genericEncodeJson 389 + 390 + instance showDateTimeFormatOptions :: Show DateTimeFormatOptions where 391 + show = genericShow 392 + 393 + instance arbitraryDateTimeFormatOptions :: Arbitrary DateTimeFormatOptions where 394 + arbitrary = genericArbitrary 395 + 396 + instance semiGroupDateTimeFormatOptions :: Semigroup DateTimeFormatOptions where 397 + append (DateTimeFormatOptions a) (DateTimeFormatOptions b) = 398 + DateTimeFormatOptions 399 + { dateStyle: setAOrB a.dateStyle b.dateStyle 400 + , timeStyle: setAOrB a.timeStyle b.timeStyle 401 + , calendar: setAOrB a.calendar b.calendar 402 + , dayPeriod: setAOrB a.dayPeriod b.dayPeriod 403 + , numberingSystem: setAOrB a.numberingSystem b.numberingSystem 404 + , localeMatcher: setAOrB a.localeMatcher b.localeMatcher 405 + , timeZone: setAOrB a.timeZone b.timeZone 406 + , hour12: setAOrB a.hour12 b.hour12 407 + , hourCycle: setAOrB a.hourCycle b.hourCycle 408 + , formatMatcher: setAOrB a.formatMatcher b.formatMatcher 409 + , weekDay: setAOrB a.weekDay b.weekDay 410 + , era: setAOrB a.era b.era 411 + , year: setAOrB a.year b.year 412 + , month: setAOrB a.month b.month 413 + , day: setAOrB a.day b.day 414 + , hour: setAOrB a.hour b.hour 415 + , minute: setAOrB a.minute b.minute 416 + , second: setAOrB a.second b.second 417 + , fractionalSecondDigits: setAOrB a.fractionalSecondDigits b.fractionalSecondDigits 418 + , timeZoneNameStyle: setAOrB a.timeZoneNameStyle b.timeZoneNameStyle 419 + } 420 + where 421 + setAOrB :: forall a. Maybe a -> Maybe a -> Maybe a 422 + setAOrB c Nothing = c 423 + 424 + setAOrB _ (Just d) = Just d 425 + 426 + instance monoidDateTimeFormatOptions :: Monoid DateTimeFormatOptions where 427 + mempty = emptyDateTimeFormatOptions 428 + 429 + {------------------------------------------------------------------------------- 430 + | Return the default `DateTimeFormat` object of the current (browser) locale. 431 + -} 432 + foreign import defaultDateTimeFormat :: Unit -> Effect DateTimeFormat 433 + 434 + {------------------------------------------------------------------------------- 435 + | Return a `DateTimeFormat` from the given `Locale` and `DateTimeFormatOptions`. 436 + | 437 + | This format is to be used as argument to to `format...` functions, like 438 + | `formatDateTime`. 439 + -} 440 + dateTimeFormat :: Array Locale -> DateTimeFormatOptions -> DateTimeFormat 441 + dateTimeFormat locales options = runFn2 getDateTimeFormatJS locales optionsJS 442 + where 443 + optionsJS = convertDateTimeOptions options 444 + 445 + foreign import getDateTimeFormatJS :: Fn2 (Array Locale) DateTimeFormatOptionsJS DateTimeFormat 446 + 447 + {------------------------------------------------------------------------------- 448 + | Return a string of the current date and time formatted using the given 449 + | formatter object. 450 + -} 451 + foreign import formatDateTimeNow :: DateTimeFormat -> Effect String 452 + 453 + {------------------------------------------------------------------------------- 454 + | Return the current date and time as ISO ISO 8601 string as UTC. 455 + -} 456 + foreign import isoDateTimeNow :: Unit -> Effect String 457 + 458 + foreign import isoDateTimeJS :: Fn6 Int Int Int Int Int Int String 459 + 460 + {------------------------------------------------------------------------------- 461 + | Return the given date and time as ISO ISO 8601 string as UTC. 462 + | 463 + | * `dateTime` - The local date and time to return as ISO ISO 8601 string. 464 + -} 465 + isoDateTime :: DateTime -> String 466 + isoDateTime (DateTime date time) = runFn6 isoDateTimeJS year' month' day' hour' minute' seconds' 467 + where 468 + year' = fromEnum $ year date 469 + 470 + month' = (fromEnum $ month date) - 1 471 + 472 + day' = fromEnum $ day date 473 + 474 + hour' = fromEnum $ hour time 475 + 476 + minute' = fromEnum $ minute time 477 + 478 + seconds' = fromEnum $ second time 479 + 480 + {------------------------------------------------------------------------------- 481 + | Return the given local date and time as ISO ISO 8601 string as UTC. 482 + | 483 + | All bounds are checked, but for dates like the `31st of November` the 484 + | `1st of December` is returned. `30th February` yields `2nd (or 1st) March`. 485 + | A date like the `52th of November` yields `Nothing`. 486 + | 487 + | * year - The Year 488 + | * month - The month (starting at 1, January is 1) 489 + | * day - The day of the month (starting at 1) 490 + | * hour - The hour 491 + | * minutes - The minutes 492 + | * seconds - The seconds 493 + -} 494 + isoDateTimeInts :: 495 + Int -> Int -> Int -> Int -> Int -> Int -> Maybe String 496 + isoDateTimeInts yearI monthI dayI hourI minuteI secondsI = do 497 + year' <- toEnum yearI 498 + month' <- toEnum monthI 499 + day' <- toEnum dayI 500 + hour' <- toEnum hourI 501 + minute' <- toEnum minuteI 502 + seconds' <- toEnum secondsI 503 + millis' <- toEnum 0 504 + let 505 + date = canonicalDate year' month' day' 506 + 507 + time = Time hour' minute' seconds' millis' 508 + pure $ isoDateTime (DateTime date time) 509 + 510 + {------------------------------------------------------------------------------- 511 + | Return the given date and time as ISO ISO 8601 string as UTC. 512 + | 513 + | No bounds are checked, a date like the `52th of November` yields 514 + | `22nd of December`. 515 + | 516 + | * year - The Year 517 + | * month - The month (starting at 1, January is 1) 518 + | * day - The day of the month (starting at 1) 519 + | * hour - The hour 520 + | * minutes - The minutes 521 + | * seconds - The seconds 522 + -} 523 + isoDateTimeIntsUnsafe :: 524 + Int -> Int -> Int -> Int -> Int -> Int -> String 525 + isoDateTimeIntsUnsafe yearI monthI dayI hourI minuteI secondsI = runFn6 isoDateTimeJS yearI (monthI - 1) dayI hourI minuteI secondsI 526 + 527 + foreign import formatDateJS :: Fn4 DateTimeFormat Int Int Int String 528 + 529 + {------------------------------------------------------------------------------- 530 + | Return the given local date formatted by the given formatter. 531 + | 532 + | All bounds are checked, but for dates like the `31st of November` the 533 + | `1st of December` is returned. `30th February` yields `2nd (or 1st) March`. 534 + | A date like the `52th of November` yields `Nothing`. 535 + | 536 + | * formatter - The format to use 537 + | * date - The local date to format 538 + -} 539 + formatDate :: DateTimeFormat -> Date -> String 540 + formatDate formatter date = runFn4 formatDateJS formatter year' month' day' 541 + where 542 + year' = fromEnum $ year date 543 + 544 + month' = (fromEnum $ month date) - 1 545 + 546 + day' = fromEnum $ day date 547 + 548 + {------------------------------------------------------------------------------- 549 + | Return the given local date formatted by the given formatter. 550 + | 551 + | All bounds are checked, but for dates like the `31st of November` the 552 + | `1st of December` is returned. `30th February` yields `2nd (or 1st) March`. 553 + | A date like the `52th of November` yields `Nothing`. 554 + | 555 + | * formatter - The format to use 556 + | * year - The Year 557 + | * month - The month (starting at 1, January is 1) 558 + | * day - The day of the month (starting at 1) 559 + -} 560 + formatDateInts :: DateTimeFormat -> Int -> Int -> Int -> Maybe String 561 + formatDateInts formatter yearI monthI dayI = do 562 + year' <- toEnum yearI 563 + month' <- toEnum monthI 564 + day' <- toEnum dayI 565 + let 566 + date = canonicalDate year' month' day' 567 + pure $ formatDate formatter date 568 + 569 + {------------------------------------------------------------------------------- 570 + | Return the given date formatted by the given formatter. 571 + | 572 + | No bounds are checked, a date like the `52th of November` yields 573 + | `22nd of December`. 574 + | 575 + | * formatter - The format to use 576 + | * year - The Year 577 + | * month - The month (starting at 1, January is 1) 578 + | * day - The day of the month (starting at 1) 579 + -} 580 + formatDateIntsUnsafe :: DateTimeFormat -> Int -> Int -> Int -> String 581 + formatDateIntsUnsafe formatter yearI monthI dayI = runFn4 formatDateJS formatter yearI (monthI - 1) dayI 582 + 583 + foreign import formatDateTimeJS :: Fn7 DateTimeFormat Int Int Int Int Int Int String 584 + 585 + {------------------------------------------------------------------------------- 586 + | Return the given local date and time formatted by the given formatter. 587 + | 588 + | All bounds are checked, but for dates like the `31st of November` the 589 + | `1st of December` is returned. `30th February` yields `2nd (or 1st) March`. 590 + | A date like the `52th of November` yields `Nothing`. 591 + | 592 + | * formatter - The format to use 593 + | * dateTime - The local date and time to format 594 + -} 595 + formatDateTime :: DateTimeFormat -> DateTime -> String 596 + formatDateTime formatter (DateTime date time) = runFn7 formatDateTimeJS formatter year' month' day' hour' minute' seconds' 597 + where 598 + year' = fromEnum $ year date 599 + 600 + month' = (fromEnum $ month date) - 1 601 + 602 + day' = fromEnum $ day date 603 + 604 + hour' = fromEnum $ hour time 605 + 606 + minute' = fromEnum $ minute time 607 + 608 + seconds' = fromEnum $ second time 609 + 610 + {------------------------------------------------------------------------------- 611 + | Return the given local date and time formatted by the given formatter. 612 + | 613 + | All bounds are checked, but for dates like the `31st of November` the 614 + | `1st of December` is returned. `30th February` yields `2nd (or 1st) March`. 615 + | A date like the `52th of November` yields `Nothing`. 616 + | 617 + | * formatter - The format to use 618 + | * year - The Year 619 + | * month - The month (starting at 1, January is 1) 620 + | * day - The day of the month (starting at 1) 621 + | * hour - The hour 622 + | * minutes - The minutes 623 + | * seconds - The seconds 624 + -} 625 + formatDateTimeInts :: 626 + DateTimeFormat -> Int -> Int -> Int -> Int -> Int -> Int -> Maybe String 627 + formatDateTimeInts formatter yearI monthI dayI hourI minuteI secondsI = do 628 + year' <- toEnum yearI 629 + month' <- toEnum monthI 630 + day' <- toEnum dayI 631 + hour' <- toEnum hourI 632 + minute' <- toEnum minuteI 633 + seconds' <- toEnum secondsI 634 + millis' <- toEnum 0 635 + let 636 + date = canonicalDate year' month' day' 637 + 638 + time = Time hour' minute' seconds' millis' 639 + pure $ formatDateTime formatter (DateTime date time) 640 + 641 + {------------------------------------------------------------------------------- 642 + | Return the given date and time formatted by the given formatter. 643 + | 644 + | No bounds are checked, a date like the `52th of November` yields 645 + | `22nd of December`. 646 + | 647 + | * formatter - The format to use 648 + | * year - The Year 649 + | * month - The month (starting at 1, January is 1) 650 + | * day - The day of the month (starting at 1) 651 + | * hour - The hour 652 + | * minutes - The minutes 653 + | * seconds - The seconds 654 + -} 655 + formatDateTimeIntsUnsafe :: 656 + DateTimeFormat -> Int -> Int -> Int -> Int -> Int -> Int -> String 657 + formatDateTimeIntsUnsafe formatter yearI monthI dayI hourI minuteI secondsI = runFn7 formatDateTimeJS formatter yearI (monthI - 1) dayI hourI minuteI secondsI 658 + 659 + {------------------------------------------------------------------------------- 660 + | The style with which to format the date. 661 + | 662 + | One of 663 + | * Full 664 + | * Long 665 + | * Medium 666 + | * Short 667 + -} 668 + data DateStyle 669 + = Full 670 + | Long 671 + | Medium 672 + | Short 673 + 674 + {------------------------------------------------------------------------------- 675 + | The possible values of the `dateStyle` field in the Javascript options record. 676 + -} 677 + dateStyleJS :: 678 + { full :: String 679 + , long :: String 680 + , medium :: String 681 + , short :: String 682 + } 683 + dateStyleJS = 684 + { full: "full" 685 + , long: "long" 686 + , medium: "medium" 687 + , short: "short" 688 + } 689 + 690 + toDateStyleJS :: DateStyle -> String 691 + toDateStyleJS Full = dateStyleJS.full 692 + 693 + toDateStyleJS Long = dateStyleJS.long 694 + 695 + toDateStyleJS Medium = dateStyleJS.medium 696 + 697 + toDateStyleJS Short = dateStyleJS.short 698 + 699 + derive instance eqDateStyle :: Eq DateStyle 700 + 701 + derive instance ordDateStyle :: Ord DateStyle 702 + 703 + derive instance genericDateStyle :: Generic DateStyle _ 704 + 705 + instance decodeJsonDateStyle :: DecodeJson DateStyle where 706 + decodeJson = genericDecodeJson 707 + 708 + instance encodeJsonDateStyle :: EncodeJson DateStyle where 709 + encodeJson = genericEncodeJson 710 + 711 + instance showDateStyle :: Show DateStyle where 712 + show = genericShow 713 + 714 + {------------------------------------------------------------------------------- 715 + ATTENTION: 4 is the number of values of `DateStyle`. 716 + -} 717 + instance arbitraryDateStyle :: Arbitrary DateStyle where 718 + arbitrary = map intToDateStyle arbitrary 719 + where 720 + intToDateStyle :: Int -> DateStyle 721 + intToDateStyle n 722 + | n >= 0 = case n `mod` 4 of 723 + 0 -> Full 724 + 1 -> Long 725 + 2 -> Medium 726 + _ -> Short 727 + | otherwise = intToDateStyle (-n) 728 + 729 + {------------------------------------------------------------------------------- 730 + | The style of the time format. 731 + | 732 + | One of 733 + | * FullT 734 + | * LongT 735 + | * MediumT 736 + | * ShortT 737 + -} 738 + data TimeStyle 739 + = FullT 740 + | LongT 741 + | MediumT 742 + | ShortT 743 + 744 + {------------------------------------------------------------------------------- 745 + | The possible values of the `timeStyle` field in the Javascript options record. 746 + -} 747 + timeStyleJS :: 748 + { full :: String 749 + , long :: String 750 + , medium :: String 751 + , short :: String 752 + } 753 + timeStyleJS = 754 + { full: "full" 755 + , long: "long" 756 + , medium: "medium" 757 + , short: "short" 758 + } 759 + 760 + toTimeStyleJS :: TimeStyle -> String 761 + toTimeStyleJS FullT = timeStyleJS.full 762 + 763 + toTimeStyleJS LongT = timeStyleJS.long 764 + 765 + toTimeStyleJS MediumT = timeStyleJS.medium 766 + 767 + toTimeStyleJS ShortT = timeStyleJS.short 768 + 769 + derive instance eqTimeStyle :: Eq TimeStyle 770 + 771 + derive instance ordTimeStyle :: Ord TimeStyle 772 + 773 + derive instance genericTimeStyle :: Generic TimeStyle _ 774 + 775 + instance decodeJsonTimeStyle :: DecodeJson TimeStyle where 776 + decodeJson = genericDecodeJson 777 + 778 + instance encodeJsonTimeStyle :: EncodeJson TimeStyle where 779 + encodeJson = genericEncodeJson 780 + 781 + instance showTimeStyle :: Show TimeStyle where 782 + show = genericShow 783 + 784 + {------------------------------------------------------------------------------- 785 + ATTENTION: 4 is the number of values of `TimeStyle`. 786 + -} 787 + instance arbitraryTimeStyle :: Arbitrary TimeStyle where 788 + arbitrary = map intToTimeStyle arbitrary 789 + where 790 + intToTimeStyle :: Int -> TimeStyle 791 + intToTimeStyle n 792 + | n >= 0 = case n `mod` 4 of 793 + 0 -> FullT 794 + 1 -> LongT 795 + 2 -> MediumT 796 + _ -> ShortT 797 + | otherwise = intToTimeStyle (-n) 798 + 799 + {------------------------------------------------------------------------------- 800 + | The format of a day period - like `AM` and `PM`. 801 + | 802 + | 12 hour format must be enabled for this to have an effect. 803 + | 804 + | One of 805 + | * Narrow 806 + | * Short 807 + | * Long 808 + -} 809 + data DayPeriod 810 + = NarrowDP 811 + | ShortDP 812 + | LongDP 813 + 814 + {------------------------------------------------------------------------------- 815 + | The format of a day period, values for Javascript FFI. 816 + -} 817 + dayPeriodJS :: 818 + { long :: String 819 + , narrow :: String 820 + , short :: String 821 + } 822 + dayPeriodJS = { narrow: "narrow", short: "short", long: "long" } 823 + 824 + toDayPeriodJS :: DayPeriod -> String 825 + toDayPeriodJS NarrowDP = dayPeriodJS.narrow 826 + 827 + toDayPeriodJS ShortDP = dayPeriodJS.short 828 + 829 + toDayPeriodJS LongDP = dayPeriodJS.long 830 + 831 + derive instance eqDayPeriod :: Eq DayPeriod 832 + 833 + derive instance ordDayPeriod :: Ord DayPeriod 834 + 835 + derive instance genericDayPeriod :: Generic DayPeriod _ 836 + 837 + instance decodeJsonDayPeriod :: DecodeJson DayPeriod where 838 + decodeJson = genericDecodeJson 839 + 840 + instance encodeJsonDayPeriod :: EncodeJson DayPeriod where 841 + encodeJson = genericEncodeJson 842 + 843 + instance showDayPeriod :: Show DayPeriod where 844 + show = genericShow 845 + 846 + {------------------------------------------------------------------------------- 847 + ATTENTION: 3 is the number of values of `DayPeriod`. 848 + -} 849 + instance arbitraryDayPeriod :: Arbitrary DayPeriod where 850 + arbitrary = map intToDayPeriod arbitrary 851 + where 852 + intToDayPeriod :: Int -> DayPeriod 853 + intToDayPeriod n 854 + | n >= 0 = case n `mod` 3 of 855 + 0 -> NarrowDP 856 + 1 -> ShortDP 857 + _ -> LongDP 858 + | otherwise = intToDayPeriod (-n) 859 + 860 + {------------------------------------------------------------------------------- 861 + | The options to match the locale. 862 + | 863 + | One of 864 + | * Lookup 865 + | * BestFit 866 + -} 867 + data LocaleMatcher 868 + = Lookup 869 + | BestFit 870 + 871 + {------------------------------------------------------------------------------- 872 + | The values of a `LocaleMatcher` for the JS FFI. 873 + -} 874 + localeMatcherJS :: 875 + { bestFit :: String 876 + , lookup :: String 877 + } 878 + localeMatcherJS = { lookup: "lookup", bestFit: "best fit" } 879 + 880 + toLocalMatcherJS :: LocaleMatcher -> String 881 + toLocalMatcherJS Lookup = localeMatcherJS.lookup 882 + 883 + toLocalMatcherJS BestFit = localeMatcherJS.bestFit 884 + 885 + derive instance eqLocaleMatcher :: Eq LocaleMatcher 886 + 887 + derive instance ordLocaleMatcher :: Ord LocaleMatcher 888 + 889 + derive instance genericLocaleMatcher :: Generic LocaleMatcher _ 890 + 891 + instance decodeJsonLocaleMatcher :: DecodeJson LocaleMatcher where 892 + decodeJson = genericDecodeJson 893 + 894 + instance encodeJsonLocaleMatcher :: EncodeJson LocaleMatcher where 895 + encodeJson = genericEncodeJson 896 + 897 + instance showLocaleMatcher :: Show LocaleMatcher where 898 + show = genericShow 899 + 900 + {------------------------------------------------------------------------------- 901 + ATTENTION: 2 is the number of values of `LocaleMatcher`. 902 + -} 903 + instance arbitraryLocaleMatcher :: Arbitrary LocaleMatcher where 904 + arbitrary = map intToLocaleMatcher arbitrary 905 + where 906 + intToLocaleMatcher :: Int -> LocaleMatcher 907 + intToLocaleMatcher n 908 + | n >= 0 = case n `mod` 2 of 909 + 0 -> Lookup 910 + _ -> BestFit 911 + | otherwise = intToLocaleMatcher (-n) 912 + 913 + {------------------------------------------------------------------------------- 914 + | The timezone of a locale. 915 + | 916 + | See https://www.iana.org/time-zones for (long ;) list. 917 + -} 918 + newtype TimeZone 919 + = TimeZone String 920 + 921 + derive newtype instance eqTimeZone :: Eq TimeZone 922 + 923 + derive newtype instance ordTimeZone :: Ord TimeZone 924 + 925 + derive newtype instance showTimeZone :: Show TimeZone 926 + 927 + derive newtype instance decodeJsonTimeZone :: DecodeJson TimeZone 928 + 929 + derive newtype instance encodeJsonTimeZone :: EncodeJson TimeZone 930 + 931 + derive instance genericTimeZone :: Generic TimeZone _ 932 + 933 + derive instance newtypeTimeZone :: Newtype TimeZone _ 934 + 935 + derive newtype instance arbitraryTimeZone :: Arbitrary TimeZone 936 + 937 + {------------------------------------------------------------------------------- 938 + | Convert a `TimeZone` to a `String`. 939 + | 940 + | * `obj` - The `TimeZone` to convert to a `String`. 941 + -} 942 + timeZoneToString :: TimeZone -> String 943 + timeZoneToString = unwrap 944 + 945 + {------------------------------------------------------------------------------- 946 + | Convert a String to a `TimeZone`. 947 + | 948 + | * `obj` - The `String` to convert to a `TimeZone`. 949 + -} 950 + stringToTimeZone :: String -> TimeZone 951 + stringToTimeZone = wrap 952 + 953 + {------------------------------------------------------------------------------- 954 + | Set the time formt to a 12 hour one. 955 + | 956 + | Only works if the number of hours isn't set to 24 elsewhere. 957 + | 958 + | One of 959 + | * Hour12 960 + | * Hour24 961 + -} 962 + data Hour12 963 + = Hour12 964 + | Hour24 965 + 966 + derive instance eqHour12 :: Eq Hour12 967 + 968 + derive instance ordHour12 :: Ord Hour12 969 + 970 + derive instance genericHour12 :: Generic Hour12 _ 971 + 972 + instance decodeJsonHour12 :: DecodeJson Hour12 where 973 + decodeJson = genericDecodeJson 974 + 975 + instance encodeJsonHour12 :: EncodeJson Hour12 where 976 + encodeJson = genericEncodeJson 977 + 978 + instance showHour12 :: Show Hour12 where 979 + show = genericShow 980 + 981 + {------------------------------------------------------------------------------- 982 + ATTENTION: 2 is the number of values of `Hour12`. 983 + -} 984 + instance arbitraryHour12 :: Arbitrary Hour12 where 985 + arbitrary = map intToHour12 arbitrary 986 + where 987 + intToHour12 :: Int -> Hour12 988 + intToHour12 n 989 + | n >= 0 = case n `mod` 2 of 990 + 0 -> Hour12 991 + _ -> Hour24 992 + | otherwise = intToHour12 (-n) 993 + 994 + hour12ToBoolean :: Hour12 -> Boolean 995 + hour12ToBoolean Hour12 = true 996 + 997 + hour12ToBoolean Hour24 = false 998 + 999 + {------------------------------------------------------------------------------- 1000 + | The number of hours in a clock cycle of a day. 1001 + | 1002 + | One of 1003 + | * H11 1004 + | * H12 1005 + | * H23 1006 + | * H24 1007 + -} 1008 + data HourCycle 1009 + = H11 1010 + | H12 1011 + | H23 1012 + | H24 1013 + 1014 + {------------------------------------------------------------------------------- 1015 + | The values of `HourCycle` fo teh JS FFI. 1016 + -} 1017 + hourCycleJS :: 1018 + { h11 :: String 1019 + , h12 :: String 1020 + , h23 :: String 1021 + , h24 :: String 1022 + } 1023 + hourCycleJS = { h11: "h11", h12: "h12", h23: "h23", h24: "h24" } 1024 + 1025 + toHourCycleJS :: HourCycle -> String 1026 + toHourCycleJS H11 = hourCycleJS.h11 1027 + 1028 + toHourCycleJS H12 = hourCycleJS.h12 1029 + 1030 + toHourCycleJS H23 = hourCycleJS.h23 1031 + 1032 + toHourCycleJS H24 = hourCycleJS.h24 1033 + 1034 + derive instance eqHourCycle :: Eq HourCycle 1035 + 1036 + derive instance ordHourCycle :: Ord HourCycle 1037 + 1038 + derive instance genericHourCycle :: Generic HourCycle _ 1039 + 1040 + instance decodeJsonHourCycle :: DecodeJson HourCycle where 1041 + decodeJson = genericDecodeJson 1042 + 1043 + instance encodeJsonHourCycle :: EncodeJson HourCycle where 1044 + encodeJson = genericEncodeJson 1045 + 1046 + instance showHourCycle :: Show HourCycle where 1047 + show = genericShow 1048 + 1049 + {------------------------------------------------------------------------------- 1050 + ATTENTION: 4 is the number of values of `HourCycle`. 1051 + -} 1052 + instance arbitraryHourCycle :: Arbitrary HourCycle where 1053 + arbitrary = map intToHourCycle arbitrary 1054 + where 1055 + intToHourCycle :: Int -> HourCycle 1056 + intToHourCycle n 1057 + | n >= 0 = case n `mod` 4 of 1058 + 0 -> H11 1059 + 1 -> H12 1060 + 2 -> H23 1061 + _ -> H24 1062 + | otherwise = intToHourCycle (-n) 1063 + 1064 + {------------------------------------------------------------------------------- 1065 + | The possible values of a format matcher. 1066 + | 1067 + | One of 1068 + | * BasicFM 1069 + | * BestFitFM 1070 + -} 1071 + data FormatMatcher 1072 + = BasicFM 1073 + | BestFitFM 1074 + 1075 + {------------------------------------------------------------------------------- 1076 + | The values for the formatMatcher in the DateTimeFormat options. 1077 + -} 1078 + formatMatcherJS :: 1079 + { basic :: String 1080 + , bestFit :: String 1081 + } 1082 + formatMatcherJS = { basic: "basic", bestFit: "best fit" } 1083 + 1084 + toFormatMatcherJS :: FormatMatcher -> String 1085 + toFormatMatcherJS BasicFM = formatMatcherJS.basic 1086 + 1087 + toFormatMatcherJS BestFitFM = formatMatcherJS.bestFit 1088 + 1089 + derive instance eqFormatMatcher :: Eq FormatMatcher 1090 + 1091 + derive instance ordFormatMatcher :: Ord FormatMatcher 1092 + 1093 + derive instance genericFormatMatcher :: Generic FormatMatcher _ 1094 + 1095 + instance decodeJsonFormatMatcher :: DecodeJson FormatMatcher where 1096 + decodeJson = genericDecodeJson 1097 + 1098 + instance encodeJsonFormatMatcher :: EncodeJson FormatMatcher where 1099 + encodeJson = genericEncodeJson 1100 + 1101 + instance showFormatMatcher :: Show FormatMatcher where 1102 + show = genericShow 1103 + 1104 + {------------------------------------------------------------------------------- 1105 + ATTENTION: 2 is the number of values of `FormatMatcher`. 1106 + -} 1107 + instance arbitraryFormatMatcher :: Arbitrary FormatMatcher where 1108 + arbitrary = map intToFormatMatcher arbitrary 1109 + where 1110 + intToFormatMatcher :: Int -> FormatMatcher 1111 + intToFormatMatcher n 1112 + | n >= 0 = case n `mod` 2 of 1113 + 0 -> BasicFM 1114 + _ -> BestFitFM 1115 + | otherwise = intToFormatMatcher (-n) 1116 + 1117 + {------------------------------------------------------------------------------- 1118 + | The possible values of a `WeekDayFormat` 1119 + | 1120 + | One of 1121 + | * LongWD 1122 + | * ShortWD 1123 + | * NarrowWD 1124 + -} 1125 + data WeekDayFormat 1126 + = LongWD 1127 + | ShortWD 1128 + | NarrowWD 1129 + 1130 + {------------------------------------------------------------------------------- 1131 + | JS values of `WeekDayFormat`. 1132 + -} 1133 + weekDayFormatJS :: 1134 + { long :: String 1135 + , narrow :: String 1136 + , short :: String 1137 + } 1138 + weekDayFormatJS = { long: "long", short: "short", narrow: "narrow" } 1139 + 1140 + toWeekDayFormatJS :: WeekDayFormat -> String 1141 + toWeekDayFormatJS LongWD = weekDayFormatJS.long 1142 + 1143 + toWeekDayFormatJS ShortWD = weekDayFormatJS.short 1144 + 1145 + toWeekDayFormatJS NarrowWD = weekDayFormatJS.narrow 1146 + 1147 + derive instance eqWeekDayFormat :: Eq WeekDayFormat 1148 + 1149 + derive instance ordWeekDayFormat :: Ord WeekDayFormat 1150 + 1151 + derive instance genericWeekDayFormat :: Generic WeekDayFormat _ 1152 + 1153 + instance decodeJsonWeekDayFormat :: DecodeJson WeekDayFormat where 1154 + decodeJson = genericDecodeJson 1155 + 1156 + instance encodeJsonWeekDayFormat :: EncodeJson WeekDayFormat where 1157 + encodeJson = genericEncodeJson 1158 + 1159 + instance showWeekDayFormat :: Show WeekDayFormat where 1160 + show = genericShow 1161 + 1162 + {------------------------------------------------------------------------------- 1163 + ATTENTION: 3 is the number of values of `WeekDayFormat`. 1164 + -} 1165 + instance arbitraryWeekDayFormat :: Arbitrary WeekDayFormat where 1166 + arbitrary = map intToWeekDayFormat arbitrary 1167 + where 1168 + intToWeekDayFormat :: Int -> WeekDayFormat 1169 + intToWeekDayFormat n 1170 + | n >= 0 = case n `mod` 3 of 1171 + 0 -> LongWD 1172 + 1 -> ShortWD 1173 + _ -> NarrowWD 1174 + | otherwise = intToWeekDayFormat (-n) 1175 + 1176 + {------------------------------------------------------------------------------- 1177 + | The format for the era of a date 1178 + | 1179 + | One of 1180 + | * LongE 1181 + | * ShortE 1182 + | * NarrowE 1183 + -} 1184 + data EraFormat 1185 + = LongE 1186 + | ShortE 1187 + | NarrowE 1188 + 1189 + {------------------------------------------------------------------------------- 1190 + | Values of the era format for JS FFI. 1191 + -} 1192 + eraFormatJS :: 1193 + { long :: String 1194 + , narrow :: String 1195 + , short :: String 1196 + } 1197 + eraFormatJS = { long: "long", short: "short", narrow: "narrow" } 1198 + 1199 + toEraFormatJS :: EraFormat -> String 1200 + toEraFormatJS LongE = eraFormatJS.long 1201 + 1202 + toEraFormatJS ShortE = eraFormatJS.short 1203 + 1204 + toEraFormatJS NarrowE = eraFormatJS.narrow 1205 + 1206 + derive instance eqEraFormat :: Eq EraFormat 1207 + 1208 + derive instance ordEraFormat :: Ord EraFormat 1209 + 1210 + derive instance genericEraFormat :: Generic EraFormat _ 1211 + 1212 + instance decodeJsonEraFormat :: DecodeJson EraFormat where 1213 + decodeJson = genericDecodeJson 1214 + 1215 + instance encodeJsonEraFormat :: EncodeJson EraFormat where 1216 + encodeJson = genericEncodeJson 1217 + 1218 + instance showEraFormat :: Show EraFormat where 1219 + show = genericShow 1220 + 1221 + {------------------------------------------------------------------------------- 1222 + ATTENTION: 3 is the number of values of `EraFormat`. 1223 + -} 1224 + instance arbitraryEraFormat :: Arbitrary EraFormat where 1225 + arbitrary = map intToEraFormat arbitrary 1226 + where 1227 + intToEraFormat :: Int -> EraFormat 1228 + intToEraFormat n 1229 + | n >= 0 = case n `mod` 3 of 1230 + 0 -> LongE 1231 + 1 -> ShortE 1232 + _ -> NarrowE 1233 + | otherwise = intToEraFormat (-n) 1234 + 1235 + {------------------------------------------------------------------------------- 1236 + | The format of a year in a date. 1237 + | 1238 + | One of 1239 + | * NumericY 1240 + | * TwoDigitY 1241 + -} 1242 + data YearFormat 1243 + = NumericY 1244 + | TwoDigitY 1245 + 1246 + {------------------------------------------------------------------------------- 1247 + | The format of a year, JS FFI version. 1248 + -} 1249 + yearFormatJS :: 1250 + { numeric :: String 1251 + , twoDigit :: String 1252 + } 1253 + yearFormatJS = { numeric: "numeric", twoDigit: "2-digit" } 1254 + 1255 + toYearFormatJS :: YearFormat -> String 1256 + toYearFormatJS NumericY = yearFormatJS.numeric 1257 + 1258 + toYearFormatJS TwoDigitY = yearFormatJS.twoDigit 1259 + 1260 + derive instance eqYearFormat :: Eq YearFormat 1261 + 1262 + derive instance ordYearFormat :: Ord YearFormat 1263 + 1264 + derive instance genericYearFormat :: Generic YearFormat _ 1265 + 1266 + instance decodeJsonYearFormat :: DecodeJson YearFormat where 1267 + decodeJson = genericDecodeJson 1268 + 1269 + instance encodeJsonYearFormat :: EncodeJson YearFormat where 1270 + encodeJson = genericEncodeJson 1271 + 1272 + instance showYearFormat :: Show YearFormat where 1273 + show = genericShow 1274 + 1275 + {------------------------------------------------------------------------------- 1276 + ATTENTION: 2 is the number of values of `YearFormat`. 1277 + -} 1278 + instance arbitraryYearFormat :: Arbitrary YearFormat where 1279 + arbitrary = map intToYearFormat arbitrary 1280 + where 1281 + intToYearFormat :: Int -> YearFormat 1282 + intToYearFormat n 1283 + | n >= 0 = case n `mod` 2 of 1284 + 0 -> NumericY 1285 + _ -> TwoDigitY 1286 + | otherwise = intToYearFormat (-n) 1287 + 1288 + {------------------------------------------------------------------------------- 1289 + | The format of a month. 1290 + | 1291 + | One of 1292 + | * NumericM 1293 + | * TwoDigitM 1294 + | * LongM 1295 + | * ShortM 1296 + | * NarrowM 1297 + -} 1298 + data MonthFormat 1299 + = NumericM 1300 + | TwoDigitM 1301 + | LongM 1302 + | ShortM 1303 + | NarrowM 1304 + 1305 + {------------------------------------------------------------------------------- 1306 + | Month format in the JS version for FFI. 1307 + -} 1308 + monthFormatJS ∷ 1309 + { long ∷ String 1310 + , narrow ∷ String 1311 + , numeric ∷ String 1312 + , short ∷ String 1313 + , twoDigit ∷ String 1314 + } 1315 + monthFormatJS = 1316 + { numeric: "numeric" 1317 + , twoDigit: "2-digit" 1318 + , long: "long" 1319 + , short: "short" 1320 + , narrow: "narrow" 1321 + } 1322 + 1323 + toMonthFormatJS :: MonthFormat -> String 1324 + toMonthFormatJS NumericM = monthFormatJS.numeric 1325 + 1326 + toMonthFormatJS TwoDigitM = monthFormatJS.twoDigit 1327 + 1328 + toMonthFormatJS LongM = monthFormatJS.long 1329 + 1330 + toMonthFormatJS ShortM = monthFormatJS.short 1331 + 1332 + toMonthFormatJS NarrowM = monthFormatJS.narrow 1333 + 1334 + derive instance eqMonthFormat :: Eq MonthFormat 1335 + 1336 + derive instance ordMonthFormat :: Ord MonthFormat 1337 + 1338 + derive instance genericMonthFormat :: Generic MonthFormat _ 1339 + 1340 + instance decodeJsonMonthFormat :: DecodeJson MonthFormat where 1341 + decodeJson = genericDecodeJson 1342 + 1343 + instance encodeJsonMonthFormat :: EncodeJson MonthFormat where 1344 + encodeJson = genericEncodeJson 1345 + 1346 + instance showMonthFormat :: Show MonthFormat where 1347 + show = genericShow 1348 + 1349 + {------------------------------------------------------------------------------- 1350 + ATTENTION: 5 is the number of values of `MonthFormat`. 1351 + -} 1352 + instance arbitraryMonthFormat :: Arbitrary MonthFormat where 1353 + arbitrary = map intToMonthFormat arbitrary 1354 + where 1355 + intToMonthFormat :: Int -> MonthFormat 1356 + intToMonthFormat n 1357 + | n >= 0 = case n `mod` 5 of 1358 + 0 -> NumericM 1359 + 1 -> TwoDigitM 1360 + 2 -> LongM 1361 + 3 -> ShortM 1362 + _ -> NarrowM 1363 + | otherwise = intToMonthFormat (-n) 1364 + 1365 + {------------------------------------------------------------------------------- 1366 + | The format of a day 1367 + | 1368 + | One of 1369 + | * NumericD 1370 + | * TwoDigitD 1371 + -} 1372 + data DayFormat 1373 + = NumericD 1374 + | TwoDigitD 1375 + 1376 + {------------------------------------------------------------------------------- 1377 + | The values of a day format for the JS FFI. 1378 + -} 1379 + dayFormatJS :: 1380 + { numeric :: String 1381 + , twoDigit :: String 1382 + } 1383 + dayFormatJS = { numeric: "numeric", twoDigit: "2-digit" } 1384 + 1385 + toDayFormatJS :: DayFormat -> String 1386 + toDayFormatJS NumericD = dayFormatJS.numeric 1387 + 1388 + toDayFormatJS TwoDigitD = dayFormatJS.twoDigit 1389 + 1390 + derive instance eqDayFormat :: Eq DayFormat 1391 + 1392 + derive instance ordDayFormat :: Ord DayFormat 1393 + 1394 + derive instance genericDayFormat :: Generic DayFormat _ 1395 + 1396 + instance decodeJsonDayFormat :: DecodeJson DayFormat where 1397 + decodeJson = genericDecodeJson 1398 + 1399 + instance encodeJsonDayFormat :: EncodeJson DayFormat where 1400 + encodeJson = genericEncodeJson 1401 + 1402 + instance showDayFormat :: Show DayFormat where 1403 + show = genericShow 1404 + 1405 + {------------------------------------------------------------------------------- 1406 + ATTENTION: 2 is the number of values of `DayFormat`. 1407 + -} 1408 + instance arbitraryDayFormat :: Arbitrary DayFormat where 1409 + arbitrary = map intToDayFormat arbitrary 1410 + where 1411 + intToDayFormat :: Int -> DayFormat 1412 + intToDayFormat n 1413 + | n >= 0 = case n `mod` 2 of 1414 + 0 -> NumericD 1415 + _ -> TwoDigitD 1416 + | otherwise = intToDayFormat (-n) 1417 + 1418 + {------------------------------------------------------------------------------- 1419 + | The format fo an hour. 1420 + | 1421 + | One of 1422 + | * NumericH 1423 + | * TwoDigitH 1424 + -} 1425 + data HourFormat 1426 + = NumericH 1427 + | TwoDigitH 1428 + 1429 + {------------------------------------------------------------------------------- 1430 + | The format of an hour, for JS FFI. 1431 + -} 1432 + hourFormatJS :: 1433 + { numeric :: String 1434 + , twoDigit :: String 1435 + } 1436 + hourFormatJS = { numeric: "numeric", twoDigit: "2-digit" } 1437 + 1438 + toHourFormatJS :: HourFormat -> String 1439 + toHourFormatJS NumericH = hourFormatJS.numeric 1440 + 1441 + toHourFormatJS TwoDigitH = hourFormatJS.twoDigit 1442 + 1443 + derive instance eqHourFormat :: Eq HourFormat 1444 + 1445 + derive instance ordHourFormat :: Ord HourFormat 1446 + 1447 + derive instance genericHourFormat :: Generic HourFormat _ 1448 + 1449 + instance decodeJsonHourFormat :: DecodeJson HourFormat where 1450 + decodeJson = genericDecodeJson 1451 + 1452 + instance encodeJsonHourFormat :: EncodeJson HourFormat where 1453 + encodeJson = genericEncodeJson 1454 + 1455 + instance showHourFormat :: Show HourFormat where 1456 + show = genericShow 1457 + 1458 + {------------------------------------------------------------------------------- 1459 + ATTENTION: 2 is the number of values of `HourFormat`. 1460 + -} 1461 + instance arbitraryHourFormat :: Arbitrary HourFormat where 1462 + arbitrary = map intToHourFormat arbitrary 1463 + where 1464 + intToHourFormat :: Int -> HourFormat 1465 + intToHourFormat n 1466 + | n >= 0 = case n `mod` 2 of 1467 + 0 -> NumericH 1468 + _ -> TwoDigitH 1469 + | otherwise = intToHourFormat (-n) 1470 + 1471 + {------------------------------------------------------------------------------- 1472 + | The format of a minute. 1473 + | 1474 + | One of 1475 + | * NumericMi 1476 + | * TwoDigitMi 1477 + -} 1478 + data MinuteFormat 1479 + = NumericMi 1480 + | TwoDigitMi 1481 + 1482 + {------------------------------------------------------------------------------- 1483 + | The minute format, JS interop. 1484 + -} 1485 + minuteFormatJS :: 1486 + { numeric :: String 1487 + , twoDigit :: String 1488 + } 1489 + minuteFormatJS = { numeric: "numeric", twoDigit: "2-digit" } 1490 + 1491 + toMinuteFormatJS :: MinuteFormat -> String 1492 + toMinuteFormatJS NumericMi = minuteFormatJS.numeric 1493 + 1494 + toMinuteFormatJS TwoDigitMi = minuteFormatJS.twoDigit 1495 + 1496 + derive instance eqMinuteFormat :: Eq MinuteFormat 1497 + 1498 + derive instance ordMinuteFormat :: Ord MinuteFormat 1499 + 1500 + derive instance genericMinuteFormat :: Generic MinuteFormat _ 1501 + 1502 + instance decodeJsonMinuteFormat :: DecodeJson MinuteFormat where 1503 + decodeJson = genericDecodeJson 1504 + 1505 + instance encodeJsonMinuteFormat :: EncodeJson MinuteFormat where 1506 + encodeJson = genericEncodeJson 1507 + 1508 + instance showMinuteFormat :: Show MinuteFormat where 1509 + show = genericShow 1510 + 1511 + {------------------------------------------------------------------------------- 1512 + ATTENTION: 2 is the number of values of `MinuteFormat`. 1513 + -} 1514 + instance arbitraryMinuteFormat :: Arbitrary MinuteFormat where 1515 + arbitrary = map intToMinuteFormat arbitrary 1516 + where 1517 + intToMinuteFormat :: Int -> MinuteFormat 1518 + intToMinuteFormat n 1519 + | n >= 0 = case n `mod` 2 of 1520 + 0 -> NumericMi 1521 + _ -> TwoDigitMi 1522 + | otherwise = intToMinuteFormat (-n) 1523 + 1524 + {------------------------------------------------------------------------------- 1525 + | The format of a second. 1526 + | 1527 + | One of 1528 + | * NumericS 1529 + | * TwoDigitS 1530 + -} 1531 + data SecondFormat 1532 + = NumericS 1533 + | TwoDigitS 1534 + 1535 + {------------------------------------------------------------------------------- 1536 + | Format of a second, JS FFI. 1537 + -} 1538 + secondFormatJS :: 1539 + { numeric :: String 1540 + , twoDigit :: String 1541 + } 1542 + secondFormatJS = { numeric: "numeric", twoDigit: "2-digit" } 1543 + 1544 + toSecondFormatJS :: SecondFormat -> String 1545 + toSecondFormatJS NumericS = secondFormatJS.numeric 1546 + 1547 + toSecondFormatJS TwoDigitS = secondFormatJS.twoDigit 1548 + 1549 + derive instance eqSecondFormat :: Eq SecondFormat 1550 + 1551 + derive instance ordSecondFormat :: Ord SecondFormat 1552 + 1553 + derive instance genericSecondFormat :: Generic SecondFormat _ 1554 + 1555 + instance decodeJsonSecondFormat :: DecodeJson SecondFormat where 1556 + decodeJson = genericDecodeJson 1557 + 1558 + instance encodeJsonSecondFormat :: EncodeJson SecondFormat where 1559 + encodeJson = genericEncodeJson 1560 + 1561 + instance showSecondFormat :: Show SecondFormat where 1562 + show = genericShow 1563 + 1564 + {------------------------------------------------------------------------------- 1565 + ATTENTION: 2 is the number of values of `SecondFormat`. 1566 + -} 1567 + instance arbitrarySecondFormat :: Arbitrary SecondFormat where 1568 + arbitrary = map intToSecondFormat arbitrary 1569 + where 1570 + intToSecondFormat :: Int -> SecondFormat 1571 + intToSecondFormat n 1572 + | n >= 0 = case n `mod` 2 of 1573 + 0 -> NumericS 1574 + _ -> TwoDigitS 1575 + | otherwise = intToSecondFormat (-n) 1576 + 1577 + {------------------------------------------------------------------------------- 1578 + | The number of digits in the fractional part of the second. 1579 + | 1580 + | One of 1581 + | * Digits0 1582 + | * Digits1 1583 + | * Digits2 1584 + | * Digits3 1585 + -} 1586 + data FractionalSecondDigits 1587 + = Digits0 1588 + | Digits1 1589 + | Digits2 1590 + | Digits3 1591 + 1592 + {------------------------------------------------------------------------------- 1593 + | The number of digits in the fractional part of a second, JS interop. 1594 + -} 1595 + fractionalSecondDigitsJS :: 1596 + { digits0 :: Int 1597 + , digits1 :: Int 1598 + , digits2 :: Int 1599 + , digits3 :: Int 1600 + } 1601 + fractionalSecondDigitsJS = 1602 + { digits0: 0 1603 + , digits1: 1 1604 + , digits2: 2 1605 + , digits3: 3 1606 + } 1607 + 1608 + toFractionalDigitsJS :: FractionalSecondDigits -> Int 1609 + toFractionalDigitsJS Digits0 = fractionalSecondDigitsJS.digits0 1610 + 1611 + toFractionalDigitsJS Digits1 = fractionalSecondDigitsJS.digits1 1612 + 1613 + toFractionalDigitsJS Digits2 = fractionalSecondDigitsJS.digits2 1614 + 1615 + toFractionalDigitsJS Digits3 = fractionalSecondDigitsJS.digits3 1616 + 1617 + derive instance eqFractionalSecondDigits :: Eq FractionalSecondDigits 1618 + 1619 + derive instance ordFractionalSecondDigits :: Ord FractionalSecondDigits 1620 + 1621 + derive instance genericFractionalSecondDigits :: Generic FractionalSecondDigits _ 1622 + 1623 + instance decodeJsonFractionalSecondDigits :: DecodeJson FractionalSecondDigits where 1624 + decodeJson = genericDecodeJson 1625 + 1626 + instance encodeJsonFractionalSecondDigits :: EncodeJson FractionalSecondDigits where 1627 + encodeJson = genericEncodeJson 1628 + 1629 + instance showFractionalSecondDigits :: Show FractionalSecondDigits where 1630 + show = genericShow 1631 + 1632 + {------------------------------------------------------------------------------- 1633 + ATTENTION: 4 is the number of values of `FractionalSecondDigits`. 1634 + -} 1635 + instance arbitraryFractionalSecondDigits :: Arbitrary FractionalSecondDigits where 1636 + arbitrary = map intToFractionalSecondDigits arbitrary 1637 + where 1638 + intToFractionalSecondDigits :: Int -> FractionalSecondDigits 1639 + intToFractionalSecondDigits n 1640 + | n >= 0 = case n `mod` 4 of 1641 + 0 -> Digits0 1642 + 0 -> Digits1 1643 + 0 -> Digits2 1644 + _ -> Digits3 1645 + | otherwise = intToFractionalSecondDigits (-n) 1646 + 1647 + {------------------------------------------------------------------------------- 1648 + | The style of the time zone name. 1649 + | 1650 + | One of 1651 + | * Short 1652 + | * Long 1653 + | * ShortOffset 1654 + | * LongOffset 1655 + | * ShortGeneric 1656 + | * LongGeneric 1657 + -} 1658 + data TimeZoneNameStyle 1659 + = ShortTZ 1660 + | LongTZ 1661 + | ShortOffsetTZ 1662 + | LongOffsetTZ 1663 + | ShortGenericTZ 1664 + | LongGenericTZ 1665 + 1666 + {------------------------------------------------------------------------------- 1667 + | The possible values of the `timeZoneName` field in the Javascript options 1668 + | record. 1669 + -} 1670 + timeZoneNameStyleJS :: 1671 + { long :: String 1672 + , longGeneric :: String 1673 + , longOffset :: String 1674 + , short :: String 1675 + , shortGeneric :: String 1676 + , shortOffset :: String 1677 + } 1678 + timeZoneNameStyleJS = 1679 + { short: "short" 1680 + , long: "long" 1681 + , shortOffset: "shortOffset" 1682 + , longOffset: "longOffset" 1683 + , shortGeneric: "shortGeneric" 1684 + , longGeneric: "longGeneric" 1685 + } 1686 + 1687 + toTimeZoneNameStyleJS :: TimeZoneNameStyle -> String 1688 + toTimeZoneNameStyleJS ShortTZ = timeZoneNameStyleJS.short 1689 + 1690 + toTimeZoneNameStyleJS LongTZ = timeZoneNameStyleJS.long 1691 + 1692 + toTimeZoneNameStyleJS ShortOffsetTZ = timeZoneNameStyleJS.shortOffset 1693 + 1694 + toTimeZoneNameStyleJS LongOffsetTZ = timeZoneNameStyleJS.longOffset 1695 + 1696 + toTimeZoneNameStyleJS ShortGenericTZ = timeZoneNameStyleJS.shortGeneric 1697 + 1698 + toTimeZoneNameStyleJS LongGenericTZ = timeZoneNameStyleJS.longGeneric 1699 + 1700 + derive instance eqTimeZoneNameStyle :: Eq TimeZoneNameStyle 1701 + 1702 + derive instance ordTimeZoneNameStyle :: Ord TimeZoneNameStyle 1703 + 1704 + derive instance genericTimeZoneNameStyle :: Generic TimeZoneNameStyle _ 1705 + 1706 + instance decodeJsonTimeZoneNameStyle :: DecodeJson TimeZoneNameStyle where 1707 + decodeJson = genericDecodeJson 1708 + 1709 + instance encodeJsonTimeZoneNameStyle :: EncodeJson TimeZoneNameStyle where 1710 + encodeJson = genericEncodeJson 1711 + 1712 + instance showTimeZoneNameStyle :: Show TimeZoneNameStyle where 1713 + show = genericShow 1714 + 1715 + {------------------------------------------------------------------------------- 1716 + ATTENTION: 6 is the number of values of `TimeZoneNameStyle`. 1717 + -} 1718 + instance arbitraryTimeZoneNameStyle :: Arbitrary TimeZoneNameStyle where 1719 + arbitrary = map intToTimeZoneNameStyle arbitrary 1720 + where 1721 + intToTimeZoneNameStyle :: Int -> TimeZoneNameStyle 1722 + intToTimeZoneNameStyle n 1723 + | n >= 0 = case n `mod` 6 of 1724 + 0 -> ShortTZ 1725 + 1 -> LongTZ 1726 + 2 -> ShortOffsetTZ 1727 + 3 -> LongOffsetTZ 1728 + 4 -> ShortGenericTZ 1729 + _ -> LongGenericTZ 1730 + | otherwise = intToTimeZoneNameStyle (-n) 1731 + 1732 + {------------------------------------------------------------------------------- 1733 + | The JS version of `DateTimeFormatOptions`, the record which is used for JS 1734 + | FFI. 1735 + -} 1736 + type DateTimeFormatOptionsJS 1737 + = { dateStyle :: UndefinedOr String 1738 + , timeStyle :: UndefinedOr String 1739 + , calendar :: UndefinedOr String 1740 + , dayPeriod :: UndefinedOr String 1741 + , numberingSystem :: UndefinedOr String 1742 + , localeMatcher :: UndefinedOr String 1743 + , timeZone :: UndefinedOr String 1744 + , hour12 :: UndefinedOr Boolean 1745 + , hourCycle :: UndefinedOr String 1746 + , formatMatcher :: UndefinedOr String 1747 + , weekDay :: UndefinedOr String 1748 + , era :: UndefinedOr String 1749 + , year :: UndefinedOr String 1750 + , month :: UndefinedOr String 1751 + , day :: UndefinedOr String 1752 + , hour :: UndefinedOr String 1753 + , minute :: UndefinedOr String 1754 + , second :: UndefinedOr String 1755 + , fractionalSecondDigits :: UndefinedOr Int 1756 + , timeZoneNameStyle :: UndefinedOr String 1757 + } 1758 + 1759 + {------------------------------------------------------------------------------- 1760 + | Helper function: convert a `DateTimeFormatOptions` object to a 1761 + | `DateTimeFormatOptionsJS` object. 1762 + -} 1763 + convertDateTimeOptions :: DateTimeFormatOptions -> DateTimeFormatOptionsJS 1764 + convertDateTimeOptions (DateTimeFormatOptions options) = 1765 + setDTFOJSFromMaybe setDateStyleJS options.dateStyle (cast {}) 1766 + # setDTFOJSFromMaybe setTimeStyleJS options.timeStyle 1767 + # setDTFOJSFromMaybe setCalendarFormatJS options.calendar 1768 + # setDTFOJSFromMaybe setDayPeriodStyleJS options.dayPeriod 1769 + # setDTFOJSFromMaybe setNumberingSystemJS options.numberingSystem 1770 + # setDTFOJSFromMaybe setLocaleMatcherJS options.localeMatcher 1771 + # setDTFOJSFromMaybe setTimeZoneJS options.timeZone 1772 + # setDTFOJSFromMaybe setHour12JS options.hour12 1773 + # setDTFOJSFromMaybe setHourCycleJS options.hourCycle 1774 + # setDTFOJSFromMaybe setFormatMatcherJS options.formatMatcher 1775 + # setDTFOJSFromMaybe setWeekDayFormatJS options.weekDay 1776 + # setDTFOJSFromMaybe setEraFormatJS options.era 1777 + # setDTFOJSFromMaybe setYearFormatJS options.year 1778 + # setDTFOJSFromMaybe setMonthFormatJS options.month 1779 + # setDTFOJSFromMaybe setDayFormatJS options.day 1780 + # setDTFOJSFromMaybe setHourFormatJS options.hour 1781 + # setDTFOJSFromMaybe setMinuteFormatJS options.minute 1782 + # setDTFOJSFromMaybe setSecondFormatJS options.second 1783 + # setDTFOJSFromMaybe setFractionalSecondDigitsJS options.fractionalSecondDigits 1784 + # setDTFOJSFromMaybe setTimeZoneNameStyleJS options.timeZoneNameStyle 1785 + 1786 + setDTFOJSFromMaybe :: 1787 + forall a. 1788 + (DateTimeFormatOptionsJS -> a -> DateTimeFormatOptionsJS) -> 1789 + Maybe a -> 1790 + DateTimeFormatOptionsJS -> 1791 + DateTimeFormatOptionsJS 1792 + setDTFOJSFromMaybe f (Just x) fmt = f fmt x 1793 + 1794 + setDTFOJSFromMaybe _ Nothing fmt = fmt 1795 + 1796 + setDateStyleJS :: 1797 + DateTimeFormatOptionsJS -> 1798 + DateStyle -> DateTimeFormatOptionsJS 1799 + setDateStyleJS fmt style = cast fmt { dateStyle = toDateStyleJS style } 1800 + 1801 + setTimeStyleJS :: 1802 + DateTimeFormatOptionsJS -> 1803 + TimeStyle -> DateTimeFormatOptionsJS 1804 + setTimeStyleJS fmt style = cast fmt { timeStyle = toTimeStyleJS style } 1805 + 1806 + setCalendarFormatJS :: 1807 + DateTimeFormatOptionsJS -> 1808 + CalendarFormat -> DateTimeFormatOptionsJS 1809 + setCalendarFormatJS fmt calFmt = cast fmt { calendar = calendarFormatToString calFmt } 1810 + 1811 + setDayPeriodStyleJS :: 1812 + DateTimeFormatOptionsJS -> 1813 + DayPeriod -> DateTimeFormatOptionsJS 1814 + setDayPeriodStyleJS fmt style = cast fmt { dayPeriod = toDayPeriodJS style } 1815 + 1816 + setNumberingSystemJS :: 1817 + DateTimeFormatOptionsJS -> 1818 + NumberingSystem -> DateTimeFormatOptionsJS 1819 + setNumberingSystemJS fmt numSys = cast fmt { numberingSystem = numberingSystemToString numSys } 1820 + 1821 + setLocaleMatcherJS :: 1822 + DateTimeFormatOptionsJS -> 1823 + LocaleMatcher -> DateTimeFormatOptionsJS 1824 + setLocaleMatcherJS fmt matcher = cast fmt { localeMatcher = toLocalMatcherJS matcher } 1825 + 1826 + setTimeZoneJS :: 1827 + DateTimeFormatOptionsJS -> 1828 + TimeZone -> DateTimeFormatOptionsJS 1829 + setTimeZoneJS fmt timezone = cast fmt { timeZone = timeZoneToString timezone } 1830 + 1831 + setHour12JS :: 1832 + DateTimeFormatOptionsJS -> 1833 + Hour12 -> DateTimeFormatOptionsJS 1834 + setHour12JS fmt hour12 = cast fmt { hour12 = hour12ToBoolean hour12 } 1835 + 1836 + setHourCycleJS :: 1837 + DateTimeFormatOptionsJS -> 1838 + HourCycle -> DateTimeFormatOptionsJS 1839 + setHourCycleJS fmt style = cast fmt { hourCycle = toHourCycleJS style } 1840 + 1841 + setFormatMatcherJS :: 1842 + DateTimeFormatOptionsJS -> 1843 + FormatMatcher -> DateTimeFormatOptionsJS 1844 + setFormatMatcherJS fmt style = cast fmt { formatMatcher = toFormatMatcherJS style } 1845 + 1846 + setWeekDayFormatJS :: 1847 + DateTimeFormatOptionsJS -> 1848 + WeekDayFormat -> DateTimeFormatOptionsJS 1849 + setWeekDayFormatJS fmt style = cast fmt { weekDay = toWeekDayFormatJS style } 1850 + 1851 + setEraFormatJS :: 1852 + DateTimeFormatOptionsJS -> 1853 + EraFormat -> DateTimeFormatOptionsJS 1854 + setEraFormatJS fmt style = cast fmt { era = toEraFormatJS style } 1855 + 1856 + setYearFormatJS :: 1857 + DateTimeFormatOptionsJS -> 1858 + YearFormat -> DateTimeFormatOptionsJS 1859 + setYearFormatJS fmt style = cast fmt { year = toYearFormatJS style } 1860 + 1861 + setMonthFormatJS :: 1862 + DateTimeFormatOptionsJS -> 1863 + MonthFormat -> DateTimeFormatOptionsJS 1864 + setMonthFormatJS fmt style = cast fmt { month = toMonthFormatJS style } 1865 + 1866 + setDayFormatJS :: 1867 + DateTimeFormatOptionsJS -> 1868 + DayFormat -> DateTimeFormatOptionsJS 1869 + setDayFormatJS fmt style = cast fmt { day = toDayFormatJS style } 1870 + 1871 + setHourFormatJS :: 1872 + DateTimeFormatOptionsJS -> 1873 + HourFormat -> DateTimeFormatOptionsJS 1874 + setHourFormatJS fmt style = cast fmt { hour = toHourFormatJS style } 1875 + 1876 + setMinuteFormatJS :: 1877 + DateTimeFormatOptionsJS -> 1878 + MinuteFormat -> DateTimeFormatOptionsJS 1879 + setMinuteFormatJS fmt style = cast fmt { minute = toMinuteFormatJS style } 1880 + 1881 + setSecondFormatJS :: 1882 + DateTimeFormatOptionsJS -> 1883 + SecondFormat -> DateTimeFormatOptionsJS 1884 + setSecondFormatJS fmt style = cast fmt { second = toSecondFormatJS style } 1885 + 1886 + setFractionalSecondDigitsJS :: 1887 + DateTimeFormatOptionsJS -> 1888 + FractionalSecondDigits -> DateTimeFormatOptionsJS 1889 + setFractionalSecondDigitsJS fmt style = cast fmt { fractionalSecondDigits = toFractionalDigitsJS style } 1890 + 1891 + setTimeZoneNameStyleJS :: 1892 + DateTimeFormatOptionsJS -> 1893 + TimeZoneNameStyle -> DateTimeFormatOptionsJS 1894 + setTimeZoneNameStyleJS fmt style = cast fmt { timeZoneNameStyle = toTimeZoneNameStyleJS style } 1895 + 1896 + {------------------------------------------------------------------------------- 1897 + | Regex matching a `String` not containing only whitespace or being empty. 1898 + -} 1899 + notOnlyWhitespaceRegex :: Regex 1900 + notOnlyWhitespaceRegex = unsafeRegex "\\S+" unicode
+500
src/Data/NumberingSystem.purs
··· 1 + -- SPDX-License-Identifier: MIT 2 + -- Copyright (C) 2022 Roland Csaszar 3 + -- 4 + -- Project: purescript-datetimeformat 5 + -- File: NumberingSystem.purs 6 + -- Date: 12.Feb.2022 7 + -- 8 + -- ============================================================================== 9 + -- | Module Data.NumberingSystem, the type of the numbering system of a locale. 10 + -- | See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/numberingSystem 11 + module Data.NumberingSystem 12 + ( NumberingSystem(..) 13 + , numberingSystemToString 14 + , toString 15 + ) where 16 + 17 + import Prelude 18 + import Data.Argonaut (class DecodeJson, class EncodeJson) 19 + import Data.Argonaut.Decode.Generic (genericDecodeJson) 20 + import Data.Argonaut.Encode.Generic (genericEncodeJson) 21 + import Data.Generic.Rep (class Generic) 22 + import Data.Show.Generic (genericShow) 23 + import Test.QuickCheck (class Arbitrary, arbitrary) 24 + 25 + {------------------------------------------------------------------------------- 26 + | The numbering systems of locales. 27 + | 28 + | See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat 29 + | 30 + | One of 31 + | * Adlm - Adlam digits 32 + | * Ahom - Ahom digits 33 + | * Arab - Arabic-Indic digits 34 + | * Arabext - Extended Arabic-Indic digits 35 + | * Armn - Armenian upper case numerals — algorithmic 36 + | * Armnlow - Armenian lower case numerals — algorithmic 37 + | * Bali - Balinese digits 38 + | * Beng - Bengali digits 39 + | * Bhks - Bhaiksuki digits 40 + | * Brah - Brahmi digits 41 + | * Cakm - Chakma digits 42 + | * Cham - Cham digits 43 + | * Cyrl - Cyrillic numerals — algorithmic 44 + | * Deva - Devanagari digits 45 + | * Ethi - Ethiopic numerals — algorithmic 46 + | * Finance - Financial numerals — may be algorithmic 47 + | * Fullwide - Full width digits 48 + | * Geor - Georgian numerals — algorithmic 49 + | * Gong - Gunjala Gondi digits 50 + | * Gonm - Masaram Gondi digits 51 + | * Grek - Greek upper case numerals — algorithmic 52 + | * Greklow - Greek lower case numerals — algorithmic 53 + | * Gujr - Gujarati digits 54 + | * Guru - Gurmukhi digits 55 + | * Hanidays - Han-character day-of-month numbering for lunar/other traditional calendars 56 + | * Hanidec - Positional decimal system using Chinese number ideographs as digits 57 + | * Hans - Simplified Chinese numerals — algorithmic 58 + | * Hansfin - Simplified Chinese financial numerals — algorithmic 59 + | * Hant - Traditional Chinese numerals — algorithmic 60 + | * Hantfin - Traditional Chinese financial numerals — algorithmic 61 + | * Hebr - Hebrew numerals — algorithmic 62 + | * Hmng - Pahawh Hmong digits 63 + | * Hmnp - Nyiakeng Puachue Hmong digits 64 + | * Java - Javanese digits 65 + | * Jpan - Japanese numerals — algorithmic 66 + | * Jpanfin - Japanese financial numerals — algorithmic 67 + | * Jpanyear - Japanese first-year Gannen numbering for Japanese calendar 68 + | * Kali - Kayah Li digits 69 + | * Khmr - Khmer digits 70 + | * Knda - Kannada digits 71 + | * Lana - Tai Tham Hora (secular) digits 72 + | * Lanatham - Tai Tham (ecclesiastical) digits 73 + | * Laoo - Lao digits 74 + | * Latn - Latin digits 75 + | * Lepc - Lepcha digits 76 + | * Limb - Limbu digits 77 + | * Mathbold - Mathematical bold digits 78 + | * Mathdbl - Mathematical double-struck digits 79 + | * Mathmono - Mathematical monospace digits 80 + | * Mathsanb - Mathematical sans-serif bold digits 81 + | * Mathsans - Mathematical sans-serif digits 82 + | * Mlym - Malayalam digits 83 + | * Modi - Modi digits 84 + | * Mong - Mongolian digits 85 + | * Mroo - Mro digits 86 + | * Mtei - Meetei Mayek digits 87 + | * Mymr - Myanmar digits 88 + | * Mymrshan - Myanmar Shan digits 89 + | * Mymrtlng - Myanmar Tai Laing digits 90 + | * Native - Native digits 91 + | * Newa - Newa digits 92 + | * Nkoo - N'Ko digits 93 + | * Olck - Ol Chiki digits 94 + | * Orya - Oriya digits 95 + | * Osma - Osmanya digits 96 + | * Rohg - Hanifi Rohingya digits 97 + | * Roman - Roman upper case numerals — algorithmic 98 + | * Romanlow - Roman lowercase numerals — algorithmic 99 + | * Saur - Saurashtra digits 100 + | * Shrd - Sharada digits 101 + | * Sind - Khudawadi digits 102 + | * Sinh - Sinhala Lith digits 103 + | * Sora - Sora_Sompeng digits 104 + | * Sund - Sundanese digits 105 + | * Takr - Takri digits 106 + | * Talu - New Tai Lue digits 107 + | * Taml - Tamil numerals — algorithmic 108 + | * Tamldec - Modern Tamil decimal digits 109 + | * Telu - Telugu digits 110 + | * Thai - Thai digits 111 + | * Tirh - Tirhuta digits 112 + | * Tibt - Tibetan digits 113 + | * Traditio - Traditional numerals — may be algorithmic 114 + | * Vaii - Vai digits 115 + | * Wara - Warang Citi digits 116 + | * Wcho - Wancho digits 117 + -} 118 + data NumberingSystem 119 + = Adlm 120 + | Ahom 121 + | Arab 122 + | Arabext 123 + | Armn 124 + | Armnlow 125 + | Bali 126 + | Beng 127 + | Bhks 128 + | Brah 129 + | Cakm 130 + | Cham 131 + | Cyrl 132 + | Deva 133 + | Ethi 134 + | Finance 135 + | Fullwide 136 + | Geor 137 + | Gong 138 + | Gonm 139 + | Grek 140 + | Greklow 141 + | Gujr 142 + | Guru 143 + | Hanidays 144 + | Hanidec 145 + | Hans 146 + | Hansfin 147 + | Hant 148 + | Hantfin 149 + | Hebr 150 + | Hmng 151 + | Hmnp 152 + | Java 153 + | Jpan 154 + | Jpanfin 155 + | Jpanyear 156 + | Kali 157 + | Khmr 158 + | Knda 159 + | Lana 160 + | Lanatham 161 + | Laoo 162 + | Latn 163 + | Lepc 164 + | Limb 165 + | Mathbold 166 + | Mathdbl 167 + | Mathmono 168 + | Mathsanb 169 + | Mathsans 170 + | Mlym 171 + | Modi 172 + | Mong 173 + | Mroo 174 + | Mtei 175 + | Mymr 176 + | Mymrshan 177 + | Mymrtlng 178 + | Native 179 + | Newa 180 + | Nkoo 181 + | Olck 182 + | Orya 183 + | Osma 184 + | Rohg 185 + | Roman 186 + | Romanlow 187 + | Saur 188 + | Shrd 189 + | Sind 190 + | Sinh 191 + | Sora 192 + | Sund 193 + | Takr 194 + | Talu 195 + | Taml 196 + | Tamldec 197 + | Telu 198 + | Thai 199 + | Tirh 200 + | Tibt 201 + | Traditio 202 + | Vaii 203 + | Wara 204 + | Wcho 205 + 206 + derive instance eqNumberingSystem :: Eq NumberingSystem 207 + 208 + derive instance ordNumberingSystem :: Ord NumberingSystem 209 + 210 + derive instance genericNumberingSystem :: Generic NumberingSystem _ 211 + 212 + instance decodeJsonNumberingSystem :: DecodeJson NumberingSystem where 213 + decodeJson = genericDecodeJson 214 + 215 + instance encodeJsonNumberingSystem :: EncodeJson NumberingSystem where 216 + encodeJson = genericEncodeJson 217 + 218 + instance showNumberingSystem :: Show NumberingSystem where 219 + show = genericShow 220 + 221 + {------------------------------------------------------------------------------- 222 + ATTENTION: 86 is the number of values of `NumberingSystem`. 223 + -} 224 + instance arbitraryNumberingSystem :: Arbitrary NumberingSystem where 225 + arbitrary = map intToNumberingSystem arbitrary 226 + where 227 + intToNumberingSystem :: Int -> NumberingSystem 228 + intToNumberingSystem n 229 + | n >= 0 = case n `mod` 86 of 230 + 0 -> Adlm 231 + 1 -> Ahom 232 + 2 -> Arab 233 + 3 -> Arabext 234 + 4 -> Armn 235 + 5 -> Armnlow 236 + 6 -> Bali 237 + 7 -> Beng 238 + 8 -> Bhks 239 + 9 -> Brah 240 + 10 -> Cakm 241 + 11 -> Cham 242 + 12 -> Cyrl 243 + 13 -> Deva 244 + 14 -> Ethi 245 + 15 -> Finance 246 + 16 -> Fullwide 247 + 17 -> Geor 248 + 18 -> Gong 249 + 19 -> Gonm 250 + 20 -> Grek 251 + 21 -> Greklow 252 + 22 -> Gujr 253 + 23 -> Guru 254 + 24 -> Hanidays 255 + 25 -> Hanidec 256 + 26 -> Hans 257 + 27 -> Hansfin 258 + 28 -> Hant 259 + 29 -> Hantfin 260 + 30 -> Hebr 261 + 31 -> Hmng 262 + 32 -> Hmnp 263 + 33 -> Java 264 + 34 -> Jpan 265 + 35 -> Jpanfin 266 + 36 -> Jpanyear 267 + 37 -> Kali 268 + 38 -> Khmr 269 + 39 -> Knda 270 + 40 -> Lana 271 + 41 -> Lanatham 272 + 42 -> Laoo 273 + 43 -> Latn 274 + 44 -> Lepc 275 + 45 -> Limb 276 + 46 -> Mathbold 277 + 47 -> Mathdbl 278 + 48 -> Mathmono 279 + 49 -> Mathsanb 280 + 50 -> Mathsans 281 + 51 -> Mlym 282 + 52 -> Modi 283 + 53 -> Mong 284 + 54 -> Mroo 285 + 55 -> Mtei 286 + 56 -> Mymr 287 + 57 -> Mymrshan 288 + 58 -> Mymrtlng 289 + 59 -> Native 290 + 60 -> Newa 291 + 61 -> Nkoo 292 + 62 -> Olck 293 + 63 -> Orya 294 + 64 -> Osma 295 + 65 -> Rohg 296 + 66 -> Roman 297 + 67 -> Romanlow 298 + 68 -> Saur 299 + 69 -> Shrd 300 + 70 -> Sind 301 + 71 -> Sinh 302 + 72 -> Sora 303 + 73 -> Sund 304 + 74 -> Takr 305 + 75 -> Talu 306 + 76 -> Taml 307 + 77 -> Tamldec 308 + 78 -> Telu 309 + 79 -> Thai 310 + 80 -> Tirh 311 + 81 -> Tibt 312 + 82 -> Traditio 313 + 83 -> Vaii 314 + 84 -> Wara 315 + _ -> Wcho 316 + | otherwise = intToNumberingSystem (-n) 317 + 318 + {------------------------------------------------------------------------------- 319 + | Return the string representation of a `NumberingSystem`. 320 + | 321 + | A shorter alias of `numberingSystemToString`. 322 + -} 323 + toString ∷ NumberingSystem → String 324 + toString = numberingSystemToString 325 + 326 + {------------------------------------------------------------------------------- 327 + | Return the string representation of a `NumberingSystem`. 328 + -} 329 + numberingSystemToString :: NumberingSystem -> String 330 + numberingSystemToString Adlm = "adlm" 331 + 332 + numberingSystemToString Ahom = "ahom" 333 + 334 + numberingSystemToString Arab = "arab" 335 + 336 + numberingSystemToString Arabext = "arabext" 337 + 338 + numberingSystemToString Armn = "armn" 339 + 340 + numberingSystemToString Armnlow = "armnlow" 341 + 342 + numberingSystemToString Bali = "bali" 343 + 344 + numberingSystemToString Beng = "beng" 345 + 346 + numberingSystemToString Bhks = "bhks" 347 + 348 + numberingSystemToString Brah = "brah" 349 + 350 + numberingSystemToString Cakm = "cakm" 351 + 352 + numberingSystemToString Cham = "cham" 353 + 354 + numberingSystemToString Cyrl = "cyrl" 355 + 356 + numberingSystemToString Deva = "deva" 357 + 358 + numberingSystemToString Ethi = "ethi" 359 + 360 + numberingSystemToString Finance = "finance" 361 + 362 + numberingSystemToString Fullwide = "fullwide" 363 + 364 + numberingSystemToString Geor = "geor" 365 + 366 + numberingSystemToString Gong = "gong" 367 + 368 + numberingSystemToString Gonm = "gonm" 369 + 370 + numberingSystemToString Grek = "grek" 371 + 372 + numberingSystemToString Greklow = "greklow" 373 + 374 + numberingSystemToString Gujr = "gujr" 375 + 376 + numberingSystemToString Guru = "guru" 377 + 378 + numberingSystemToString Hanidays = "hanidays" 379 + 380 + numberingSystemToString Hanidec = "hanidec" 381 + 382 + numberingSystemToString Hans = "hans" 383 + 384 + numberingSystemToString Hansfin = "hansfin" 385 + 386 + numberingSystemToString Hant = "hant" 387 + 388 + numberingSystemToString Hantfin = "hantfin" 389 + 390 + numberingSystemToString Hebr = "hebr" 391 + 392 + numberingSystemToString Hmng = "hmng" 393 + 394 + numberingSystemToString Hmnp = "hmnp" 395 + 396 + numberingSystemToString Java = "java" 397 + 398 + numberingSystemToString Jpan = "jpan" 399 + 400 + numberingSystemToString Jpanfin = "jpanfin" 401 + 402 + numberingSystemToString Jpanyear = "jpanyear" 403 + 404 + numberingSystemToString Kali = "kali" 405 + 406 + numberingSystemToString Khmr = "khmr" 407 + 408 + numberingSystemToString Knda = "knda" 409 + 410 + numberingSystemToString Lana = "lana" 411 + 412 + numberingSystemToString Lanatham = "lanatham" 413 + 414 + numberingSystemToString Laoo = "laoo" 415 + 416 + numberingSystemToString Latn = "latn" 417 + 418 + numberingSystemToString Lepc = "lepc" 419 + 420 + numberingSystemToString Limb = "limb" 421 + 422 + numberingSystemToString Mathbold = "mathbold" 423 + 424 + numberingSystemToString Mathdbl = "mathdbl" 425 + 426 + numberingSystemToString Mathmono = "mathmono" 427 + 428 + numberingSystemToString Mathsanb = "mathsanb" 429 + 430 + numberingSystemToString Mathsans = "mathsans" 431 + 432 + numberingSystemToString Mlym = "mlym" 433 + 434 + numberingSystemToString Modi = "modi" 435 + 436 + numberingSystemToString Mong = "mong" 437 + 438 + numberingSystemToString Mroo = "mroo" 439 + 440 + numberingSystemToString Mtei = "mtei" 441 + 442 + numberingSystemToString Mymr = "mymr" 443 + 444 + numberingSystemToString Mymrshan = "mymrshan" 445 + 446 + numberingSystemToString Mymrtlng = "mymrtlng" 447 + 448 + numberingSystemToString Native = "native" 449 + 450 + numberingSystemToString Newa = "newa" 451 + 452 + numberingSystemToString Nkoo = "nkoo" 453 + 454 + numberingSystemToString Olck = "olck" 455 + 456 + numberingSystemToString Orya = "orya" 457 + 458 + numberingSystemToString Osma = "osma" 459 + 460 + numberingSystemToString Rohg = "rohg" 461 + 462 + numberingSystemToString Roman = "roman" 463 + 464 + numberingSystemToString Romanlow = "romanlow" 465 + 466 + numberingSystemToString Saur = "saur" 467 + 468 + numberingSystemToString Shrd = "shrd" 469 + 470 + numberingSystemToString Sind = "sind" 471 + 472 + numberingSystemToString Sinh = "sinh" 473 + 474 + numberingSystemToString Sora = "sora" 475 + 476 + numberingSystemToString Sund = "sund" 477 + 478 + numberingSystemToString Takr = "takr" 479 + 480 + numberingSystemToString Talu = "talu" 481 + 482 + numberingSystemToString Taml = "taml" 483 + 484 + numberingSystemToString Tamldec = "tamldec" 485 + 486 + numberingSystemToString Telu = "telu" 487 + 488 + numberingSystemToString Thai = "thai" 489 + 490 + numberingSystemToString Tirh = "tirh" 491 + 492 + numberingSystemToString Tibt = "tibt" 493 + 494 + numberingSystemToString Traditio = "traditio" 495 + 496 + numberingSystemToString Vaii = "vaii" 497 + 498 + numberingSystemToString Wara = "wara" 499 + 500 + numberingSystemToString Wcho = "wcho"