├── .babelrc ├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .github └── workflows │ └── test.yml ├── .gitignore ├── .nycrc ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bower.json ├── dist ├── fecha.min.js └── fecha.min.js.map ├── lib ├── fecha.d.ts ├── fecha.js ├── fecha.js.map ├── fecha.umd.js └── fecha.umd.js.map ├── package-lock.json ├── package.json ├── rollup.config.js ├── src └── fecha.ts ├── test.js ├── tsconfig.json └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env" 5 | ] 6 | ], 7 | "plugins": ["@babel/plugin-proposal-optional-chaining"] 8 | } -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | defaults -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 2 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | plugins: [ 5 | '@typescript-eslint', 6 | ], 7 | extends: [ 8 | 'eslint:recommended', 9 | 'plugin:@typescript-eslint/eslint-recommended', 10 | 'plugin:@typescript-eslint/recommended', 11 | 'prettier', 12 | ], 13 | rules: { 14 | "@typescript-eslint/ban-ts-ignore": "off" 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [12.x, 14.x, 16.x] 20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v3 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | cache: 'npm' 29 | - run: npm ci 30 | - run: npm run build --if-present 31 | - run: npm test 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | .nyc_output 4 | ts-out -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@istanbuljs/nyc-config-typescript" 3 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 12.14 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 4.2.3 2 | - Fixed bug with UTC date on daylights savings time #94 3 | 4 | ### 4.2.1 5 | - Fixed missing source map 6 | - Fixed security y18n 7 | 8 | ### 4.2.0 9 | Added isoDate and isoDateTime masks 10 | 11 | ### 4.1.0 12 | Added Z format/parse and fixed Peru timezone issue 13 | - Added `Z` format token. See readme for more info. Big thanks to @fer22f for writing the code. 14 | - Fixed a strange issue when Peru changed timezones in 1990. See #78 15 | 16 | ## 4.0.0 17 | **Major Features and Breaking changes in this version** 18 | 19 | #### Improvements 20 | - *Valid date parsing* - By default fecha will check validity of dates. Previously `2019-55-01` or `2019-01-42` would parse correctly, since Javascript can handle it. Now invalid dates will return `null` instead 21 | - *ES Module and Tree Shaking Support* - You can now import fecha `parse` or `format` independently 22 | ```js 23 | import {format, parse} from 'fecha'; 24 | 25 | format(...); 26 | parse(...) 27 | ``` 28 | 29 | #### Breaking changes 30 | - `parseDate` may return `null` when previously returned a `Date`. See improvements above, but invalid dates will return `null` now 31 | - Change to how to set masks and i18n 32 | Previously 33 | ```js 34 | import fecha from 'fecha'; 35 | 36 | fecha.i18n = { ... } 37 | fecha.masks.myMask = 'DD , MM, YYYY' 38 | ``` 39 | 40 | New 41 | ```js 42 | import {parse, format, setGlobalDateI18n, setGlobalDateMasks} from 'fecha'; 43 | 44 | setGlobalDateI18n({ 45 | // ... 46 | }) 47 | setGlobalDateMasks({ 48 | myMask: 'DD , MM, YYYY' 49 | }); 50 | ``` 51 | 52 | ### 3.0.3 53 | - Fixed bug when using brackets when parsing dates 54 | ### 3.0.2 55 | - Fixed issue where src files are not included correctly in npm 56 | 57 | ### 3.0.0 58 | - Moved to ES modules 59 | - Changed invalid date from `false` to `null` 60 | 61 | ### 2.3.3 62 | Fixed bug with year 999 not having leading zero 63 | 64 | ### 2.3.2 65 | Added typescript definitions to NPM 66 | 67 | ### 2.3.0 68 | Added strict version of date parser that returns null on invalid dates (may use strict version in v3) 69 | 70 | ### 2.2.0 71 | Fixed a bug when parsing Do format dates 72 | 73 | ## 2.0.0 74 | Fecha now throws errors on invalid dates in `fecha.format` and is stricter about what dates it accepts. Dates must pass `Object.prototype.toString.call(dateObj) !== '[object Date]'`. 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | We are open to, and grateful for, any contributions made by the community. 3 | 4 | ## Reporting Issues and Asking Questions 5 | Before opening an issue, please search the [issue tracker](https://github.com/taylorhakes/fecha/issues) to make sure your issue hasn't already been reported. 6 | 7 | ## Development 8 | 9 | Visit the [Issue tracker](https://github.com/taylorhakes/fecha/issues) to find a list of open issues that need attention. 10 | 11 | Fork, then clone the repo: 12 | ``` 13 | git clone https://github.com/your-username/fecha.git 14 | ``` 15 | 16 | ### New Features 17 | 18 | Please open an issue with a proposal for a new feature or refactoring before starting on the work. We don't want you to waste your efforts on a pull request that we won't want to accept. 19 | 20 | ## Submitting Changes 21 | 22 | * Open a new issue in the [Issue tracker](https://github.com/taylorhakes/fecha/issues). 23 | * Fork the repo. 24 | * Create a new feature branch based off the `master` branch. 25 | * Make sure all tests pass and there are no linting errors. 26 | * Submit a pull request, referencing any issues it addresses. 27 | 28 | Please try to keep your pull request focused in scope and avoid including unrelated commits. 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Taylor Hakes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fecha [![Build Status](https://travis-ci.org/taylorhakes/fecha.svg?branch=master)](https://travis-ci.org/taylorhakes/fecha) 2 | 3 | Lightweight date formatting and parsing (~2KB). Meant to replace parsing and formatting functionality of moment.js. 4 | 5 | ### NPM 6 | ``` 7 | npm install fecha --save 8 | ``` 9 | ### Yarn 10 | ``` 11 | yarn add fecha 12 | ``` 13 | 14 | ### Fecha vs Moment 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
FechaMoment
Size (Min. and Gzipped)2.1KBs13.1KBs
Date Parsing
Date Formatting
Date Manipulation
I18n Support
49 | 50 | ## Use it 51 | 52 | #### Formatting 53 | `format` accepts a Date object (or timestamp) and a string format and returns a formatted string. See below for 54 | available format tokens. 55 | 56 | Note: `format` will throw an error when passed invalid parameters 57 | ```js 58 | import { format } from 'fecha'; 59 | 60 | type format = (date: Date, format?: string, i18n?: I18nSettings) => str; 61 | 62 | // Custom formats 63 | format(new Date(2015, 10, 20), 'dddd MMMM Do, YYYY'); // 'Friday November 20th, 2015' 64 | format(new Date(1998, 5, 3, 15, 23, 10, 350), 'YYYY-MM-DD hh:mm:ss.SSS A'); // '1998-06-03 03:23:10.350 PM' 65 | 66 | // Named masks 67 | format(new Date(2015, 10, 20), 'isoDate'); // '2015-11-20' 68 | format(new Date(2015, 10, 20), 'mediumDate'); // 'Nov 20, 2015' 69 | format(new Date(2015, 10, 20, 3, 2, 1), 'isoDateTime'); // '2015-11-20T03:02:01-05:00' 70 | format(new Date(2015, 2, 10, 5, 30, 20), 'shortTime'); // '05:30' 71 | 72 | // Literals 73 | format(new Date(2001, 2, 5, 6, 7, 2, 5), '[on] MM-DD-YYYY [at] HH:mm'); // 'on 03-05-2001 at 06:07' 74 | ``` 75 | 76 | #### Parsing 77 | `parse` accepts a Date string and a string format and returns a Date object. See below for available format tokens. 78 | 79 | *NOTE*: `parse` will throw an error when passed invalid string format or missing format. You MUST specify a format. 80 | ```js 81 | import { parse } from 'fecha'; 82 | 83 | type parse = (dateStr: string, format: string, i18n?: I18nSettingsOptional) => Date|null; 84 | 85 | // Custom formats 86 | parse('February 3rd, 2014', 'MMMM Do, YYYY'); // new Date(2014, 1, 3) 87 | parse('10-12-10 14:11:12', 'YY-MM-DD HH:mm:ss'); // new Date(2010, 11, 10, 14, 11, 12) 88 | 89 | // Named masks 90 | parse('5/3/98', 'shortDate'); // new Date(1998, 4, 3) 91 | parse('November 4, 2005', 'longDate'); // new Date(2005, 10, 4) 92 | parse('2015-11-20T03:02:01-05:00', 'isoDateTime'); // new Date(2015, 10, 20, 3, 2, 1) 93 | 94 | // Override i18n 95 | parse('4 de octubre de 1983', 'M de MMMM de YYYY', { 96 | monthNames: [ 97 | 'enero', 98 | 'febrero', 99 | 'marzo', 100 | 'abril', 101 | 'mayo', 102 | 'junio', 103 | 'julio', 104 | 'agosto', 105 | 'septiembre', 106 | 'octubre', 107 | 'noviembre', 108 | 'diciembre' 109 | ] 110 | }); // new Date(1983, 9, 4) 111 | ``` 112 | 113 | #### i18n Support 114 | ```js 115 | import {setGlobalDateI18n} from 'fecha'; 116 | 117 | /* 118 | Default I18n Settings 119 | { 120 | dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat'], 121 | dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], 122 | monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], 123 | monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], 124 | amPm: ['am', 'pm'], 125 | // D is the day of the month, function returns something like... 3rd or 11th 126 | DoFn(dayOfMonth) { 127 | return dayOfMonth + [ 'th', 'st', 'nd', 'rd' ][ dayOfMonth % 10 > 3 ? 0 : (dayOfMonth - dayOfMonth % 10 !== 10) * dayOfMonth % 10 ]; 128 | } 129 | } 130 | */ 131 | 132 | setGlobalDateI18n({ 133 | dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat'], 134 | dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], 135 | monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], 136 | monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], 137 | amPm: ['am', 'pm'], 138 | // D is the day of the month, function returns something like... 3rd or 11th 139 | DoFn: function (D) { 140 | return D + [ 'th', 'st', 'nd', 'rd' ][ D % 10 > 3 ? 0 : (D - D % 10 !== 10) * D % 10 ]; 141 | } 142 | }); 143 | 144 | ``` 145 | 146 | #### Custom Named Masks 147 | ```js 148 | import { format, setGlobalDateMasks } from 'fecha'; 149 | /* 150 | Default global masks 151 | { 152 | default: 'ddd MMM DD YYYY HH:mm:ss', 153 | shortDate: 'M/D/YY', 154 | mediumDate: 'MMM D, YYYY', 155 | longDate: 'MMMM D, YYYY', 156 | fullDate: 'dddd, MMMM D, YYYY', 157 | shortTime: 'HH:mm', 158 | mediumTime: 'HH:mm:ss', 159 | longTime: 'HH:mm:ss.SSS' 160 | } 161 | */ 162 | 163 | // Create a new mask 164 | setGlobalDateMasks({ 165 | myMask: 'HH:mm:ss YY/MM/DD'; 166 | }); 167 | 168 | // Use it 169 | format(new Date(2014, 5, 6, 14, 10, 45), 'myMask'); // '14:10:45 14/06/06' 170 | ``` 171 | 172 | ### Formatting Tokens 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 311 | 312 | 313 | 314 | 315 | 318 | 319 | 320 |
TokenOutput
MonthM1 2 ... 11 12
MM01 02 ... 11 12
MMMJan Feb ... Nov Dec
MMMMJanuary February ... November December
Day of MonthD1 2 ... 30 31
Do1st 2nd ... 30th 31st
DD01 02 ... 30 31
Day of Weekd0 1 ... 5 6
dddSun Mon ... Fri Sat
ddddSunday Monday ... Friday Saturday
YearYY70 71 ... 29 30
YYYY1970 1971 ... 2029 2030
AM/PMAAM PM
aam pm
HourH0 1 ... 22 23
HH00 01 ... 22 23
h1 2 ... 11 12
hh01 02 ... 11 12
Minutem0 1 ... 58 59
mm00 01 ... 58 59
Seconds0 1 ... 58 59
ss00 01 ... 58 59
Fractional SecondS0 1 ... 8 9
SS0 1 ... 98 99
SSS0 1 ... 998 999
TimezoneZ 309 | -07:00 -06:00 ... +06:00 +07:00 310 |
ZZ 316 | -0700 -0600 ... +0600 +0700 317 |
321 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fecha", 3 | "main": "fecha.js", 4 | "version": "2.3.2", 5 | "homepage": "https://github.com/taylorhakes/fecha", 6 | "authors": [ 7 | "Taylor Hakes" 8 | ], 9 | "description": "Date formatting and parsing", 10 | "moduleType": [ 11 | "amd", 12 | "globals", 13 | "node" 14 | ], 15 | "keywords": [ 16 | "date", 17 | "parse", 18 | "moment", 19 | "format", 20 | "fecha", 21 | "formatting" 22 | ], 23 | "license": "MIT", 24 | "ignore": [ 25 | "**/.*", 26 | "node_modules", 27 | "bower_components", 28 | "test", 29 | "tests" 30 | ], 31 | "devDependencies": { 32 | "karma": "^0.12.31", 33 | "jasmine-core": "^2.1.3", 34 | "karma-jasmine": "^0.3.4", 35 | "karma-phantomjs-launcher": "^0.1.4", 36 | "karma-coverage": "^0.2.7", 37 | "gulp": "^3.8.10", 38 | "gulp-uglify": "^1.0.2", 39 | "gulp-rename": "^1.2.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /dist/fecha.min.js: -------------------------------------------------------------------------------- 1 | !function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.fecha={})}(this,function(t){"use strict";var n=/d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|Z|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g,e="[^\\s]+",r=/\[([^]*?)\]/gm;function o(t,n){for(var e=[],r=0,o=t.length;r-1?r:null}};function a(t){for(var n=[],e=1;e3?0:(t-t%10!=10?1:0)*t%10]}},m=a({},f),c=function(t){return m=a(m,t)},l=function(t){return t.replace(/[|\\{()[^$+*?.-]/g,"\\$&")},h=function(t,n){for(void 0===n&&(n=2),t=String(t);t.length0?"-":"+")+h(100*Math.floor(Math.abs(n)/60)+Math.abs(n)%60,4)},Z:function(t){var n=t.getTimezoneOffset();return(n>0?"-":"+")+h(Math.floor(Math.abs(n)/60),2)+":"+h(Math.abs(n)%60,2)}},M=function(t){return+t-1},D=[null,"\\d\\d?"],Y=[null,e],y=["isPm",e,function(t,n){var e=t.toLowerCase();return e===n.amPm[0]?0:e===n.amPm[1]?1:null}],p=["timezoneOffset","[^\\s]*?[\\+\\-]\\d\\d:?\\d\\d|[^\\s]*?Z?",function(t){var n=(t+"").match(/([+-]|\d\d)/gi);if(n){var e=60*+n[1]+parseInt(n[2],10);return"+"===n[0]?e:-e}return 0}],S={D:["day","\\d\\d?"],DD:["day","\\d\\d"],Do:["day","\\d\\d?"+e,function(t){return parseInt(t,10)}],M:["month","\\d\\d?",M],MM:["month","\\d\\d",M],YY:["year","\\d\\d",function(t){var n=+(""+(new Date).getFullYear()).substr(0,2);return+(""+(+t>68?n-1:n)+t)}],h:["hour","\\d\\d?",void 0,"isPm"],hh:["hour","\\d\\d",void 0,"isPm"],H:["hour","\\d\\d?"],HH:["hour","\\d\\d"],m:["minute","\\d\\d?"],mm:["minute","\\d\\d"],s:["second","\\d\\d?"],ss:["second","\\d\\d"],YYYY:["year","\\d{4}"],S:["millisecond","\\d",function(t){return 100*+t}],SS:["millisecond","\\d\\d",function(t){return 10*+t}],SSS:["millisecond","\\d{3}"],d:D,dd:D,ddd:Y,dddd:Y,MMM:["month",e,u("monthNamesShort")],MMMM:["month",e,u("monthNames")],a:y,A:y,ZZ:p,Z:p},v={default:"ddd MMM DD YYYY HH:mm:ss",shortDate:"M/D/YY",mediumDate:"MMM D, YYYY",longDate:"MMMM D, YYYY",fullDate:"dddd, MMMM D, YYYY",isoDate:"YYYY-MM-DD",isoDateTime:"YYYY-MM-DDTHH:mm:ssZ",shortTime:"HH:mm",mediumTime:"HH:mm:ss",longTime:"HH:mm:ss.SSS"},H=function(t){return a(v,t)},b=function(t,e,o){if(void 0===e&&(e=v.default),void 0===o&&(o={}),"number"==typeof t&&(t=new Date(t)),"[object Date]"!==Object.prototype.toString.call(t)||isNaN(t.getTime()))throw new Error("Invalid Date pass to format");var u=[];e=(e=v[e]||e).replace(r,function(t,n){return u.push(n),"@@@"});var i=a(a({},m),o);return(e=e.replace(n,function(n){return g[n](t,i)})).replace(/@@@/g,function(){return u.shift()})};function w(t,e,o){if(void 0===o&&(o={}),"string"!=typeof e)throw new Error("Invalid format in fecha parse");if(e=v[e]||e,t.length>1e3)return null;var u={year:(new Date).getFullYear(),month:0,day:1,hour:0,minute:0,second:0,millisecond:0,isPm:null,timezoneOffset:null},i=[],d=[],s=e.replace(r,function(t,n){return d.push(l(n)),"@@@"}),f={},c={};s=l(s).replace(n,function(t){var n=S[t],e=n[0],r=n[1],o=n[3];if(f[e])throw new Error("Invalid format. "+e+" specified twice in format");return f[e]=!0,o&&(c[o]=!0),i.push(n),"("+r+")"}),Object.keys(c).forEach(function(t){if(!f[t])throw new Error("Invalid format. "+t+" is required in specified format")}),s=s.replace(/@@@/g,function(){return d.shift()});var h=t.match(new RegExp(s,"i"));if(!h)return null;for(var g,M=a(a({},m),o),D=1;D11||u.month<0||u.day>31||u.day<1||u.hour>23||u.hour<0||u.minute>59||u.minute<0||u.second>59||u.second<0)return null;return g}var P={format:b,parse:w,defaultI18n:f,setGlobalDateI18n:c,setGlobalDateMasks:H};t.assign=a,t.default=P,t.format=b,t.parse=w,t.defaultI18n=f,t.setGlobalDateI18n=c,t.setGlobalDateMasks=H,Object.defineProperty(t,"__esModule",{value:!0})}); 2 | //# sourceMappingURL=fecha.min.js.map 3 | -------------------------------------------------------------------------------- /dist/fecha.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"fecha.min.js","sources":["../src/fecha.ts"],"sourcesContent":["const token = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|Z|([HhMsDm])\\1?|[aA]|\"[^\"]*\"|'[^']*'/g;\nconst twoDigitsOptional = \"\\\\d\\\\d?\";\nconst twoDigits = \"\\\\d\\\\d\";\nconst threeDigits = \"\\\\d{3}\";\nconst fourDigits = \"\\\\d{4}\";\nconst word = \"[^\\\\s]+\";\nconst literal = /\\[([^]*?)\\]/gm;\n\ntype DateInfo = {\n year: number;\n month: number;\n day: number;\n hour: number;\n minute: number;\n second: number;\n millisecond: number;\n isPm: number | null;\n timezoneOffset: number | null;\n};\n\nexport type I18nSettings = {\n amPm: [string, string];\n dayNames: Days;\n dayNamesShort: Days;\n monthNames: Months;\n monthNamesShort: Months;\n DoFn(dayOfMonth: number): string;\n};\n\nexport type I18nSettingsOptional = Partial;\n\nexport type Days = [string, string, string, string, string, string, string];\nexport type Months = [\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string\n];\n\nfunction shorten(arr: T, sLen: number): string[] {\n const newArr: string[] = [];\n for (let i = 0, len = arr.length; i < len; i++) {\n newArr.push(arr[i].substr(0, sLen));\n }\n return newArr;\n}\n\nconst monthUpdate = (\n arrName: \"monthNames\" | \"monthNamesShort\" | \"dayNames\" | \"dayNamesShort\"\n) => (v: string, i18n: I18nSettings): number | null => {\n const lowerCaseArr = i18n[arrName].map(v => v.toLowerCase());\n const index = lowerCaseArr.indexOf(v.toLowerCase());\n if (index > -1) {\n return index;\n }\n return null;\n};\n\nexport function assign(a: A): A;\nexport function assign(a: A, b: B): A & B;\nexport function assign(a: A, b: B, c: C): A & B & C;\nexport function assign(a: A, b: B, c: C, d: D): A & B & C & D;\nexport function assign(origObj: any, ...args: any[]): any {\n for (const obj of args) {\n for (const key in obj) {\n // @ts-ignore ex\n origObj[key] = obj[key];\n }\n }\n return origObj;\n}\n\nconst dayNames: Days = [\n \"Sunday\",\n \"Monday\",\n \"Tuesday\",\n \"Wednesday\",\n \"Thursday\",\n \"Friday\",\n \"Saturday\"\n];\nconst monthNames: Months = [\n \"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\"\n];\n\nconst monthNamesShort: Months = shorten(monthNames, 3) as Months;\nconst dayNamesShort: Days = shorten(dayNames, 3) as Days;\n\nconst defaultI18n: I18nSettings = {\n dayNamesShort,\n dayNames,\n monthNamesShort,\n monthNames,\n amPm: [\"am\", \"pm\"],\n DoFn(dayOfMonth: number) {\n return (\n dayOfMonth +\n [\"th\", \"st\", \"nd\", \"rd\"][\n dayOfMonth % 10 > 3\n ? 0\n : ((dayOfMonth - (dayOfMonth % 10) !== 10 ? 1 : 0) * dayOfMonth) % 10\n ]\n );\n }\n};\nlet globalI18n = assign({}, defaultI18n);\nconst setGlobalDateI18n = (i18n: I18nSettingsOptional): I18nSettings =>\n (globalI18n = assign(globalI18n, i18n));\n\nconst regexEscape = (str: string): string =>\n str.replace(/[|\\\\{()[^$+*?.-]/g, \"\\\\$&\");\n\nconst pad = (val: string | number, len = 2): string => {\n val = String(val);\n while (val.length < len) {\n val = \"0\" + val;\n }\n return val;\n};\n\nconst formatFlags: Record<\n string,\n (dateObj: Date, i18n: I18nSettings) => string\n> = {\n D: (dateObj: Date): string => String(dateObj.getDate()),\n DD: (dateObj: Date): string => pad(dateObj.getDate()),\n Do: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.DoFn(dateObj.getDate()),\n d: (dateObj: Date): string => String(dateObj.getDay()),\n dd: (dateObj: Date): string => pad(dateObj.getDay()),\n ddd: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.dayNamesShort[dateObj.getDay()],\n dddd: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.dayNames[dateObj.getDay()],\n M: (dateObj: Date): string => String(dateObj.getMonth() + 1),\n MM: (dateObj: Date): string => pad(dateObj.getMonth() + 1),\n MMM: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.monthNamesShort[dateObj.getMonth()],\n MMMM: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.monthNames[dateObj.getMonth()],\n YY: (dateObj: Date): string =>\n pad(String(dateObj.getFullYear()), 4).substr(2),\n YYYY: (dateObj: Date): string => pad(dateObj.getFullYear(), 4),\n h: (dateObj: Date): string => String(dateObj.getHours() % 12 || 12),\n hh: (dateObj: Date): string => pad(dateObj.getHours() % 12 || 12),\n H: (dateObj: Date): string => String(dateObj.getHours()),\n HH: (dateObj: Date): string => pad(dateObj.getHours()),\n m: (dateObj: Date): string => String(dateObj.getMinutes()),\n mm: (dateObj: Date): string => pad(dateObj.getMinutes()),\n s: (dateObj: Date): string => String(dateObj.getSeconds()),\n ss: (dateObj: Date): string => pad(dateObj.getSeconds()),\n S: (dateObj: Date): string =>\n String(Math.round(dateObj.getMilliseconds() / 100)),\n SS: (dateObj: Date): string =>\n pad(Math.round(dateObj.getMilliseconds() / 10), 2),\n SSS: (dateObj: Date): string => pad(dateObj.getMilliseconds(), 3),\n a: (dateObj: Date, i18n: I18nSettings): string =>\n dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1],\n A: (dateObj: Date, i18n: I18nSettings): string =>\n dateObj.getHours() < 12\n ? i18n.amPm[0].toUpperCase()\n : i18n.amPm[1].toUpperCase(),\n ZZ(dateObj: Date): string {\n const offset = dateObj.getTimezoneOffset();\n return (\n (offset > 0 ? \"-\" : \"+\") +\n pad(Math.floor(Math.abs(offset) / 60) * 100 + (Math.abs(offset) % 60), 4)\n );\n },\n Z(dateObj: Date): string {\n const offset = dateObj.getTimezoneOffset();\n return (\n (offset > 0 ? \"-\" : \"+\") +\n pad(Math.floor(Math.abs(offset) / 60), 2) +\n \":\" +\n pad(Math.abs(offset) % 60, 2)\n );\n }\n};\n\ntype ParseInfo = [\n keyof DateInfo,\n string,\n ((v: string, i18n: I18nSettings) => number | null)?,\n string?\n];\nconst monthParse = (v: string): number => +v - 1;\nconst emptyDigits: ParseInfo = [null, twoDigitsOptional];\nconst emptyWord: ParseInfo = [null, word];\nconst amPm: ParseInfo = [\n \"isPm\",\n word,\n (v: string, i18n: I18nSettings): number | null => {\n const val = v.toLowerCase();\n if (val === i18n.amPm[0]) {\n return 0;\n } else if (val === i18n.amPm[1]) {\n return 1;\n }\n return null;\n }\n];\nconst timezoneOffset: ParseInfo = [\n \"timezoneOffset\",\n \"[^\\\\s]*?[\\\\+\\\\-]\\\\d\\\\d:?\\\\d\\\\d|[^\\\\s]*?Z?\",\n (v: string): number | null => {\n const parts = (v + \"\").match(/([+-]|\\d\\d)/gi);\n\n if (parts) {\n const minutes = +parts[1] * 60 + parseInt(parts[2], 10);\n return parts[0] === \"+\" ? minutes : -minutes;\n }\n\n return 0;\n }\n];\nconst parseFlags: Record = {\n D: [\"day\", twoDigitsOptional],\n DD: [\"day\", twoDigits],\n Do: [\"day\", twoDigitsOptional + word, (v: string): number => parseInt(v, 10)],\n M: [\"month\", twoDigitsOptional, monthParse],\n MM: [\"month\", twoDigits, monthParse],\n YY: [\n \"year\",\n twoDigits,\n (v: string): number => {\n const now = new Date();\n const cent = +(\"\" + now.getFullYear()).substr(0, 2);\n return +(\"\" + (+v > 68 ? cent - 1 : cent) + v);\n }\n ],\n h: [\"hour\", twoDigitsOptional, undefined, \"isPm\"],\n hh: [\"hour\", twoDigits, undefined, \"isPm\"],\n H: [\"hour\", twoDigitsOptional],\n HH: [\"hour\", twoDigits],\n m: [\"minute\", twoDigitsOptional],\n mm: [\"minute\", twoDigits],\n s: [\"second\", twoDigitsOptional],\n ss: [\"second\", twoDigits],\n YYYY: [\"year\", fourDigits],\n S: [\"millisecond\", \"\\\\d\", (v: string): number => +v * 100],\n SS: [\"millisecond\", twoDigits, (v: string): number => +v * 10],\n SSS: [\"millisecond\", threeDigits],\n d: emptyDigits,\n dd: emptyDigits,\n ddd: emptyWord,\n dddd: emptyWord,\n MMM: [\"month\", word, monthUpdate(\"monthNamesShort\")],\n MMMM: [\"month\", word, monthUpdate(\"monthNames\")],\n a: amPm,\n A: amPm,\n ZZ: timezoneOffset,\n Z: timezoneOffset\n};\n\n// Some common format strings\nconst globalMasks: { [key: string]: string } = {\n default: \"ddd MMM DD YYYY HH:mm:ss\",\n shortDate: \"M/D/YY\",\n mediumDate: \"MMM D, YYYY\",\n longDate: \"MMMM D, YYYY\",\n fullDate: \"dddd, MMMM D, YYYY\",\n isoDate: \"YYYY-MM-DD\",\n isoDateTime: \"YYYY-MM-DDTHH:mm:ssZ\",\n shortTime: \"HH:mm\",\n mediumTime: \"HH:mm:ss\",\n longTime: \"HH:mm:ss.SSS\"\n};\nconst setGlobalDateMasks = (masks: {\n [key: string]: string;\n}): { [key: string]: string } => assign(globalMasks, masks);\n\n/***\n * Format a date\n * @method format\n * @param {Date|number} dateObj\n * @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate'\n * @returns {string} Formatted date string\n */\nconst format = (\n dateObj: Date,\n mask: string = globalMasks[\"default\"],\n i18n: I18nSettingsOptional = {}\n): string => {\n if (typeof dateObj === \"number\") {\n dateObj = new Date(dateObj);\n }\n\n if (\n Object.prototype.toString.call(dateObj) !== \"[object Date]\" ||\n isNaN(dateObj.getTime())\n ) {\n throw new Error(\"Invalid Date pass to format\");\n }\n\n mask = globalMasks[mask] || mask;\n\n const literals: string[] = [];\n\n // Make literals inactive by replacing them with @@@\n mask = mask.replace(literal, function($0, $1) {\n literals.push($1);\n return \"@@@\";\n });\n\n const combinedI18nSettings: I18nSettings = assign(\n assign({}, globalI18n),\n i18n\n );\n // Apply formatting rules\n mask = mask.replace(token, $0 =>\n formatFlags[$0](dateObj, combinedI18nSettings)\n );\n // Inline literal values back into the formatted value\n return mask.replace(/@@@/g, () => literals.shift());\n};\n\n/**\n * Parse a date string into a Javascript Date object /\n * @method parse\n * @param {string} dateStr Date string\n * @param {string} format Date parse format\n * @param {i18n} I18nSettingsOptional Full or subset of I18N settings\n * @returns {Date|null} Returns Date object. Returns null what date string is invalid or doesn't match format\n */\nfunction parse(\n dateStr: string,\n format: string,\n i18n: I18nSettingsOptional = {}\n): Date | null {\n if (typeof format !== \"string\") {\n throw new Error(\"Invalid format in fecha parse\");\n }\n\n // Check to see if the format is actually a mask\n format = globalMasks[format] || format;\n\n // Avoid regular expression denial of service, fail early for really long strings\n // https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS\n if (dateStr.length > 1000) {\n return null;\n }\n\n // Default to the beginning of the year.\n const today = new Date();\n const dateInfo: DateInfo = {\n year: today.getFullYear(),\n month: 0,\n day: 1,\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0,\n isPm: null,\n timezoneOffset: null\n };\n const parseInfo: ParseInfo[] = [];\n const literals: string[] = [];\n\n // Replace all the literals with @@@. Hopefully a string that won't exist in the format\n let newFormat = format.replace(literal, ($0, $1) => {\n literals.push(regexEscape($1));\n return \"@@@\";\n });\n const specifiedFields: { [field: string]: boolean } = {};\n const requiredFields: { [field: string]: boolean } = {};\n\n // Change every token that we find into the correct regex\n newFormat = regexEscape(newFormat).replace(token, $0 => {\n const info = parseFlags[$0];\n const [field, regex, , requiredField] = info;\n\n // Check if the person has specified the same field twice. This will lead to confusing results.\n if (specifiedFields[field]) {\n throw new Error(`Invalid format. ${field} specified twice in format`);\n }\n\n specifiedFields[field] = true;\n\n // Check if there are any required fields. For instance, 12 hour time requires AM/PM specified\n if (requiredField) {\n requiredFields[requiredField] = true;\n }\n\n parseInfo.push(info);\n return \"(\" + regex + \")\";\n });\n\n // Check all the required fields are present\n Object.keys(requiredFields).forEach(field => {\n if (!specifiedFields[field]) {\n throw new Error(\n `Invalid format. ${field} is required in specified format`\n );\n }\n });\n\n // Add back all the literals after\n newFormat = newFormat.replace(/@@@/g, () => literals.shift());\n\n // Check if the date string matches the format. If it doesn't return null\n const matches = dateStr.match(new RegExp(newFormat, \"i\"));\n if (!matches) {\n return null;\n }\n\n const combinedI18nSettings: I18nSettings = assign(\n assign({}, globalI18n),\n i18n\n );\n\n // For each match, call the parser function for that date part\n for (let i = 1; i < matches.length; i++) {\n const [field, , parser] = parseInfo[i - 1];\n const value = parser\n ? parser(matches[i], combinedI18nSettings)\n : +matches[i];\n\n // If the parser can't make sense of the value, return null\n if (value == null) {\n return null;\n }\n\n dateInfo[field] = value;\n }\n\n if (dateInfo.isPm === 1 && dateInfo.hour != null && +dateInfo.hour !== 12) {\n dateInfo.hour = +dateInfo.hour + 12;\n } else if (dateInfo.isPm === 0 && +dateInfo.hour === 12) {\n dateInfo.hour = 0;\n }\n\n let dateTZ: Date;\n if (dateInfo.timezoneOffset == null) {\n dateTZ = new Date(\n dateInfo.year,\n dateInfo.month,\n dateInfo.day,\n dateInfo.hour,\n dateInfo.minute,\n dateInfo.second,\n dateInfo.millisecond\n );\n const validateFields: [\n \"month\" | \"day\" | \"hour\" | \"minute\" | \"second\",\n \"getMonth\" | \"getDate\" | \"getHours\" | \"getMinutes\" | \"getSeconds\"\n ][] = [\n [\"month\", \"getMonth\"],\n [\"day\", \"getDate\"],\n [\"hour\", \"getHours\"],\n [\"minute\", \"getMinutes\"],\n [\"second\", \"getSeconds\"]\n ];\n for (let i = 0, len = validateFields.length; i < len; i++) {\n // Check to make sure the date field is within the allowed range. Javascript dates allows values\n // outside the allowed range. If the values don't match the value was invalid\n if (\n specifiedFields[validateFields[i][0]] &&\n dateInfo[validateFields[i][0]] !== dateTZ[validateFields[i][1]]()\n ) {\n return null;\n }\n }\n } else {\n dateTZ = new Date(\n Date.UTC(\n dateInfo.year,\n dateInfo.month,\n dateInfo.day,\n dateInfo.hour,\n dateInfo.minute - dateInfo.timezoneOffset,\n dateInfo.second,\n dateInfo.millisecond\n )\n );\n\n // We can't validate dates in another timezone unfortunately. Do a basic check instead\n if (\n dateInfo.month > 11 ||\n dateInfo.month < 0 ||\n dateInfo.day > 31 ||\n dateInfo.day < 1 ||\n dateInfo.hour > 23 ||\n dateInfo.hour < 0 ||\n dateInfo.minute > 59 ||\n dateInfo.minute < 0 ||\n dateInfo.second > 59 ||\n dateInfo.second < 0\n ) {\n return null;\n }\n }\n\n // Don't allow invalid dates\n\n return dateTZ;\n}\nexport default {\n format,\n parse,\n defaultI18n,\n setGlobalDateI18n,\n setGlobalDateMasks\n};\nexport { format, parse, defaultI18n, setGlobalDateI18n, setGlobalDateMasks };\n"],"names":["token","word","literal","shorten","arr","sLen","newArr","i","len","length","push","substr","monthUpdate","arrName","v","i18n","index","map","toLowerCase","indexOf","assign","origObj","_i","args","args_1","_a","obj","key","dayNames","monthNames","monthNamesShort","defaultI18n","dayNamesShort","amPm","DoFn","dayOfMonth","globalI18n","setGlobalDateI18n","regexEscape","str","replace","pad","val","String","formatFlags","D","dateObj","getDate","DD","Do","d","getDay","dd","ddd","dddd","M","getMonth","MM","MMM","MMMM","YY","getFullYear","YYYY","h","getHours","hh","H","HH","m","getMinutes","mm","s","getSeconds","ss","S","Math","round","getMilliseconds","SS","SSS","a","A","toUpperCase","ZZ","offset","getTimezoneOffset","floor","abs","Z","monthParse","emptyDigits","emptyWord","timezoneOffset","parts","match","minutes","parseInt","parseFlags","cent","Date","undefined","globalMasks","default","shortDate","mediumDate","longDate","fullDate","isoDate","isoDateTime","shortTime","mediumTime","longTime","setGlobalDateMasks","masks","format","mask","Object","prototype","toString","call","isNaN","getTime","Error","literals","$0","$1","combinedI18nSettings","shift","parse","dateStr","dateInfo","year","month","day","hour","minute","second","millisecond","isPm","parseInfo","newFormat","specifiedFields","requiredFields","info","field","regex","requiredField","keys","forEach","matches","RegExp","dateTZ","parser","value","validateFields","UTC"],"mappings":"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"} -------------------------------------------------------------------------------- /lib/fecha.d.ts: -------------------------------------------------------------------------------- 1 | export declare type I18nSettings = { 2 | amPm: [string, string]; 3 | dayNames: Days; 4 | dayNamesShort: Days; 5 | monthNames: Months; 6 | monthNamesShort: Months; 7 | DoFn(dayOfMonth: number): string; 8 | }; 9 | export declare type I18nSettingsOptional = Partial; 10 | export declare type Days = [string, string, string, string, string, string, string]; 11 | export declare type Months = [string, string, string, string, string, string, string, string, string, string, string, string]; 12 | export declare function assign(a: A): A; 13 | export declare function assign(a: A, b: B): A & B; 14 | export declare function assign(a: A, b: B, c: C): A & B & C; 15 | export declare function assign(a: A, b: B, c: C, d: D): A & B & C & D; 16 | declare const defaultI18n: I18nSettings; 17 | declare const setGlobalDateI18n: (i18n: I18nSettingsOptional) => I18nSettings; 18 | declare const setGlobalDateMasks: (masks: { 19 | [key: string]: string; 20 | }) => { 21 | [key: string]: string; 22 | }; 23 | /*** 24 | * Format a date 25 | * @method format 26 | * @param {Date|number} dateObj 27 | * @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate' 28 | * @returns {string} Formatted date string 29 | */ 30 | declare const format: (dateObj: Date, mask?: string, i18n?: I18nSettingsOptional) => string; 31 | /** 32 | * Parse a date string into a Javascript Date object / 33 | * @method parse 34 | * @param {string} dateStr Date string 35 | * @param {string} format Date parse format 36 | * @param {i18n} I18nSettingsOptional Full or subset of I18N settings 37 | * @returns {Date|null} Returns Date object. Returns null what date string is invalid or doesn't match format 38 | */ 39 | declare function parse(dateStr: string, format: string, i18n?: I18nSettingsOptional): Date | null; 40 | declare const _default: { 41 | format: (dateObj: Date, mask?: string, i18n?: Partial) => string; 42 | parse: typeof parse; 43 | defaultI18n: I18nSettings; 44 | setGlobalDateI18n: (i18n: Partial) => I18nSettings; 45 | setGlobalDateMasks: (masks: { 46 | [key: string]: string; 47 | }) => { 48 | [key: string]: string; 49 | }; 50 | }; 51 | export default _default; 52 | export { format, parse, defaultI18n, setGlobalDateI18n, setGlobalDateMasks }; 53 | -------------------------------------------------------------------------------- /lib/fecha.js: -------------------------------------------------------------------------------- 1 | var token = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|Z|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g; 2 | var twoDigitsOptional = "\\d\\d?"; 3 | var twoDigits = "\\d\\d"; 4 | var threeDigits = "\\d{3}"; 5 | var fourDigits = "\\d{4}"; 6 | var word = "[^\\s]+"; 7 | var literal = /\[([^]*?)\]/gm; 8 | function shorten(arr, sLen) { 9 | var newArr = []; 10 | for (var i = 0, len = arr.length; i < len; i++) { 11 | newArr.push(arr[i].substr(0, sLen)); 12 | } 13 | return newArr; 14 | } 15 | var monthUpdate = function (arrName) { return function (v, i18n) { 16 | var lowerCaseArr = i18n[arrName].map(function (v) { return v.toLowerCase(); }); 17 | var index = lowerCaseArr.indexOf(v.toLowerCase()); 18 | if (index > -1) { 19 | return index; 20 | } 21 | return null; 22 | }; }; 23 | function assign(origObj) { 24 | var args = []; 25 | for (var _i = 1; _i < arguments.length; _i++) { 26 | args[_i - 1] = arguments[_i]; 27 | } 28 | for (var _a = 0, args_1 = args; _a < args_1.length; _a++) { 29 | var obj = args_1[_a]; 30 | for (var key in obj) { 31 | // @ts-ignore ex 32 | origObj[key] = obj[key]; 33 | } 34 | } 35 | return origObj; 36 | } 37 | var dayNames = [ 38 | "Sunday", 39 | "Monday", 40 | "Tuesday", 41 | "Wednesday", 42 | "Thursday", 43 | "Friday", 44 | "Saturday" 45 | ]; 46 | var monthNames = [ 47 | "January", 48 | "February", 49 | "March", 50 | "April", 51 | "May", 52 | "June", 53 | "July", 54 | "August", 55 | "September", 56 | "October", 57 | "November", 58 | "December" 59 | ]; 60 | var monthNamesShort = shorten(monthNames, 3); 61 | var dayNamesShort = shorten(dayNames, 3); 62 | var defaultI18n = { 63 | dayNamesShort: dayNamesShort, 64 | dayNames: dayNames, 65 | monthNamesShort: monthNamesShort, 66 | monthNames: monthNames, 67 | amPm: ["am", "pm"], 68 | DoFn: function (dayOfMonth) { 69 | return (dayOfMonth + 70 | ["th", "st", "nd", "rd"][dayOfMonth % 10 > 3 71 | ? 0 72 | : ((dayOfMonth - (dayOfMonth % 10) !== 10 ? 1 : 0) * dayOfMonth) % 10]); 73 | } 74 | }; 75 | var globalI18n = assign({}, defaultI18n); 76 | var setGlobalDateI18n = function (i18n) { 77 | return (globalI18n = assign(globalI18n, i18n)); 78 | }; 79 | var regexEscape = function (str) { 80 | return str.replace(/[|\\{()[^$+*?.-]/g, "\\$&"); 81 | }; 82 | var pad = function (val, len) { 83 | if (len === void 0) { len = 2; } 84 | val = String(val); 85 | while (val.length < len) { 86 | val = "0" + val; 87 | } 88 | return val; 89 | }; 90 | var formatFlags = { 91 | D: function (dateObj) { return String(dateObj.getDate()); }, 92 | DD: function (dateObj) { return pad(dateObj.getDate()); }, 93 | Do: function (dateObj, i18n) { 94 | return i18n.DoFn(dateObj.getDate()); 95 | }, 96 | d: function (dateObj) { return String(dateObj.getDay()); }, 97 | dd: function (dateObj) { return pad(dateObj.getDay()); }, 98 | ddd: function (dateObj, i18n) { 99 | return i18n.dayNamesShort[dateObj.getDay()]; 100 | }, 101 | dddd: function (dateObj, i18n) { 102 | return i18n.dayNames[dateObj.getDay()]; 103 | }, 104 | M: function (dateObj) { return String(dateObj.getMonth() + 1); }, 105 | MM: function (dateObj) { return pad(dateObj.getMonth() + 1); }, 106 | MMM: function (dateObj, i18n) { 107 | return i18n.monthNamesShort[dateObj.getMonth()]; 108 | }, 109 | MMMM: function (dateObj, i18n) { 110 | return i18n.monthNames[dateObj.getMonth()]; 111 | }, 112 | YY: function (dateObj) { 113 | return pad(String(dateObj.getFullYear()), 4).substr(2); 114 | }, 115 | YYYY: function (dateObj) { return pad(dateObj.getFullYear(), 4); }, 116 | h: function (dateObj) { return String(dateObj.getHours() % 12 || 12); }, 117 | hh: function (dateObj) { return pad(dateObj.getHours() % 12 || 12); }, 118 | H: function (dateObj) { return String(dateObj.getHours()); }, 119 | HH: function (dateObj) { return pad(dateObj.getHours()); }, 120 | m: function (dateObj) { return String(dateObj.getMinutes()); }, 121 | mm: function (dateObj) { return pad(dateObj.getMinutes()); }, 122 | s: function (dateObj) { return String(dateObj.getSeconds()); }, 123 | ss: function (dateObj) { return pad(dateObj.getSeconds()); }, 124 | S: function (dateObj) { 125 | return String(Math.round(dateObj.getMilliseconds() / 100)); 126 | }, 127 | SS: function (dateObj) { 128 | return pad(Math.round(dateObj.getMilliseconds() / 10), 2); 129 | }, 130 | SSS: function (dateObj) { return pad(dateObj.getMilliseconds(), 3); }, 131 | a: function (dateObj, i18n) { 132 | return dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1]; 133 | }, 134 | A: function (dateObj, i18n) { 135 | return dateObj.getHours() < 12 136 | ? i18n.amPm[0].toUpperCase() 137 | : i18n.amPm[1].toUpperCase(); 138 | }, 139 | ZZ: function (dateObj) { 140 | var offset = dateObj.getTimezoneOffset(); 141 | return ((offset > 0 ? "-" : "+") + 142 | pad(Math.floor(Math.abs(offset) / 60) * 100 + (Math.abs(offset) % 60), 4)); 143 | }, 144 | Z: function (dateObj) { 145 | var offset = dateObj.getTimezoneOffset(); 146 | return ((offset > 0 ? "-" : "+") + 147 | pad(Math.floor(Math.abs(offset) / 60), 2) + 148 | ":" + 149 | pad(Math.abs(offset) % 60, 2)); 150 | } 151 | }; 152 | var monthParse = function (v) { return +v - 1; }; 153 | var emptyDigits = [null, twoDigitsOptional]; 154 | var emptyWord = [null, word]; 155 | var amPm = [ 156 | "isPm", 157 | word, 158 | function (v, i18n) { 159 | var val = v.toLowerCase(); 160 | if (val === i18n.amPm[0]) { 161 | return 0; 162 | } 163 | else if (val === i18n.amPm[1]) { 164 | return 1; 165 | } 166 | return null; 167 | } 168 | ]; 169 | var timezoneOffset = [ 170 | "timezoneOffset", 171 | "[^\\s]*?[\\+\\-]\\d\\d:?\\d\\d|[^\\s]*?Z?", 172 | function (v) { 173 | var parts = (v + "").match(/([+-]|\d\d)/gi); 174 | if (parts) { 175 | var minutes = +parts[1] * 60 + parseInt(parts[2], 10); 176 | return parts[0] === "+" ? minutes : -minutes; 177 | } 178 | return 0; 179 | } 180 | ]; 181 | var parseFlags = { 182 | D: ["day", twoDigitsOptional], 183 | DD: ["day", twoDigits], 184 | Do: ["day", twoDigitsOptional + word, function (v) { return parseInt(v, 10); }], 185 | M: ["month", twoDigitsOptional, monthParse], 186 | MM: ["month", twoDigits, monthParse], 187 | YY: [ 188 | "year", 189 | twoDigits, 190 | function (v) { 191 | var now = new Date(); 192 | var cent = +("" + now.getFullYear()).substr(0, 2); 193 | return +("" + (+v > 68 ? cent - 1 : cent) + v); 194 | } 195 | ], 196 | h: ["hour", twoDigitsOptional, undefined, "isPm"], 197 | hh: ["hour", twoDigits, undefined, "isPm"], 198 | H: ["hour", twoDigitsOptional], 199 | HH: ["hour", twoDigits], 200 | m: ["minute", twoDigitsOptional], 201 | mm: ["minute", twoDigits], 202 | s: ["second", twoDigitsOptional], 203 | ss: ["second", twoDigits], 204 | YYYY: ["year", fourDigits], 205 | S: ["millisecond", "\\d", function (v) { return +v * 100; }], 206 | SS: ["millisecond", twoDigits, function (v) { return +v * 10; }], 207 | SSS: ["millisecond", threeDigits], 208 | d: emptyDigits, 209 | dd: emptyDigits, 210 | ddd: emptyWord, 211 | dddd: emptyWord, 212 | MMM: ["month", word, monthUpdate("monthNamesShort")], 213 | MMMM: ["month", word, monthUpdate("monthNames")], 214 | a: amPm, 215 | A: amPm, 216 | ZZ: timezoneOffset, 217 | Z: timezoneOffset 218 | }; 219 | // Some common format strings 220 | var globalMasks = { 221 | default: "ddd MMM DD YYYY HH:mm:ss", 222 | shortDate: "M/D/YY", 223 | mediumDate: "MMM D, YYYY", 224 | longDate: "MMMM D, YYYY", 225 | fullDate: "dddd, MMMM D, YYYY", 226 | isoDate: "YYYY-MM-DD", 227 | isoDateTime: "YYYY-MM-DDTHH:mm:ssZ", 228 | shortTime: "HH:mm", 229 | mediumTime: "HH:mm:ss", 230 | longTime: "HH:mm:ss.SSS" 231 | }; 232 | var setGlobalDateMasks = function (masks) { return assign(globalMasks, masks); }; 233 | /*** 234 | * Format a date 235 | * @method format 236 | * @param {Date|number} dateObj 237 | * @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate' 238 | * @returns {string} Formatted date string 239 | */ 240 | var format = function (dateObj, mask, i18n) { 241 | if (mask === void 0) { mask = globalMasks["default"]; } 242 | if (i18n === void 0) { i18n = {}; } 243 | if (typeof dateObj === "number") { 244 | dateObj = new Date(dateObj); 245 | } 246 | if (Object.prototype.toString.call(dateObj) !== "[object Date]" || 247 | isNaN(dateObj.getTime())) { 248 | throw new Error("Invalid Date pass to format"); 249 | } 250 | mask = globalMasks[mask] || mask; 251 | var literals = []; 252 | // Make literals inactive by replacing them with @@@ 253 | mask = mask.replace(literal, function ($0, $1) { 254 | literals.push($1); 255 | return "@@@"; 256 | }); 257 | var combinedI18nSettings = assign(assign({}, globalI18n), i18n); 258 | // Apply formatting rules 259 | mask = mask.replace(token, function ($0) { 260 | return formatFlags[$0](dateObj, combinedI18nSettings); 261 | }); 262 | // Inline literal values back into the formatted value 263 | return mask.replace(/@@@/g, function () { return literals.shift(); }); 264 | }; 265 | /** 266 | * Parse a date string into a Javascript Date object / 267 | * @method parse 268 | * @param {string} dateStr Date string 269 | * @param {string} format Date parse format 270 | * @param {i18n} I18nSettingsOptional Full or subset of I18N settings 271 | * @returns {Date|null} Returns Date object. Returns null what date string is invalid or doesn't match format 272 | */ 273 | function parse(dateStr, format, i18n) { 274 | if (i18n === void 0) { i18n = {}; } 275 | if (typeof format !== "string") { 276 | throw new Error("Invalid format in fecha parse"); 277 | } 278 | // Check to see if the format is actually a mask 279 | format = globalMasks[format] || format; 280 | // Avoid regular expression denial of service, fail early for really long strings 281 | // https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS 282 | if (dateStr.length > 1000) { 283 | return null; 284 | } 285 | // Default to the beginning of the year. 286 | var today = new Date(); 287 | var dateInfo = { 288 | year: today.getFullYear(), 289 | month: 0, 290 | day: 1, 291 | hour: 0, 292 | minute: 0, 293 | second: 0, 294 | millisecond: 0, 295 | isPm: null, 296 | timezoneOffset: null 297 | }; 298 | var parseInfo = []; 299 | var literals = []; 300 | // Replace all the literals with @@@. Hopefully a string that won't exist in the format 301 | var newFormat = format.replace(literal, function ($0, $1) { 302 | literals.push(regexEscape($1)); 303 | return "@@@"; 304 | }); 305 | var specifiedFields = {}; 306 | var requiredFields = {}; 307 | // Change every token that we find into the correct regex 308 | newFormat = regexEscape(newFormat).replace(token, function ($0) { 309 | var info = parseFlags[$0]; 310 | var field = info[0], regex = info[1], requiredField = info[3]; 311 | // Check if the person has specified the same field twice. This will lead to confusing results. 312 | if (specifiedFields[field]) { 313 | throw new Error("Invalid format. " + field + " specified twice in format"); 314 | } 315 | specifiedFields[field] = true; 316 | // Check if there are any required fields. For instance, 12 hour time requires AM/PM specified 317 | if (requiredField) { 318 | requiredFields[requiredField] = true; 319 | } 320 | parseInfo.push(info); 321 | return "(" + regex + ")"; 322 | }); 323 | // Check all the required fields are present 324 | Object.keys(requiredFields).forEach(function (field) { 325 | if (!specifiedFields[field]) { 326 | throw new Error("Invalid format. " + field + " is required in specified format"); 327 | } 328 | }); 329 | // Add back all the literals after 330 | newFormat = newFormat.replace(/@@@/g, function () { return literals.shift(); }); 331 | // Check if the date string matches the format. If it doesn't return null 332 | var matches = dateStr.match(new RegExp(newFormat, "i")); 333 | if (!matches) { 334 | return null; 335 | } 336 | var combinedI18nSettings = assign(assign({}, globalI18n), i18n); 337 | // For each match, call the parser function for that date part 338 | for (var i = 1; i < matches.length; i++) { 339 | var _a = parseInfo[i - 1], field = _a[0], parser = _a[2]; 340 | var value = parser 341 | ? parser(matches[i], combinedI18nSettings) 342 | : +matches[i]; 343 | // If the parser can't make sense of the value, return null 344 | if (value == null) { 345 | return null; 346 | } 347 | dateInfo[field] = value; 348 | } 349 | if (dateInfo.isPm === 1 && dateInfo.hour != null && +dateInfo.hour !== 12) { 350 | dateInfo.hour = +dateInfo.hour + 12; 351 | } 352 | else if (dateInfo.isPm === 0 && +dateInfo.hour === 12) { 353 | dateInfo.hour = 0; 354 | } 355 | var dateTZ; 356 | if (dateInfo.timezoneOffset == null) { 357 | dateTZ = new Date(dateInfo.year, dateInfo.month, dateInfo.day, dateInfo.hour, dateInfo.minute, dateInfo.second, dateInfo.millisecond); 358 | var validateFields = [ 359 | ["month", "getMonth"], 360 | ["day", "getDate"], 361 | ["hour", "getHours"], 362 | ["minute", "getMinutes"], 363 | ["second", "getSeconds"] 364 | ]; 365 | for (var i = 0, len = validateFields.length; i < len; i++) { 366 | // Check to make sure the date field is within the allowed range. Javascript dates allows values 367 | // outside the allowed range. If the values don't match the value was invalid 368 | if (specifiedFields[validateFields[i][0]] && 369 | dateInfo[validateFields[i][0]] !== dateTZ[validateFields[i][1]]()) { 370 | return null; 371 | } 372 | } 373 | } 374 | else { 375 | dateTZ = new Date(Date.UTC(dateInfo.year, dateInfo.month, dateInfo.day, dateInfo.hour, dateInfo.minute - dateInfo.timezoneOffset, dateInfo.second, dateInfo.millisecond)); 376 | // We can't validate dates in another timezone unfortunately. Do a basic check instead 377 | if (dateInfo.month > 11 || 378 | dateInfo.month < 0 || 379 | dateInfo.day > 31 || 380 | dateInfo.day < 1 || 381 | dateInfo.hour > 23 || 382 | dateInfo.hour < 0 || 383 | dateInfo.minute > 59 || 384 | dateInfo.minute < 0 || 385 | dateInfo.second > 59 || 386 | dateInfo.second < 0) { 387 | return null; 388 | } 389 | } 390 | // Don't allow invalid dates 391 | return dateTZ; 392 | } 393 | var fecha = { 394 | format: format, 395 | parse: parse, 396 | defaultI18n: defaultI18n, 397 | setGlobalDateI18n: setGlobalDateI18n, 398 | setGlobalDateMasks: setGlobalDateMasks 399 | }; 400 | 401 | export default fecha; 402 | export { assign, format, parse, defaultI18n, setGlobalDateI18n, setGlobalDateMasks }; 403 | //# sourceMappingURL=fecha.js.map 404 | -------------------------------------------------------------------------------- /lib/fecha.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"fecha.js","sources":["../src/fecha.ts"],"sourcesContent":["const token = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|Z|([HhMsDm])\\1?|[aA]|\"[^\"]*\"|'[^']*'/g;\nconst twoDigitsOptional = \"\\\\d\\\\d?\";\nconst twoDigits = \"\\\\d\\\\d\";\nconst threeDigits = \"\\\\d{3}\";\nconst fourDigits = \"\\\\d{4}\";\nconst word = \"[^\\\\s]+\";\nconst literal = /\\[([^]*?)\\]/gm;\n\ntype DateInfo = {\n year: number;\n month: number;\n day: number;\n hour: number;\n minute: number;\n second: number;\n millisecond: number;\n isPm: number | null;\n timezoneOffset: number | null;\n};\n\nexport type I18nSettings = {\n amPm: [string, string];\n dayNames: Days;\n dayNamesShort: Days;\n monthNames: Months;\n monthNamesShort: Months;\n DoFn(dayOfMonth: number): string;\n};\n\nexport type I18nSettingsOptional = Partial;\n\nexport type Days = [string, string, string, string, string, string, string];\nexport type Months = [\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string\n];\n\nfunction shorten(arr: T, sLen: number): string[] {\n const newArr: string[] = [];\n for (let i = 0, len = arr.length; i < len; i++) {\n newArr.push(arr[i].substr(0, sLen));\n }\n return newArr;\n}\n\nconst monthUpdate = (\n arrName: \"monthNames\" | \"monthNamesShort\" | \"dayNames\" | \"dayNamesShort\"\n) => (v: string, i18n: I18nSettings): number | null => {\n const lowerCaseArr = i18n[arrName].map(v => v.toLowerCase());\n const index = lowerCaseArr.indexOf(v.toLowerCase());\n if (index > -1) {\n return index;\n }\n return null;\n};\n\nexport function assign(a: A): A;\nexport function assign(a: A, b: B): A & B;\nexport function assign(a: A, b: B, c: C): A & B & C;\nexport function assign(a: A, b: B, c: C, d: D): A & B & C & D;\nexport function assign(origObj: any, ...args: any[]): any {\n for (const obj of args) {\n for (const key in obj) {\n // @ts-ignore ex\n origObj[key] = obj[key];\n }\n }\n return origObj;\n}\n\nconst dayNames: Days = [\n \"Sunday\",\n \"Monday\",\n \"Tuesday\",\n \"Wednesday\",\n \"Thursday\",\n \"Friday\",\n \"Saturday\"\n];\nconst monthNames: Months = [\n \"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\"\n];\n\nconst monthNamesShort: Months = shorten(monthNames, 3) as Months;\nconst dayNamesShort: Days = shorten(dayNames, 3) as Days;\n\nconst defaultI18n: I18nSettings = {\n dayNamesShort,\n dayNames,\n monthNamesShort,\n monthNames,\n amPm: [\"am\", \"pm\"],\n DoFn(dayOfMonth: number) {\n return (\n dayOfMonth +\n [\"th\", \"st\", \"nd\", \"rd\"][\n dayOfMonth % 10 > 3\n ? 0\n : ((dayOfMonth - (dayOfMonth % 10) !== 10 ? 1 : 0) * dayOfMonth) % 10\n ]\n );\n }\n};\nlet globalI18n = assign({}, defaultI18n);\nconst setGlobalDateI18n = (i18n: I18nSettingsOptional): I18nSettings =>\n (globalI18n = assign(globalI18n, i18n));\n\nconst regexEscape = (str: string): string =>\n str.replace(/[|\\\\{()[^$+*?.-]/g, \"\\\\$&\");\n\nconst pad = (val: string | number, len = 2): string => {\n val = String(val);\n while (val.length < len) {\n val = \"0\" + val;\n }\n return val;\n};\n\nconst formatFlags: Record<\n string,\n (dateObj: Date, i18n: I18nSettings) => string\n> = {\n D: (dateObj: Date): string => String(dateObj.getDate()),\n DD: (dateObj: Date): string => pad(dateObj.getDate()),\n Do: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.DoFn(dateObj.getDate()),\n d: (dateObj: Date): string => String(dateObj.getDay()),\n dd: (dateObj: Date): string => pad(dateObj.getDay()),\n ddd: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.dayNamesShort[dateObj.getDay()],\n dddd: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.dayNames[dateObj.getDay()],\n M: (dateObj: Date): string => String(dateObj.getMonth() + 1),\n MM: (dateObj: Date): string => pad(dateObj.getMonth() + 1),\n MMM: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.monthNamesShort[dateObj.getMonth()],\n MMMM: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.monthNames[dateObj.getMonth()],\n YY: (dateObj: Date): string =>\n pad(String(dateObj.getFullYear()), 4).substr(2),\n YYYY: (dateObj: Date): string => pad(dateObj.getFullYear(), 4),\n h: (dateObj: Date): string => String(dateObj.getHours() % 12 || 12),\n hh: (dateObj: Date): string => pad(dateObj.getHours() % 12 || 12),\n H: (dateObj: Date): string => String(dateObj.getHours()),\n HH: (dateObj: Date): string => pad(dateObj.getHours()),\n m: (dateObj: Date): string => String(dateObj.getMinutes()),\n mm: (dateObj: Date): string => pad(dateObj.getMinutes()),\n s: (dateObj: Date): string => String(dateObj.getSeconds()),\n ss: (dateObj: Date): string => pad(dateObj.getSeconds()),\n S: (dateObj: Date): string =>\n String(Math.round(dateObj.getMilliseconds() / 100)),\n SS: (dateObj: Date): string =>\n pad(Math.round(dateObj.getMilliseconds() / 10), 2),\n SSS: (dateObj: Date): string => pad(dateObj.getMilliseconds(), 3),\n a: (dateObj: Date, i18n: I18nSettings): string =>\n dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1],\n A: (dateObj: Date, i18n: I18nSettings): string =>\n dateObj.getHours() < 12\n ? i18n.amPm[0].toUpperCase()\n : i18n.amPm[1].toUpperCase(),\n ZZ(dateObj: Date): string {\n const offset = dateObj.getTimezoneOffset();\n return (\n (offset > 0 ? \"-\" : \"+\") +\n pad(Math.floor(Math.abs(offset) / 60) * 100 + (Math.abs(offset) % 60), 4)\n );\n },\n Z(dateObj: Date): string {\n const offset = dateObj.getTimezoneOffset();\n return (\n (offset > 0 ? \"-\" : \"+\") +\n pad(Math.floor(Math.abs(offset) / 60), 2) +\n \":\" +\n pad(Math.abs(offset) % 60, 2)\n );\n }\n};\n\ntype ParseInfo = [\n keyof DateInfo,\n string,\n ((v: string, i18n: I18nSettings) => number | null)?,\n string?\n];\nconst monthParse = (v: string): number => +v - 1;\nconst emptyDigits: ParseInfo = [null, twoDigitsOptional];\nconst emptyWord: ParseInfo = [null, word];\nconst amPm: ParseInfo = [\n \"isPm\",\n word,\n (v: string, i18n: I18nSettings): number | null => {\n const val = v.toLowerCase();\n if (val === i18n.amPm[0]) {\n return 0;\n } else if (val === i18n.amPm[1]) {\n return 1;\n }\n return null;\n }\n];\nconst timezoneOffset: ParseInfo = [\n \"timezoneOffset\",\n \"[^\\\\s]*?[\\\\+\\\\-]\\\\d\\\\d:?\\\\d\\\\d|[^\\\\s]*?Z?\",\n (v: string): number | null => {\n const parts = (v + \"\").match(/([+-]|\\d\\d)/gi);\n\n if (parts) {\n const minutes = +parts[1] * 60 + parseInt(parts[2], 10);\n return parts[0] === \"+\" ? minutes : -minutes;\n }\n\n return 0;\n }\n];\nconst parseFlags: Record = {\n D: [\"day\", twoDigitsOptional],\n DD: [\"day\", twoDigits],\n Do: [\"day\", twoDigitsOptional + word, (v: string): number => parseInt(v, 10)],\n M: [\"month\", twoDigitsOptional, monthParse],\n MM: [\"month\", twoDigits, monthParse],\n YY: [\n \"year\",\n twoDigits,\n (v: string): number => {\n const now = new Date();\n const cent = +(\"\" + now.getFullYear()).substr(0, 2);\n return +(\"\" + (+v > 68 ? cent - 1 : cent) + v);\n }\n ],\n h: [\"hour\", twoDigitsOptional, undefined, \"isPm\"],\n hh: [\"hour\", twoDigits, undefined, \"isPm\"],\n H: [\"hour\", twoDigitsOptional],\n HH: [\"hour\", twoDigits],\n m: [\"minute\", twoDigitsOptional],\n mm: [\"minute\", twoDigits],\n s: [\"second\", twoDigitsOptional],\n ss: [\"second\", twoDigits],\n YYYY: [\"year\", fourDigits],\n S: [\"millisecond\", \"\\\\d\", (v: string): number => +v * 100],\n SS: [\"millisecond\", twoDigits, (v: string): number => +v * 10],\n SSS: [\"millisecond\", threeDigits],\n d: emptyDigits,\n dd: emptyDigits,\n ddd: emptyWord,\n dddd: emptyWord,\n MMM: [\"month\", word, monthUpdate(\"monthNamesShort\")],\n MMMM: [\"month\", word, monthUpdate(\"monthNames\")],\n a: amPm,\n A: amPm,\n ZZ: timezoneOffset,\n Z: timezoneOffset\n};\n\n// Some common format strings\nconst globalMasks: { [key: string]: string } = {\n default: \"ddd MMM DD YYYY HH:mm:ss\",\n shortDate: \"M/D/YY\",\n mediumDate: \"MMM D, YYYY\",\n longDate: \"MMMM D, YYYY\",\n fullDate: \"dddd, MMMM D, YYYY\",\n isoDate: \"YYYY-MM-DD\",\n isoDateTime: \"YYYY-MM-DDTHH:mm:ssZ\",\n shortTime: \"HH:mm\",\n mediumTime: \"HH:mm:ss\",\n longTime: \"HH:mm:ss.SSS\"\n};\nconst setGlobalDateMasks = (masks: {\n [key: string]: string;\n}): { [key: string]: string } => assign(globalMasks, masks);\n\n/***\n * Format a date\n * @method format\n * @param {Date|number} dateObj\n * @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate'\n * @returns {string} Formatted date string\n */\nconst format = (\n dateObj: Date,\n mask: string = globalMasks[\"default\"],\n i18n: I18nSettingsOptional = {}\n): string => {\n if (typeof dateObj === \"number\") {\n dateObj = new Date(dateObj);\n }\n\n if (\n Object.prototype.toString.call(dateObj) !== \"[object Date]\" ||\n isNaN(dateObj.getTime())\n ) {\n throw new Error(\"Invalid Date pass to format\");\n }\n\n mask = globalMasks[mask] || mask;\n\n const literals: string[] = [];\n\n // Make literals inactive by replacing them with @@@\n mask = mask.replace(literal, function($0, $1) {\n literals.push($1);\n return \"@@@\";\n });\n\n const combinedI18nSettings: I18nSettings = assign(\n assign({}, globalI18n),\n i18n\n );\n // Apply formatting rules\n mask = mask.replace(token, $0 =>\n formatFlags[$0](dateObj, combinedI18nSettings)\n );\n // Inline literal values back into the formatted value\n return mask.replace(/@@@/g, () => literals.shift());\n};\n\n/**\n * Parse a date string into a Javascript Date object /\n * @method parse\n * @param {string} dateStr Date string\n * @param {string} format Date parse format\n * @param {i18n} I18nSettingsOptional Full or subset of I18N settings\n * @returns {Date|null} Returns Date object. Returns null what date string is invalid or doesn't match format\n */\nfunction parse(\n dateStr: string,\n format: string,\n i18n: I18nSettingsOptional = {}\n): Date | null {\n if (typeof format !== \"string\") {\n throw new Error(\"Invalid format in fecha parse\");\n }\n\n // Check to see if the format is actually a mask\n format = globalMasks[format] || format;\n\n // Avoid regular expression denial of service, fail early for really long strings\n // https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS\n if (dateStr.length > 1000) {\n return null;\n }\n\n // Default to the beginning of the year.\n const today = new Date();\n const dateInfo: DateInfo = {\n year: today.getFullYear(),\n month: 0,\n day: 1,\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0,\n isPm: null,\n timezoneOffset: null\n };\n const parseInfo: ParseInfo[] = [];\n const literals: string[] = [];\n\n // Replace all the literals with @@@. Hopefully a string that won't exist in the format\n let newFormat = format.replace(literal, ($0, $1) => {\n literals.push(regexEscape($1));\n return \"@@@\";\n });\n const specifiedFields: { [field: string]: boolean } = {};\n const requiredFields: { [field: string]: boolean } = {};\n\n // Change every token that we find into the correct regex\n newFormat = regexEscape(newFormat).replace(token, $0 => {\n const info = parseFlags[$0];\n const [field, regex, , requiredField] = info;\n\n // Check if the person has specified the same field twice. This will lead to confusing results.\n if (specifiedFields[field]) {\n throw new Error(`Invalid format. ${field} specified twice in format`);\n }\n\n specifiedFields[field] = true;\n\n // Check if there are any required fields. For instance, 12 hour time requires AM/PM specified\n if (requiredField) {\n requiredFields[requiredField] = true;\n }\n\n parseInfo.push(info);\n return \"(\" + regex + \")\";\n });\n\n // Check all the required fields are present\n Object.keys(requiredFields).forEach(field => {\n if (!specifiedFields[field]) {\n throw new Error(\n `Invalid format. ${field} is required in specified format`\n );\n }\n });\n\n // Add back all the literals after\n newFormat = newFormat.replace(/@@@/g, () => literals.shift());\n\n // Check if the date string matches the format. If it doesn't return null\n const matches = dateStr.match(new RegExp(newFormat, \"i\"));\n if (!matches) {\n return null;\n }\n\n const combinedI18nSettings: I18nSettings = assign(\n assign({}, globalI18n),\n i18n\n );\n\n // For each match, call the parser function for that date part\n for (let i = 1; i < matches.length; i++) {\n const [field, , parser] = parseInfo[i - 1];\n const value = parser\n ? parser(matches[i], combinedI18nSettings)\n : +matches[i];\n\n // If the parser can't make sense of the value, return null\n if (value == null) {\n return null;\n }\n\n dateInfo[field] = value;\n }\n\n if (dateInfo.isPm === 1 && dateInfo.hour != null && +dateInfo.hour !== 12) {\n dateInfo.hour = +dateInfo.hour + 12;\n } else if (dateInfo.isPm === 0 && +dateInfo.hour === 12) {\n dateInfo.hour = 0;\n }\n\n let dateTZ: Date;\n if (dateInfo.timezoneOffset == null) {\n dateTZ = new Date(\n dateInfo.year,\n dateInfo.month,\n dateInfo.day,\n dateInfo.hour,\n dateInfo.minute,\n dateInfo.second,\n dateInfo.millisecond\n );\n const validateFields: [\n \"month\" | \"day\" | \"hour\" | \"minute\" | \"second\",\n \"getMonth\" | \"getDate\" | \"getHours\" | \"getMinutes\" | \"getSeconds\"\n ][] = [\n [\"month\", \"getMonth\"],\n [\"day\", \"getDate\"],\n [\"hour\", \"getHours\"],\n [\"minute\", \"getMinutes\"],\n [\"second\", \"getSeconds\"]\n ];\n for (let i = 0, len = validateFields.length; i < len; i++) {\n // Check to make sure the date field is within the allowed range. Javascript dates allows values\n // outside the allowed range. If the values don't match the value was invalid\n if (\n specifiedFields[validateFields[i][0]] &&\n dateInfo[validateFields[i][0]] !== dateTZ[validateFields[i][1]]()\n ) {\n return null;\n }\n }\n } else {\n dateTZ = new Date(\n Date.UTC(\n dateInfo.year,\n dateInfo.month,\n dateInfo.day,\n dateInfo.hour,\n dateInfo.minute - dateInfo.timezoneOffset,\n dateInfo.second,\n dateInfo.millisecond\n )\n );\n\n // We can't validate dates in another timezone unfortunately. Do a basic check instead\n if (\n dateInfo.month > 11 ||\n dateInfo.month < 0 ||\n dateInfo.day > 31 ||\n dateInfo.day < 1 ||\n dateInfo.hour > 23 ||\n dateInfo.hour < 0 ||\n dateInfo.minute > 59 ||\n dateInfo.minute < 0 ||\n dateInfo.second > 59 ||\n dateInfo.second < 0\n ) {\n return null;\n }\n }\n\n // Don't allow invalid dates\n\n return dateTZ;\n}\nexport default {\n format,\n parse,\n defaultI18n,\n setGlobalDateI18n,\n setGlobalDateMasks\n};\nexport { format, parse, defaultI18n, setGlobalDateI18n, setGlobalDateMasks };\n"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /lib/fecha.umd.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : 3 | typeof define === 'function' && define.amd ? define(['exports'], factory) : 4 | (factory((global.fecha = {}))); 5 | }(this, (function (exports) { 'use strict'; 6 | 7 | var token = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|Z|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g; 8 | var twoDigitsOptional = "\\d\\d?"; 9 | var twoDigits = "\\d\\d"; 10 | var threeDigits = "\\d{3}"; 11 | var fourDigits = "\\d{4}"; 12 | var word = "[^\\s]+"; 13 | var literal = /\[([^]*?)\]/gm; 14 | function shorten(arr, sLen) { 15 | var newArr = []; 16 | for (var i = 0, len = arr.length; i < len; i++) { 17 | newArr.push(arr[i].substr(0, sLen)); 18 | } 19 | return newArr; 20 | } 21 | var monthUpdate = function (arrName) { return function (v, i18n) { 22 | var lowerCaseArr = i18n[arrName].map(function (v) { return v.toLowerCase(); }); 23 | var index = lowerCaseArr.indexOf(v.toLowerCase()); 24 | if (index > -1) { 25 | return index; 26 | } 27 | return null; 28 | }; }; 29 | function assign(origObj) { 30 | var args = []; 31 | for (var _i = 1; _i < arguments.length; _i++) { 32 | args[_i - 1] = arguments[_i]; 33 | } 34 | for (var _a = 0, args_1 = args; _a < args_1.length; _a++) { 35 | var obj = args_1[_a]; 36 | for (var key in obj) { 37 | // @ts-ignore ex 38 | origObj[key] = obj[key]; 39 | } 40 | } 41 | return origObj; 42 | } 43 | var dayNames = [ 44 | "Sunday", 45 | "Monday", 46 | "Tuesday", 47 | "Wednesday", 48 | "Thursday", 49 | "Friday", 50 | "Saturday" 51 | ]; 52 | var monthNames = [ 53 | "January", 54 | "February", 55 | "March", 56 | "April", 57 | "May", 58 | "June", 59 | "July", 60 | "August", 61 | "September", 62 | "October", 63 | "November", 64 | "December" 65 | ]; 66 | var monthNamesShort = shorten(monthNames, 3); 67 | var dayNamesShort = shorten(dayNames, 3); 68 | var defaultI18n = { 69 | dayNamesShort: dayNamesShort, 70 | dayNames: dayNames, 71 | monthNamesShort: monthNamesShort, 72 | monthNames: monthNames, 73 | amPm: ["am", "pm"], 74 | DoFn: function (dayOfMonth) { 75 | return (dayOfMonth + 76 | ["th", "st", "nd", "rd"][dayOfMonth % 10 > 3 77 | ? 0 78 | : ((dayOfMonth - (dayOfMonth % 10) !== 10 ? 1 : 0) * dayOfMonth) % 10]); 79 | } 80 | }; 81 | var globalI18n = assign({}, defaultI18n); 82 | var setGlobalDateI18n = function (i18n) { 83 | return (globalI18n = assign(globalI18n, i18n)); 84 | }; 85 | var regexEscape = function (str) { 86 | return str.replace(/[|\\{()[^$+*?.-]/g, "\\$&"); 87 | }; 88 | var pad = function (val, len) { 89 | if (len === void 0) { len = 2; } 90 | val = String(val); 91 | while (val.length < len) { 92 | val = "0" + val; 93 | } 94 | return val; 95 | }; 96 | var formatFlags = { 97 | D: function (dateObj) { return String(dateObj.getDate()); }, 98 | DD: function (dateObj) { return pad(dateObj.getDate()); }, 99 | Do: function (dateObj, i18n) { 100 | return i18n.DoFn(dateObj.getDate()); 101 | }, 102 | d: function (dateObj) { return String(dateObj.getDay()); }, 103 | dd: function (dateObj) { return pad(dateObj.getDay()); }, 104 | ddd: function (dateObj, i18n) { 105 | return i18n.dayNamesShort[dateObj.getDay()]; 106 | }, 107 | dddd: function (dateObj, i18n) { 108 | return i18n.dayNames[dateObj.getDay()]; 109 | }, 110 | M: function (dateObj) { return String(dateObj.getMonth() + 1); }, 111 | MM: function (dateObj) { return pad(dateObj.getMonth() + 1); }, 112 | MMM: function (dateObj, i18n) { 113 | return i18n.monthNamesShort[dateObj.getMonth()]; 114 | }, 115 | MMMM: function (dateObj, i18n) { 116 | return i18n.monthNames[dateObj.getMonth()]; 117 | }, 118 | YY: function (dateObj) { 119 | return pad(String(dateObj.getFullYear()), 4).substr(2); 120 | }, 121 | YYYY: function (dateObj) { return pad(dateObj.getFullYear(), 4); }, 122 | h: function (dateObj) { return String(dateObj.getHours() % 12 || 12); }, 123 | hh: function (dateObj) { return pad(dateObj.getHours() % 12 || 12); }, 124 | H: function (dateObj) { return String(dateObj.getHours()); }, 125 | HH: function (dateObj) { return pad(dateObj.getHours()); }, 126 | m: function (dateObj) { return String(dateObj.getMinutes()); }, 127 | mm: function (dateObj) { return pad(dateObj.getMinutes()); }, 128 | s: function (dateObj) { return String(dateObj.getSeconds()); }, 129 | ss: function (dateObj) { return pad(dateObj.getSeconds()); }, 130 | S: function (dateObj) { 131 | return String(Math.round(dateObj.getMilliseconds() / 100)); 132 | }, 133 | SS: function (dateObj) { 134 | return pad(Math.round(dateObj.getMilliseconds() / 10), 2); 135 | }, 136 | SSS: function (dateObj) { return pad(dateObj.getMilliseconds(), 3); }, 137 | a: function (dateObj, i18n) { 138 | return dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1]; 139 | }, 140 | A: function (dateObj, i18n) { 141 | return dateObj.getHours() < 12 142 | ? i18n.amPm[0].toUpperCase() 143 | : i18n.amPm[1].toUpperCase(); 144 | }, 145 | ZZ: function (dateObj) { 146 | var offset = dateObj.getTimezoneOffset(); 147 | return ((offset > 0 ? "-" : "+") + 148 | pad(Math.floor(Math.abs(offset) / 60) * 100 + (Math.abs(offset) % 60), 4)); 149 | }, 150 | Z: function (dateObj) { 151 | var offset = dateObj.getTimezoneOffset(); 152 | return ((offset > 0 ? "-" : "+") + 153 | pad(Math.floor(Math.abs(offset) / 60), 2) + 154 | ":" + 155 | pad(Math.abs(offset) % 60, 2)); 156 | } 157 | }; 158 | var monthParse = function (v) { return +v - 1; }; 159 | var emptyDigits = [null, twoDigitsOptional]; 160 | var emptyWord = [null, word]; 161 | var amPm = [ 162 | "isPm", 163 | word, 164 | function (v, i18n) { 165 | var val = v.toLowerCase(); 166 | if (val === i18n.amPm[0]) { 167 | return 0; 168 | } 169 | else if (val === i18n.amPm[1]) { 170 | return 1; 171 | } 172 | return null; 173 | } 174 | ]; 175 | var timezoneOffset = [ 176 | "timezoneOffset", 177 | "[^\\s]*?[\\+\\-]\\d\\d:?\\d\\d|[^\\s]*?Z?", 178 | function (v) { 179 | var parts = (v + "").match(/([+-]|\d\d)/gi); 180 | if (parts) { 181 | var minutes = +parts[1] * 60 + parseInt(parts[2], 10); 182 | return parts[0] === "+" ? minutes : -minutes; 183 | } 184 | return 0; 185 | } 186 | ]; 187 | var parseFlags = { 188 | D: ["day", twoDigitsOptional], 189 | DD: ["day", twoDigits], 190 | Do: ["day", twoDigitsOptional + word, function (v) { return parseInt(v, 10); }], 191 | M: ["month", twoDigitsOptional, monthParse], 192 | MM: ["month", twoDigits, monthParse], 193 | YY: [ 194 | "year", 195 | twoDigits, 196 | function (v) { 197 | var now = new Date(); 198 | var cent = +("" + now.getFullYear()).substr(0, 2); 199 | return +("" + (+v > 68 ? cent - 1 : cent) + v); 200 | } 201 | ], 202 | h: ["hour", twoDigitsOptional, undefined, "isPm"], 203 | hh: ["hour", twoDigits, undefined, "isPm"], 204 | H: ["hour", twoDigitsOptional], 205 | HH: ["hour", twoDigits], 206 | m: ["minute", twoDigitsOptional], 207 | mm: ["minute", twoDigits], 208 | s: ["second", twoDigitsOptional], 209 | ss: ["second", twoDigits], 210 | YYYY: ["year", fourDigits], 211 | S: ["millisecond", "\\d", function (v) { return +v * 100; }], 212 | SS: ["millisecond", twoDigits, function (v) { return +v * 10; }], 213 | SSS: ["millisecond", threeDigits], 214 | d: emptyDigits, 215 | dd: emptyDigits, 216 | ddd: emptyWord, 217 | dddd: emptyWord, 218 | MMM: ["month", word, monthUpdate("monthNamesShort")], 219 | MMMM: ["month", word, monthUpdate("monthNames")], 220 | a: amPm, 221 | A: amPm, 222 | ZZ: timezoneOffset, 223 | Z: timezoneOffset 224 | }; 225 | // Some common format strings 226 | var globalMasks = { 227 | default: "ddd MMM DD YYYY HH:mm:ss", 228 | shortDate: "M/D/YY", 229 | mediumDate: "MMM D, YYYY", 230 | longDate: "MMMM D, YYYY", 231 | fullDate: "dddd, MMMM D, YYYY", 232 | isoDate: "YYYY-MM-DD", 233 | isoDateTime: "YYYY-MM-DDTHH:mm:ssZ", 234 | shortTime: "HH:mm", 235 | mediumTime: "HH:mm:ss", 236 | longTime: "HH:mm:ss.SSS" 237 | }; 238 | var setGlobalDateMasks = function (masks) { return assign(globalMasks, masks); }; 239 | /*** 240 | * Format a date 241 | * @method format 242 | * @param {Date|number} dateObj 243 | * @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate' 244 | * @returns {string} Formatted date string 245 | */ 246 | var format = function (dateObj, mask, i18n) { 247 | if (mask === void 0) { mask = globalMasks["default"]; } 248 | if (i18n === void 0) { i18n = {}; } 249 | if (typeof dateObj === "number") { 250 | dateObj = new Date(dateObj); 251 | } 252 | if (Object.prototype.toString.call(dateObj) !== "[object Date]" || 253 | isNaN(dateObj.getTime())) { 254 | throw new Error("Invalid Date pass to format"); 255 | } 256 | mask = globalMasks[mask] || mask; 257 | var literals = []; 258 | // Make literals inactive by replacing them with @@@ 259 | mask = mask.replace(literal, function ($0, $1) { 260 | literals.push($1); 261 | return "@@@"; 262 | }); 263 | var combinedI18nSettings = assign(assign({}, globalI18n), i18n); 264 | // Apply formatting rules 265 | mask = mask.replace(token, function ($0) { 266 | return formatFlags[$0](dateObj, combinedI18nSettings); 267 | }); 268 | // Inline literal values back into the formatted value 269 | return mask.replace(/@@@/g, function () { return literals.shift(); }); 270 | }; 271 | /** 272 | * Parse a date string into a Javascript Date object / 273 | * @method parse 274 | * @param {string} dateStr Date string 275 | * @param {string} format Date parse format 276 | * @param {i18n} I18nSettingsOptional Full or subset of I18N settings 277 | * @returns {Date|null} Returns Date object. Returns null what date string is invalid or doesn't match format 278 | */ 279 | function parse(dateStr, format, i18n) { 280 | if (i18n === void 0) { i18n = {}; } 281 | if (typeof format !== "string") { 282 | throw new Error("Invalid format in fecha parse"); 283 | } 284 | // Check to see if the format is actually a mask 285 | format = globalMasks[format] || format; 286 | // Avoid regular expression denial of service, fail early for really long strings 287 | // https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS 288 | if (dateStr.length > 1000) { 289 | return null; 290 | } 291 | // Default to the beginning of the year. 292 | var today = new Date(); 293 | var dateInfo = { 294 | year: today.getFullYear(), 295 | month: 0, 296 | day: 1, 297 | hour: 0, 298 | minute: 0, 299 | second: 0, 300 | millisecond: 0, 301 | isPm: null, 302 | timezoneOffset: null 303 | }; 304 | var parseInfo = []; 305 | var literals = []; 306 | // Replace all the literals with @@@. Hopefully a string that won't exist in the format 307 | var newFormat = format.replace(literal, function ($0, $1) { 308 | literals.push(regexEscape($1)); 309 | return "@@@"; 310 | }); 311 | var specifiedFields = {}; 312 | var requiredFields = {}; 313 | // Change every token that we find into the correct regex 314 | newFormat = regexEscape(newFormat).replace(token, function ($0) { 315 | var info = parseFlags[$0]; 316 | var field = info[0], regex = info[1], requiredField = info[3]; 317 | // Check if the person has specified the same field twice. This will lead to confusing results. 318 | if (specifiedFields[field]) { 319 | throw new Error("Invalid format. " + field + " specified twice in format"); 320 | } 321 | specifiedFields[field] = true; 322 | // Check if there are any required fields. For instance, 12 hour time requires AM/PM specified 323 | if (requiredField) { 324 | requiredFields[requiredField] = true; 325 | } 326 | parseInfo.push(info); 327 | return "(" + regex + ")"; 328 | }); 329 | // Check all the required fields are present 330 | Object.keys(requiredFields).forEach(function (field) { 331 | if (!specifiedFields[field]) { 332 | throw new Error("Invalid format. " + field + " is required in specified format"); 333 | } 334 | }); 335 | // Add back all the literals after 336 | newFormat = newFormat.replace(/@@@/g, function () { return literals.shift(); }); 337 | // Check if the date string matches the format. If it doesn't return null 338 | var matches = dateStr.match(new RegExp(newFormat, "i")); 339 | if (!matches) { 340 | return null; 341 | } 342 | var combinedI18nSettings = assign(assign({}, globalI18n), i18n); 343 | // For each match, call the parser function for that date part 344 | for (var i = 1; i < matches.length; i++) { 345 | var _a = parseInfo[i - 1], field = _a[0], parser = _a[2]; 346 | var value = parser 347 | ? parser(matches[i], combinedI18nSettings) 348 | : +matches[i]; 349 | // If the parser can't make sense of the value, return null 350 | if (value == null) { 351 | return null; 352 | } 353 | dateInfo[field] = value; 354 | } 355 | if (dateInfo.isPm === 1 && dateInfo.hour != null && +dateInfo.hour !== 12) { 356 | dateInfo.hour = +dateInfo.hour + 12; 357 | } 358 | else if (dateInfo.isPm === 0 && +dateInfo.hour === 12) { 359 | dateInfo.hour = 0; 360 | } 361 | var dateTZ; 362 | if (dateInfo.timezoneOffset == null) { 363 | dateTZ = new Date(dateInfo.year, dateInfo.month, dateInfo.day, dateInfo.hour, dateInfo.minute, dateInfo.second, dateInfo.millisecond); 364 | var validateFields = [ 365 | ["month", "getMonth"], 366 | ["day", "getDate"], 367 | ["hour", "getHours"], 368 | ["minute", "getMinutes"], 369 | ["second", "getSeconds"] 370 | ]; 371 | for (var i = 0, len = validateFields.length; i < len; i++) { 372 | // Check to make sure the date field is within the allowed range. Javascript dates allows values 373 | // outside the allowed range. If the values don't match the value was invalid 374 | if (specifiedFields[validateFields[i][0]] && 375 | dateInfo[validateFields[i][0]] !== dateTZ[validateFields[i][1]]()) { 376 | return null; 377 | } 378 | } 379 | } 380 | else { 381 | dateTZ = new Date(Date.UTC(dateInfo.year, dateInfo.month, dateInfo.day, dateInfo.hour, dateInfo.minute - dateInfo.timezoneOffset, dateInfo.second, dateInfo.millisecond)); 382 | // We can't validate dates in another timezone unfortunately. Do a basic check instead 383 | if (dateInfo.month > 11 || 384 | dateInfo.month < 0 || 385 | dateInfo.day > 31 || 386 | dateInfo.day < 1 || 387 | dateInfo.hour > 23 || 388 | dateInfo.hour < 0 || 389 | dateInfo.minute > 59 || 390 | dateInfo.minute < 0 || 391 | dateInfo.second > 59 || 392 | dateInfo.second < 0) { 393 | return null; 394 | } 395 | } 396 | // Don't allow invalid dates 397 | return dateTZ; 398 | } 399 | var fecha = { 400 | format: format, 401 | parse: parse, 402 | defaultI18n: defaultI18n, 403 | setGlobalDateI18n: setGlobalDateI18n, 404 | setGlobalDateMasks: setGlobalDateMasks 405 | }; 406 | 407 | exports.assign = assign; 408 | exports.default = fecha; 409 | exports.format = format; 410 | exports.parse = parse; 411 | exports.defaultI18n = defaultI18n; 412 | exports.setGlobalDateI18n = setGlobalDateI18n; 413 | exports.setGlobalDateMasks = setGlobalDateMasks; 414 | 415 | Object.defineProperty(exports, '__esModule', { value: true }); 416 | 417 | }))); 418 | //# sourceMappingURL=fecha.umd.js.map 419 | -------------------------------------------------------------------------------- /lib/fecha.umd.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"fecha.umd.js","sources":["../src/fecha.ts"],"sourcesContent":["const token = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|Z|([HhMsDm])\\1?|[aA]|\"[^\"]*\"|'[^']*'/g;\nconst twoDigitsOptional = \"\\\\d\\\\d?\";\nconst twoDigits = \"\\\\d\\\\d\";\nconst threeDigits = \"\\\\d{3}\";\nconst fourDigits = \"\\\\d{4}\";\nconst word = \"[^\\\\s]+\";\nconst literal = /\\[([^]*?)\\]/gm;\n\ntype DateInfo = {\n year: number;\n month: number;\n day: number;\n hour: number;\n minute: number;\n second: number;\n millisecond: number;\n isPm: number | null;\n timezoneOffset: number | null;\n};\n\nexport type I18nSettings = {\n amPm: [string, string];\n dayNames: Days;\n dayNamesShort: Days;\n monthNames: Months;\n monthNamesShort: Months;\n DoFn(dayOfMonth: number): string;\n};\n\nexport type I18nSettingsOptional = Partial;\n\nexport type Days = [string, string, string, string, string, string, string];\nexport type Months = [\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string,\n string\n];\n\nfunction shorten(arr: T, sLen: number): string[] {\n const newArr: string[] = [];\n for (let i = 0, len = arr.length; i < len; i++) {\n newArr.push(arr[i].substr(0, sLen));\n }\n return newArr;\n}\n\nconst monthUpdate = (\n arrName: \"monthNames\" | \"monthNamesShort\" | \"dayNames\" | \"dayNamesShort\"\n) => (v: string, i18n: I18nSettings): number | null => {\n const lowerCaseArr = i18n[arrName].map(v => v.toLowerCase());\n const index = lowerCaseArr.indexOf(v.toLowerCase());\n if (index > -1) {\n return index;\n }\n return null;\n};\n\nexport function assign(a: A): A;\nexport function assign(a: A, b: B): A & B;\nexport function assign(a: A, b: B, c: C): A & B & C;\nexport function assign(a: A, b: B, c: C, d: D): A & B & C & D;\nexport function assign(origObj: any, ...args: any[]): any {\n for (const obj of args) {\n for (const key in obj) {\n // @ts-ignore ex\n origObj[key] = obj[key];\n }\n }\n return origObj;\n}\n\nconst dayNames: Days = [\n \"Sunday\",\n \"Monday\",\n \"Tuesday\",\n \"Wednesday\",\n \"Thursday\",\n \"Friday\",\n \"Saturday\"\n];\nconst monthNames: Months = [\n \"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\"\n];\n\nconst monthNamesShort: Months = shorten(monthNames, 3) as Months;\nconst dayNamesShort: Days = shorten(dayNames, 3) as Days;\n\nconst defaultI18n: I18nSettings = {\n dayNamesShort,\n dayNames,\n monthNamesShort,\n monthNames,\n amPm: [\"am\", \"pm\"],\n DoFn(dayOfMonth: number) {\n return (\n dayOfMonth +\n [\"th\", \"st\", \"nd\", \"rd\"][\n dayOfMonth % 10 > 3\n ? 0\n : ((dayOfMonth - (dayOfMonth % 10) !== 10 ? 1 : 0) * dayOfMonth) % 10\n ]\n );\n }\n};\nlet globalI18n = assign({}, defaultI18n);\nconst setGlobalDateI18n = (i18n: I18nSettingsOptional): I18nSettings =>\n (globalI18n = assign(globalI18n, i18n));\n\nconst regexEscape = (str: string): string =>\n str.replace(/[|\\\\{()[^$+*?.-]/g, \"\\\\$&\");\n\nconst pad = (val: string | number, len = 2): string => {\n val = String(val);\n while (val.length < len) {\n val = \"0\" + val;\n }\n return val;\n};\n\nconst formatFlags: Record<\n string,\n (dateObj: Date, i18n: I18nSettings) => string\n> = {\n D: (dateObj: Date): string => String(dateObj.getDate()),\n DD: (dateObj: Date): string => pad(dateObj.getDate()),\n Do: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.DoFn(dateObj.getDate()),\n d: (dateObj: Date): string => String(dateObj.getDay()),\n dd: (dateObj: Date): string => pad(dateObj.getDay()),\n ddd: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.dayNamesShort[dateObj.getDay()],\n dddd: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.dayNames[dateObj.getDay()],\n M: (dateObj: Date): string => String(dateObj.getMonth() + 1),\n MM: (dateObj: Date): string => pad(dateObj.getMonth() + 1),\n MMM: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.monthNamesShort[dateObj.getMonth()],\n MMMM: (dateObj: Date, i18n: I18nSettings): string =>\n i18n.monthNames[dateObj.getMonth()],\n YY: (dateObj: Date): string =>\n pad(String(dateObj.getFullYear()), 4).substr(2),\n YYYY: (dateObj: Date): string => pad(dateObj.getFullYear(), 4),\n h: (dateObj: Date): string => String(dateObj.getHours() % 12 || 12),\n hh: (dateObj: Date): string => pad(dateObj.getHours() % 12 || 12),\n H: (dateObj: Date): string => String(dateObj.getHours()),\n HH: (dateObj: Date): string => pad(dateObj.getHours()),\n m: (dateObj: Date): string => String(dateObj.getMinutes()),\n mm: (dateObj: Date): string => pad(dateObj.getMinutes()),\n s: (dateObj: Date): string => String(dateObj.getSeconds()),\n ss: (dateObj: Date): string => pad(dateObj.getSeconds()),\n S: (dateObj: Date): string =>\n String(Math.round(dateObj.getMilliseconds() / 100)),\n SS: (dateObj: Date): string =>\n pad(Math.round(dateObj.getMilliseconds() / 10), 2),\n SSS: (dateObj: Date): string => pad(dateObj.getMilliseconds(), 3),\n a: (dateObj: Date, i18n: I18nSettings): string =>\n dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1],\n A: (dateObj: Date, i18n: I18nSettings): string =>\n dateObj.getHours() < 12\n ? i18n.amPm[0].toUpperCase()\n : i18n.amPm[1].toUpperCase(),\n ZZ(dateObj: Date): string {\n const offset = dateObj.getTimezoneOffset();\n return (\n (offset > 0 ? \"-\" : \"+\") +\n pad(Math.floor(Math.abs(offset) / 60) * 100 + (Math.abs(offset) % 60), 4)\n );\n },\n Z(dateObj: Date): string {\n const offset = dateObj.getTimezoneOffset();\n return (\n (offset > 0 ? \"-\" : \"+\") +\n pad(Math.floor(Math.abs(offset) / 60), 2) +\n \":\" +\n pad(Math.abs(offset) % 60, 2)\n );\n }\n};\n\ntype ParseInfo = [\n keyof DateInfo,\n string,\n ((v: string, i18n: I18nSettings) => number | null)?,\n string?\n];\nconst monthParse = (v: string): number => +v - 1;\nconst emptyDigits: ParseInfo = [null, twoDigitsOptional];\nconst emptyWord: ParseInfo = [null, word];\nconst amPm: ParseInfo = [\n \"isPm\",\n word,\n (v: string, i18n: I18nSettings): number | null => {\n const val = v.toLowerCase();\n if (val === i18n.amPm[0]) {\n return 0;\n } else if (val === i18n.amPm[1]) {\n return 1;\n }\n return null;\n }\n];\nconst timezoneOffset: ParseInfo = [\n \"timezoneOffset\",\n \"[^\\\\s]*?[\\\\+\\\\-]\\\\d\\\\d:?\\\\d\\\\d|[^\\\\s]*?Z?\",\n (v: string): number | null => {\n const parts = (v + \"\").match(/([+-]|\\d\\d)/gi);\n\n if (parts) {\n const minutes = +parts[1] * 60 + parseInt(parts[2], 10);\n return parts[0] === \"+\" ? minutes : -minutes;\n }\n\n return 0;\n }\n];\nconst parseFlags: Record = {\n D: [\"day\", twoDigitsOptional],\n DD: [\"day\", twoDigits],\n Do: [\"day\", twoDigitsOptional + word, (v: string): number => parseInt(v, 10)],\n M: [\"month\", twoDigitsOptional, monthParse],\n MM: [\"month\", twoDigits, monthParse],\n YY: [\n \"year\",\n twoDigits,\n (v: string): number => {\n const now = new Date();\n const cent = +(\"\" + now.getFullYear()).substr(0, 2);\n return +(\"\" + (+v > 68 ? cent - 1 : cent) + v);\n }\n ],\n h: [\"hour\", twoDigitsOptional, undefined, \"isPm\"],\n hh: [\"hour\", twoDigits, undefined, \"isPm\"],\n H: [\"hour\", twoDigitsOptional],\n HH: [\"hour\", twoDigits],\n m: [\"minute\", twoDigitsOptional],\n mm: [\"minute\", twoDigits],\n s: [\"second\", twoDigitsOptional],\n ss: [\"second\", twoDigits],\n YYYY: [\"year\", fourDigits],\n S: [\"millisecond\", \"\\\\d\", (v: string): number => +v * 100],\n SS: [\"millisecond\", twoDigits, (v: string): number => +v * 10],\n SSS: [\"millisecond\", threeDigits],\n d: emptyDigits,\n dd: emptyDigits,\n ddd: emptyWord,\n dddd: emptyWord,\n MMM: [\"month\", word, monthUpdate(\"monthNamesShort\")],\n MMMM: [\"month\", word, monthUpdate(\"monthNames\")],\n a: amPm,\n A: amPm,\n ZZ: timezoneOffset,\n Z: timezoneOffset\n};\n\n// Some common format strings\nconst globalMasks: { [key: string]: string } = {\n default: \"ddd MMM DD YYYY HH:mm:ss\",\n shortDate: \"M/D/YY\",\n mediumDate: \"MMM D, YYYY\",\n longDate: \"MMMM D, YYYY\",\n fullDate: \"dddd, MMMM D, YYYY\",\n isoDate: \"YYYY-MM-DD\",\n isoDateTime: \"YYYY-MM-DDTHH:mm:ssZ\",\n shortTime: \"HH:mm\",\n mediumTime: \"HH:mm:ss\",\n longTime: \"HH:mm:ss.SSS\"\n};\nconst setGlobalDateMasks = (masks: {\n [key: string]: string;\n}): { [key: string]: string } => assign(globalMasks, masks);\n\n/***\n * Format a date\n * @method format\n * @param {Date|number} dateObj\n * @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate'\n * @returns {string} Formatted date string\n */\nconst format = (\n dateObj: Date,\n mask: string = globalMasks[\"default\"],\n i18n: I18nSettingsOptional = {}\n): string => {\n if (typeof dateObj === \"number\") {\n dateObj = new Date(dateObj);\n }\n\n if (\n Object.prototype.toString.call(dateObj) !== \"[object Date]\" ||\n isNaN(dateObj.getTime())\n ) {\n throw new Error(\"Invalid Date pass to format\");\n }\n\n mask = globalMasks[mask] || mask;\n\n const literals: string[] = [];\n\n // Make literals inactive by replacing them with @@@\n mask = mask.replace(literal, function($0, $1) {\n literals.push($1);\n return \"@@@\";\n });\n\n const combinedI18nSettings: I18nSettings = assign(\n assign({}, globalI18n),\n i18n\n );\n // Apply formatting rules\n mask = mask.replace(token, $0 =>\n formatFlags[$0](dateObj, combinedI18nSettings)\n );\n // Inline literal values back into the formatted value\n return mask.replace(/@@@/g, () => literals.shift());\n};\n\n/**\n * Parse a date string into a Javascript Date object /\n * @method parse\n * @param {string} dateStr Date string\n * @param {string} format Date parse format\n * @param {i18n} I18nSettingsOptional Full or subset of I18N settings\n * @returns {Date|null} Returns Date object. Returns null what date string is invalid or doesn't match format\n */\nfunction parse(\n dateStr: string,\n format: string,\n i18n: I18nSettingsOptional = {}\n): Date | null {\n if (typeof format !== \"string\") {\n throw new Error(\"Invalid format in fecha parse\");\n }\n\n // Check to see if the format is actually a mask\n format = globalMasks[format] || format;\n\n // Avoid regular expression denial of service, fail early for really long strings\n // https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS\n if (dateStr.length > 1000) {\n return null;\n }\n\n // Default to the beginning of the year.\n const today = new Date();\n const dateInfo: DateInfo = {\n year: today.getFullYear(),\n month: 0,\n day: 1,\n hour: 0,\n minute: 0,\n second: 0,\n millisecond: 0,\n isPm: null,\n timezoneOffset: null\n };\n const parseInfo: ParseInfo[] = [];\n const literals: string[] = [];\n\n // Replace all the literals with @@@. Hopefully a string that won't exist in the format\n let newFormat = format.replace(literal, ($0, $1) => {\n literals.push(regexEscape($1));\n return \"@@@\";\n });\n const specifiedFields: { [field: string]: boolean } = {};\n const requiredFields: { [field: string]: boolean } = {};\n\n // Change every token that we find into the correct regex\n newFormat = regexEscape(newFormat).replace(token, $0 => {\n const info = parseFlags[$0];\n const [field, regex, , requiredField] = info;\n\n // Check if the person has specified the same field twice. This will lead to confusing results.\n if (specifiedFields[field]) {\n throw new Error(`Invalid format. ${field} specified twice in format`);\n }\n\n specifiedFields[field] = true;\n\n // Check if there are any required fields. For instance, 12 hour time requires AM/PM specified\n if (requiredField) {\n requiredFields[requiredField] = true;\n }\n\n parseInfo.push(info);\n return \"(\" + regex + \")\";\n });\n\n // Check all the required fields are present\n Object.keys(requiredFields).forEach(field => {\n if (!specifiedFields[field]) {\n throw new Error(\n `Invalid format. ${field} is required in specified format`\n );\n }\n });\n\n // Add back all the literals after\n newFormat = newFormat.replace(/@@@/g, () => literals.shift());\n\n // Check if the date string matches the format. If it doesn't return null\n const matches = dateStr.match(new RegExp(newFormat, \"i\"));\n if (!matches) {\n return null;\n }\n\n const combinedI18nSettings: I18nSettings = assign(\n assign({}, globalI18n),\n i18n\n );\n\n // For each match, call the parser function for that date part\n for (let i = 1; i < matches.length; i++) {\n const [field, , parser] = parseInfo[i - 1];\n const value = parser\n ? parser(matches[i], combinedI18nSettings)\n : +matches[i];\n\n // If the parser can't make sense of the value, return null\n if (value == null) {\n return null;\n }\n\n dateInfo[field] = value;\n }\n\n if (dateInfo.isPm === 1 && dateInfo.hour != null && +dateInfo.hour !== 12) {\n dateInfo.hour = +dateInfo.hour + 12;\n } else if (dateInfo.isPm === 0 && +dateInfo.hour === 12) {\n dateInfo.hour = 0;\n }\n\n let dateTZ: Date;\n if (dateInfo.timezoneOffset == null) {\n dateTZ = new Date(\n dateInfo.year,\n dateInfo.month,\n dateInfo.day,\n dateInfo.hour,\n dateInfo.minute,\n dateInfo.second,\n dateInfo.millisecond\n );\n const validateFields: [\n \"month\" | \"day\" | \"hour\" | \"minute\" | \"second\",\n \"getMonth\" | \"getDate\" | \"getHours\" | \"getMinutes\" | \"getSeconds\"\n ][] = [\n [\"month\", \"getMonth\"],\n [\"day\", \"getDate\"],\n [\"hour\", \"getHours\"],\n [\"minute\", \"getMinutes\"],\n [\"second\", \"getSeconds\"]\n ];\n for (let i = 0, len = validateFields.length; i < len; i++) {\n // Check to make sure the date field is within the allowed range. Javascript dates allows values\n // outside the allowed range. If the values don't match the value was invalid\n if (\n specifiedFields[validateFields[i][0]] &&\n dateInfo[validateFields[i][0]] !== dateTZ[validateFields[i][1]]()\n ) {\n return null;\n }\n }\n } else {\n dateTZ = new Date(\n Date.UTC(\n dateInfo.year,\n dateInfo.month,\n dateInfo.day,\n dateInfo.hour,\n dateInfo.minute - dateInfo.timezoneOffset,\n dateInfo.second,\n dateInfo.millisecond\n )\n );\n\n // We can't validate dates in another timezone unfortunately. Do a basic check instead\n if (\n dateInfo.month > 11 ||\n dateInfo.month < 0 ||\n dateInfo.day > 31 ||\n dateInfo.day < 1 ||\n dateInfo.hour > 23 ||\n dateInfo.hour < 0 ||\n dateInfo.minute > 59 ||\n dateInfo.minute < 0 ||\n dateInfo.second > 59 ||\n dateInfo.second < 0\n ) {\n return null;\n }\n }\n\n // Don't allow invalid dates\n\n return dateTZ;\n}\nexport default {\n format,\n parse,\n defaultI18n,\n setGlobalDateI18n,\n setGlobalDateMasks\n};\nexport { format, parse, defaultI18n, setGlobalDateI18n, setGlobalDateMasks };\n"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fecha", 3 | "version": "4.2.3", 4 | "description": "Date formatting and parsing", 5 | "main": "lib/fecha.umd.js", 6 | "module": "lib/fecha.js", 7 | "scripts": { 8 | "test-only": "ts-node test.js", 9 | "test": "prettier --check *.js src/*.ts && eslint --ext .ts src && npm run build && nyc --cache --reporter=text ts-node test.js", 10 | "build": "NODE_ENV=production rollup -c --sourcemap && tsc", 11 | "format": "prettier --write *.js src/*.ts" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://taylorhakes@github.com/taylorhakes/fecha.git" 16 | }, 17 | "keywords": [ 18 | "date", 19 | "parse", 20 | "moment", 21 | "format", 22 | "fecha", 23 | "formatting" 24 | ], 25 | "author": "Taylor Hakes", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/taylorhakes/fecha/issues" 29 | }, 30 | "homepage": "https://github.com/taylorhakes/fecha", 31 | "devDependencies": { 32 | "@istanbuljs/nyc-config-typescript": "^1.0.1", 33 | "@typescript-eslint/eslint-plugin": "^2.14.0", 34 | "@typescript-eslint/parser": "^2.14.0", 35 | "eslint": "^7.23.0", 36 | "eslint-config-prettier": "^8.1.0", 37 | "nyc": "^15.0.0", 38 | "painless": "^0.9.7", 39 | "prettier": "1.19.1", 40 | "rollup": "^0.59.0", 41 | "rollup-plugin-sourcemaps": "^0.5.0", 42 | "rollup-plugin-typescript": "^1.0.1", 43 | "rollup-plugin-uglify": "^3.0.0", 44 | "source-map-support": "^0.5.16", 45 | "ts-node": "^8.5.4", 46 | "tslib": "^1.10.0", 47 | "typescript": "^3.7.4" 48 | }, 49 | "files": [ 50 | "lib", 51 | "dist", 52 | "src" 53 | ], 54 | "types": "lib/fecha.d.ts" 55 | } 56 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import uglify from "rollup-plugin-uglify"; 2 | import typescript from "rollup-plugin-typescript"; 3 | import sourceMaps from "rollup-plugin-sourcemaps"; 4 | 5 | export default [ 6 | // Compressed (for direct consumption in browser) 7 | // written to dist folder, minified. 8 | { 9 | input: "src/fecha.ts", 10 | output: { 11 | // How it will be exposed on window 12 | name: "fecha", 13 | format: "umd", 14 | file: "dist/fecha.min.js", 15 | exports: "named" 16 | }, 17 | plugins: [typescript(), uglify(), sourceMaps()] 18 | }, 19 | // For Node: no minify, output in lib dir 20 | { 21 | input: "src/fecha.ts", 22 | output: { 23 | name: "fecha", 24 | format: "umd", 25 | file: "lib/fecha.umd.js", 26 | exports: "named" 27 | }, 28 | plugins: [typescript()] 29 | }, 30 | { 31 | input: "src/fecha.ts", 32 | output: { 33 | name: "fecha", 34 | format: "esm", 35 | file: "lib/fecha.js", 36 | exports: "named" 37 | }, 38 | plugins: [typescript()] 39 | } 40 | ]; 41 | -------------------------------------------------------------------------------- /src/fecha.ts: -------------------------------------------------------------------------------- 1 | const token = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|Z|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g; 2 | const twoDigitsOptional = "\\d\\d?"; 3 | const twoDigits = "\\d\\d"; 4 | const threeDigits = "\\d{3}"; 5 | const fourDigits = "\\d{4}"; 6 | const word = "[^\\s]+"; 7 | const literal = /\[([^]*?)\]/gm; 8 | 9 | type DateInfo = { 10 | year: number; 11 | month: number; 12 | day: number; 13 | hour: number; 14 | minute: number; 15 | second: number; 16 | millisecond: number; 17 | isPm: number | null; 18 | timezoneOffset: number | null; 19 | }; 20 | 21 | export type I18nSettings = { 22 | amPm: [string, string]; 23 | dayNames: Days; 24 | dayNamesShort: Days; 25 | monthNames: Months; 26 | monthNamesShort: Months; 27 | DoFn(dayOfMonth: number): string; 28 | }; 29 | 30 | export type I18nSettingsOptional = Partial; 31 | 32 | export type Days = [string, string, string, string, string, string, string]; 33 | export type Months = [ 34 | string, 35 | string, 36 | string, 37 | string, 38 | string, 39 | string, 40 | string, 41 | string, 42 | string, 43 | string, 44 | string, 45 | string 46 | ]; 47 | 48 | function shorten(arr: T, sLen: number): string[] { 49 | const newArr: string[] = []; 50 | for (let i = 0, len = arr.length; i < len; i++) { 51 | newArr.push(arr[i].substr(0, sLen)); 52 | } 53 | return newArr; 54 | } 55 | 56 | const monthUpdate = ( 57 | arrName: "monthNames" | "monthNamesShort" | "dayNames" | "dayNamesShort" 58 | ) => (v: string, i18n: I18nSettings): number | null => { 59 | const lowerCaseArr = i18n[arrName].map(v => v.toLowerCase()); 60 | const index = lowerCaseArr.indexOf(v.toLowerCase()); 61 | if (index > -1) { 62 | return index; 63 | } 64 | return null; 65 | }; 66 | 67 | export function assign(a: A): A; 68 | export function assign(a: A, b: B): A & B; 69 | export function assign(a: A, b: B, c: C): A & B & C; 70 | export function assign(a: A, b: B, c: C, d: D): A & B & C & D; 71 | export function assign(origObj: any, ...args: any[]): any { 72 | for (const obj of args) { 73 | for (const key in obj) { 74 | // @ts-ignore ex 75 | origObj[key] = obj[key]; 76 | } 77 | } 78 | return origObj; 79 | } 80 | 81 | const dayNames: Days = [ 82 | "Sunday", 83 | "Monday", 84 | "Tuesday", 85 | "Wednesday", 86 | "Thursday", 87 | "Friday", 88 | "Saturday" 89 | ]; 90 | const monthNames: Months = [ 91 | "January", 92 | "February", 93 | "March", 94 | "April", 95 | "May", 96 | "June", 97 | "July", 98 | "August", 99 | "September", 100 | "October", 101 | "November", 102 | "December" 103 | ]; 104 | 105 | const monthNamesShort: Months = shorten(monthNames, 3) as Months; 106 | const dayNamesShort: Days = shorten(dayNames, 3) as Days; 107 | 108 | const defaultI18n: I18nSettings = { 109 | dayNamesShort, 110 | dayNames, 111 | monthNamesShort, 112 | monthNames, 113 | amPm: ["am", "pm"], 114 | DoFn(dayOfMonth: number) { 115 | return ( 116 | dayOfMonth + 117 | ["th", "st", "nd", "rd"][ 118 | dayOfMonth % 10 > 3 119 | ? 0 120 | : ((dayOfMonth - (dayOfMonth % 10) !== 10 ? 1 : 0) * dayOfMonth) % 10 121 | ] 122 | ); 123 | } 124 | }; 125 | let globalI18n = assign({}, defaultI18n); 126 | const setGlobalDateI18n = (i18n: I18nSettingsOptional): I18nSettings => 127 | (globalI18n = assign(globalI18n, i18n)); 128 | 129 | const regexEscape = (str: string): string => 130 | str.replace(/[|\\{()[^$+*?.-]/g, "\\$&"); 131 | 132 | const pad = (val: string | number, len = 2): string => { 133 | val = String(val); 134 | while (val.length < len) { 135 | val = "0" + val; 136 | } 137 | return val; 138 | }; 139 | 140 | const formatFlags: Record< 141 | string, 142 | (dateObj: Date, i18n: I18nSettings) => string 143 | > = { 144 | D: (dateObj: Date): string => String(dateObj.getDate()), 145 | DD: (dateObj: Date): string => pad(dateObj.getDate()), 146 | Do: (dateObj: Date, i18n: I18nSettings): string => 147 | i18n.DoFn(dateObj.getDate()), 148 | d: (dateObj: Date): string => String(dateObj.getDay()), 149 | dd: (dateObj: Date): string => pad(dateObj.getDay()), 150 | ddd: (dateObj: Date, i18n: I18nSettings): string => 151 | i18n.dayNamesShort[dateObj.getDay()], 152 | dddd: (dateObj: Date, i18n: I18nSettings): string => 153 | i18n.dayNames[dateObj.getDay()], 154 | M: (dateObj: Date): string => String(dateObj.getMonth() + 1), 155 | MM: (dateObj: Date): string => pad(dateObj.getMonth() + 1), 156 | MMM: (dateObj: Date, i18n: I18nSettings): string => 157 | i18n.monthNamesShort[dateObj.getMonth()], 158 | MMMM: (dateObj: Date, i18n: I18nSettings): string => 159 | i18n.monthNames[dateObj.getMonth()], 160 | YY: (dateObj: Date): string => 161 | pad(String(dateObj.getFullYear()), 4).substr(2), 162 | YYYY: (dateObj: Date): string => pad(dateObj.getFullYear(), 4), 163 | h: (dateObj: Date): string => String(dateObj.getHours() % 12 || 12), 164 | hh: (dateObj: Date): string => pad(dateObj.getHours() % 12 || 12), 165 | H: (dateObj: Date): string => String(dateObj.getHours()), 166 | HH: (dateObj: Date): string => pad(dateObj.getHours()), 167 | m: (dateObj: Date): string => String(dateObj.getMinutes()), 168 | mm: (dateObj: Date): string => pad(dateObj.getMinutes()), 169 | s: (dateObj: Date): string => String(dateObj.getSeconds()), 170 | ss: (dateObj: Date): string => pad(dateObj.getSeconds()), 171 | S: (dateObj: Date): string => 172 | String(Math.round(dateObj.getMilliseconds() / 100)), 173 | SS: (dateObj: Date): string => 174 | pad(Math.round(dateObj.getMilliseconds() / 10), 2), 175 | SSS: (dateObj: Date): string => pad(dateObj.getMilliseconds(), 3), 176 | a: (dateObj: Date, i18n: I18nSettings): string => 177 | dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1], 178 | A: (dateObj: Date, i18n: I18nSettings): string => 179 | dateObj.getHours() < 12 180 | ? i18n.amPm[0].toUpperCase() 181 | : i18n.amPm[1].toUpperCase(), 182 | ZZ(dateObj: Date): string { 183 | const offset = dateObj.getTimezoneOffset(); 184 | return ( 185 | (offset > 0 ? "-" : "+") + 186 | pad(Math.floor(Math.abs(offset) / 60) * 100 + (Math.abs(offset) % 60), 4) 187 | ); 188 | }, 189 | Z(dateObj: Date): string { 190 | const offset = dateObj.getTimezoneOffset(); 191 | return ( 192 | (offset > 0 ? "-" : "+") + 193 | pad(Math.floor(Math.abs(offset) / 60), 2) + 194 | ":" + 195 | pad(Math.abs(offset) % 60, 2) 196 | ); 197 | } 198 | }; 199 | 200 | type ParseInfo = [ 201 | keyof DateInfo, 202 | string, 203 | ((v: string, i18n: I18nSettings) => number | null)?, 204 | string? 205 | ]; 206 | const monthParse = (v: string): number => +v - 1; 207 | const emptyDigits: ParseInfo = [null, twoDigitsOptional]; 208 | const emptyWord: ParseInfo = [null, word]; 209 | const amPm: ParseInfo = [ 210 | "isPm", 211 | word, 212 | (v: string, i18n: I18nSettings): number | null => { 213 | const val = v.toLowerCase(); 214 | if (val === i18n.amPm[0]) { 215 | return 0; 216 | } else if (val === i18n.amPm[1]) { 217 | return 1; 218 | } 219 | return null; 220 | } 221 | ]; 222 | const timezoneOffset: ParseInfo = [ 223 | "timezoneOffset", 224 | "[^\\s]*?[\\+\\-]\\d\\d:?\\d\\d|[^\\s]*?Z?", 225 | (v: string): number | null => { 226 | const parts = (v + "").match(/([+-]|\d\d)/gi); 227 | 228 | if (parts) { 229 | const minutes = +parts[1] * 60 + parseInt(parts[2], 10); 230 | return parts[0] === "+" ? minutes : -minutes; 231 | } 232 | 233 | return 0; 234 | } 235 | ]; 236 | const parseFlags: Record = { 237 | D: ["day", twoDigitsOptional], 238 | DD: ["day", twoDigits], 239 | Do: ["day", twoDigitsOptional + word, (v: string): number => parseInt(v, 10)], 240 | M: ["month", twoDigitsOptional, monthParse], 241 | MM: ["month", twoDigits, monthParse], 242 | YY: [ 243 | "year", 244 | twoDigits, 245 | (v: string): number => { 246 | const now = new Date(); 247 | const cent = +("" + now.getFullYear()).substr(0, 2); 248 | return +("" + (+v > 68 ? cent - 1 : cent) + v); 249 | } 250 | ], 251 | h: ["hour", twoDigitsOptional, undefined, "isPm"], 252 | hh: ["hour", twoDigits, undefined, "isPm"], 253 | H: ["hour", twoDigitsOptional], 254 | HH: ["hour", twoDigits], 255 | m: ["minute", twoDigitsOptional], 256 | mm: ["minute", twoDigits], 257 | s: ["second", twoDigitsOptional], 258 | ss: ["second", twoDigits], 259 | YYYY: ["year", fourDigits], 260 | S: ["millisecond", "\\d", (v: string): number => +v * 100], 261 | SS: ["millisecond", twoDigits, (v: string): number => +v * 10], 262 | SSS: ["millisecond", threeDigits], 263 | d: emptyDigits, 264 | dd: emptyDigits, 265 | ddd: emptyWord, 266 | dddd: emptyWord, 267 | MMM: ["month", word, monthUpdate("monthNamesShort")], 268 | MMMM: ["month", word, monthUpdate("monthNames")], 269 | a: amPm, 270 | A: amPm, 271 | ZZ: timezoneOffset, 272 | Z: timezoneOffset 273 | }; 274 | 275 | // Some common format strings 276 | const globalMasks: { [key: string]: string } = { 277 | default: "ddd MMM DD YYYY HH:mm:ss", 278 | shortDate: "M/D/YY", 279 | mediumDate: "MMM D, YYYY", 280 | longDate: "MMMM D, YYYY", 281 | fullDate: "dddd, MMMM D, YYYY", 282 | isoDate: "YYYY-MM-DD", 283 | isoDateTime: "YYYY-MM-DDTHH:mm:ssZ", 284 | shortTime: "HH:mm", 285 | mediumTime: "HH:mm:ss", 286 | longTime: "HH:mm:ss.SSS" 287 | }; 288 | const setGlobalDateMasks = (masks: { 289 | [key: string]: string; 290 | }): { [key: string]: string } => assign(globalMasks, masks); 291 | 292 | /*** 293 | * Format a date 294 | * @method format 295 | * @param {Date|number} dateObj 296 | * @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate' 297 | * @returns {string} Formatted date string 298 | */ 299 | const format = ( 300 | dateObj: Date, 301 | mask: string = globalMasks["default"], 302 | i18n: I18nSettingsOptional = {} 303 | ): string => { 304 | if (typeof dateObj === "number") { 305 | dateObj = new Date(dateObj); 306 | } 307 | 308 | if ( 309 | Object.prototype.toString.call(dateObj) !== "[object Date]" || 310 | isNaN(dateObj.getTime()) 311 | ) { 312 | throw new Error("Invalid Date pass to format"); 313 | } 314 | 315 | mask = globalMasks[mask] || mask; 316 | 317 | const literals: string[] = []; 318 | 319 | // Make literals inactive by replacing them with @@@ 320 | mask = mask.replace(literal, function($0, $1) { 321 | literals.push($1); 322 | return "@@@"; 323 | }); 324 | 325 | const combinedI18nSettings: I18nSettings = assign( 326 | assign({}, globalI18n), 327 | i18n 328 | ); 329 | // Apply formatting rules 330 | mask = mask.replace(token, $0 => 331 | formatFlags[$0](dateObj, combinedI18nSettings) 332 | ); 333 | // Inline literal values back into the formatted value 334 | return mask.replace(/@@@/g, () => literals.shift()); 335 | }; 336 | 337 | /** 338 | * Parse a date string into a Javascript Date object / 339 | * @method parse 340 | * @param {string} dateStr Date string 341 | * @param {string} format Date parse format 342 | * @param {i18n} I18nSettingsOptional Full or subset of I18N settings 343 | * @returns {Date|null} Returns Date object. Returns null what date string is invalid or doesn't match format 344 | */ 345 | function parse( 346 | dateStr: string, 347 | format: string, 348 | i18n: I18nSettingsOptional = {} 349 | ): Date | null { 350 | if (typeof format !== "string") { 351 | throw new Error("Invalid format in fecha parse"); 352 | } 353 | 354 | // Check to see if the format is actually a mask 355 | format = globalMasks[format] || format; 356 | 357 | // Avoid regular expression denial of service, fail early for really long strings 358 | // https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS 359 | if (dateStr.length > 1000) { 360 | return null; 361 | } 362 | 363 | // Default to the beginning of the year. 364 | const today = new Date(); 365 | const dateInfo: DateInfo = { 366 | year: today.getFullYear(), 367 | month: 0, 368 | day: 1, 369 | hour: 0, 370 | minute: 0, 371 | second: 0, 372 | millisecond: 0, 373 | isPm: null, 374 | timezoneOffset: null 375 | }; 376 | const parseInfo: ParseInfo[] = []; 377 | const literals: string[] = []; 378 | 379 | // Replace all the literals with @@@. Hopefully a string that won't exist in the format 380 | let newFormat = format.replace(literal, ($0, $1) => { 381 | literals.push(regexEscape($1)); 382 | return "@@@"; 383 | }); 384 | const specifiedFields: { [field: string]: boolean } = {}; 385 | const requiredFields: { [field: string]: boolean } = {}; 386 | 387 | // Change every token that we find into the correct regex 388 | newFormat = regexEscape(newFormat).replace(token, $0 => { 389 | const info = parseFlags[$0]; 390 | const [field, regex, , requiredField] = info; 391 | 392 | // Check if the person has specified the same field twice. This will lead to confusing results. 393 | if (specifiedFields[field]) { 394 | throw new Error(`Invalid format. ${field} specified twice in format`); 395 | } 396 | 397 | specifiedFields[field] = true; 398 | 399 | // Check if there are any required fields. For instance, 12 hour time requires AM/PM specified 400 | if (requiredField) { 401 | requiredFields[requiredField] = true; 402 | } 403 | 404 | parseInfo.push(info); 405 | return "(" + regex + ")"; 406 | }); 407 | 408 | // Check all the required fields are present 409 | Object.keys(requiredFields).forEach(field => { 410 | if (!specifiedFields[field]) { 411 | throw new Error( 412 | `Invalid format. ${field} is required in specified format` 413 | ); 414 | } 415 | }); 416 | 417 | // Add back all the literals after 418 | newFormat = newFormat.replace(/@@@/g, () => literals.shift()); 419 | 420 | // Check if the date string matches the format. If it doesn't return null 421 | const matches = dateStr.match(new RegExp(newFormat, "i")); 422 | if (!matches) { 423 | return null; 424 | } 425 | 426 | const combinedI18nSettings: I18nSettings = assign( 427 | assign({}, globalI18n), 428 | i18n 429 | ); 430 | 431 | // For each match, call the parser function for that date part 432 | for (let i = 1; i < matches.length; i++) { 433 | const [field, , parser] = parseInfo[i - 1]; 434 | const value = parser 435 | ? parser(matches[i], combinedI18nSettings) 436 | : +matches[i]; 437 | 438 | // If the parser can't make sense of the value, return null 439 | if (value == null) { 440 | return null; 441 | } 442 | 443 | dateInfo[field] = value; 444 | } 445 | 446 | if (dateInfo.isPm === 1 && dateInfo.hour != null && +dateInfo.hour !== 12) { 447 | dateInfo.hour = +dateInfo.hour + 12; 448 | } else if (dateInfo.isPm === 0 && +dateInfo.hour === 12) { 449 | dateInfo.hour = 0; 450 | } 451 | 452 | let dateTZ: Date; 453 | if (dateInfo.timezoneOffset == null) { 454 | dateTZ = new Date( 455 | dateInfo.year, 456 | dateInfo.month, 457 | dateInfo.day, 458 | dateInfo.hour, 459 | dateInfo.minute, 460 | dateInfo.second, 461 | dateInfo.millisecond 462 | ); 463 | const validateFields: [ 464 | "month" | "day" | "hour" | "minute" | "second", 465 | "getMonth" | "getDate" | "getHours" | "getMinutes" | "getSeconds" 466 | ][] = [ 467 | ["month", "getMonth"], 468 | ["day", "getDate"], 469 | ["hour", "getHours"], 470 | ["minute", "getMinutes"], 471 | ["second", "getSeconds"] 472 | ]; 473 | for (let i = 0, len = validateFields.length; i < len; i++) { 474 | // Check to make sure the date field is within the allowed range. Javascript dates allows values 475 | // outside the allowed range. If the values don't match the value was invalid 476 | if ( 477 | specifiedFields[validateFields[i][0]] && 478 | dateInfo[validateFields[i][0]] !== dateTZ[validateFields[i][1]]() 479 | ) { 480 | return null; 481 | } 482 | } 483 | } else { 484 | dateTZ = new Date( 485 | Date.UTC( 486 | dateInfo.year, 487 | dateInfo.month, 488 | dateInfo.day, 489 | dateInfo.hour, 490 | dateInfo.minute - dateInfo.timezoneOffset, 491 | dateInfo.second, 492 | dateInfo.millisecond 493 | ) 494 | ); 495 | 496 | // We can't validate dates in another timezone unfortunately. Do a basic check instead 497 | if ( 498 | dateInfo.month > 11 || 499 | dateInfo.month < 0 || 500 | dateInfo.day > 31 || 501 | dateInfo.day < 1 || 502 | dateInfo.hour > 23 || 503 | dateInfo.hour < 0 || 504 | dateInfo.minute > 59 || 505 | dateInfo.minute < 0 || 506 | dateInfo.second > 59 || 507 | dateInfo.second < 0 508 | ) { 509 | return null; 510 | } 511 | } 512 | 513 | // Don't allow invalid dates 514 | 515 | return dateTZ; 516 | } 517 | export default { 518 | format, 519 | parse, 520 | defaultI18n, 521 | setGlobalDateI18n, 522 | setGlobalDateMasks 523 | }; 524 | export { format, parse, defaultI18n, setGlobalDateI18n, setGlobalDateMasks }; 525 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var painless = require("painless"); 2 | var fecha = require("./lib/fecha.umd"); 3 | var test = painless.createGroup(); 4 | var assert = painless.assert; 5 | var today = new Date(); 6 | var year = today.getFullYear(); 7 | 8 | function testParse(name, str, format, date) { 9 | test(name, function() { 10 | assert.equal(+fecha.parse(str, format), +date); 11 | }); 12 | } 13 | 14 | function testFormat(name, dateObj, format, expected) { 15 | test(name, function() { 16 | assert.equal(fecha.format(dateObj, format), expected); 17 | }); 18 | } 19 | testParse( 20 | "Lima Peru timezone issue", 21 | "1990-01-01", 22 | "YYYY-MM-DD", 23 | new Date(1990, 0, 1) 24 | ); 25 | testParse("leap year date", "2020-02-29", "YYYY-MM-DD", new Date(2020, 1, 29)); 26 | // This is invalid because it's in the current timezone and can be validated 27 | testParse("29 on non leap year", "2019-02-29", "YYYY-MM-DD", null); 28 | 29 | // A leap date on the wrong year would ideally catch this as wrong, but we can't validate other timezones 30 | testParse( 31 | "29 on non leap year with timzeone", 32 | "2019-02-29 00:00:00Z", 33 | "YYYY-MM-DD HH:mm:ssZ", 34 | new Date(Date.UTC(2019, 2, 1)) 35 | ); 36 | testParse( 37 | "month out of range with too many digits", 38 | "2016-1234-12", 39 | "YYYY-MM-DD", 40 | null 41 | ); 42 | testParse("month out of range", "2016-31-12", "YYYY-MM-DD", null); 43 | testParse( 44 | "zero month results in invalid date", 45 | "2016-00-12", 46 | "YYYY-MM-DD", 47 | null 48 | ); 49 | testParse( 50 | "january parses correctly", 51 | "2016-01-12", 52 | "YYYY-MM-DD", 53 | new Date(2016, 0, 12) 54 | ); 55 | testParse( 56 | "13nth month results in invalid date", 57 | "2016-13-12", 58 | "YYYY-MM-DD", 59 | null 60 | ); 61 | testParse( 62 | "december parses correctly", 63 | "2016-12-12", 64 | "YYYY-MM-DD", 65 | new Date(2016, 11, 12) 66 | ); 67 | testParse("date out of range ", "2016-12-52", "YYYY-MM-DD", null); 68 | testParse( 69 | "zero date results in invalid date ", 70 | "2016-12-00", 71 | "YYYY-MM-DD", 72 | null 73 | ); 74 | testParse( 75 | "first day of the month ", 76 | "2016-12-01", 77 | "YYYY-MM-DD", 78 | new Date(2016, 11, 1) 79 | ); 80 | testParse("invalid", "2016-9876-123", "YYYY-MM-DD", null); 81 | testParse("basic date parse", "2012/05/03", "YYYY/MM/DD", new Date(2012, 4, 3)); 82 | testParse( 83 | "compact basic date parse", 84 | "20120503", 85 | "YYYYMMDD", 86 | new Date(2012, 4, 3) 87 | ); 88 | testParse( 89 | "basic date parse with time", 90 | "2012/05/03 05:01:40", 91 | "YYYY/MM/DD HH:mm:ss", 92 | new Date(2012, 4, 3, 5, 1, 40) 93 | ); 94 | testParse( 95 | "date with different slashes", 96 | "2012-05-03 05:01:40", 97 | "YYYY-MM-DD HH:mm:ss", 98 | new Date(2012, 4, 3, 5, 1, 40) 99 | ); 100 | testParse( 101 | "date with different order", 102 | "11-7-97", 103 | "D-M-YY", 104 | new Date(1997, 6, 11) 105 | ); 106 | testParse("date very short", "2-8-04", "D-M-YY", new Date(2004, 7, 2)); 107 | testParse("ordinal day 3rd", "3rd May", "Do MMM", new Date(year, 4, 3)); 108 | testParse( 109 | "ordinal day 23rd, 2013", 110 | "23rd May, 2013", 111 | "Do MMM, YYYY", 112 | new Date(2013, 4, 23) 113 | ); 114 | testParse( 115 | "ordinal day 12th, 2002", 116 | "nd12 Nov, 2002", 117 | "Do MMM, YYYY", 118 | new Date(2002, 10, 12) 119 | ); 120 | testParse( 121 | "13th Dec, 1995", 122 | "13th Dec, 1995", 123 | "Do MMM, YYYY", 124 | new Date(1995, 11, 13) 125 | ); 126 | testParse("Long month", "December", "MMMM", new Date(year, 11, 1)); 127 | testParse("Long month invalid", "Decembr", "MMMM", null); 128 | testParse( 129 | "1st February, 1982", 130 | "1st February, 1982", 131 | "Do MMMM, YYYY", 132 | new Date(1982, 1, 1) 133 | ); 134 | testParse("compact", "11081997", "MMDDYYYY", new Date(1997, 10, 8)); 135 | testParse( 136 | "month names", 137 | "March 3rd, 1999", 138 | "MMMM Do, YYYY", 139 | new Date(1999, 2, 3) 140 | ); 141 | testParse( 142 | "month names short", 143 | "Jun 12, 2003", 144 | "MMM D, YYYY", 145 | new Date(2003, 5, 12) 146 | ); 147 | testParse( 148 | "day name", 149 | "Wednesday Feb 03, 2100", 150 | "dddd MMM DD, YYYY", 151 | new Date(2100, 1, 3) 152 | ); 153 | testParse( 154 | "ampm 10PM", 155 | "2015-11-07 10PM", 156 | "YYYY-MM-DD hhA", 157 | new Date(2015, 10, 7, 22) 158 | ); 159 | testParse("ampm imvalid", "2015-11-07 10ZM", "YYYY-MM-DD hhA", null); 160 | testParse("ampm 9AM", "2015-11-07 9AM", "YYYY-MM-DD hhA", null); 161 | testParse( 162 | "ampm 12am", 163 | "2000-01-01 12AM", 164 | "YYYY-MM-DD hhA", 165 | new Date(2000, 0, 1, 0) 166 | ); 167 | testParse( 168 | "ampm 3am", 169 | "2000-01-01 12AM", 170 | "YYYY-MM-DD hhA", 171 | new Date(2000, 0, 1, 0) 172 | ); 173 | testParse( 174 | "ampm am lowercase", 175 | "2000-01-01 11am", 176 | "YYYY-MM-DD hha", 177 | new Date(2000, 0, 1, 11) 178 | ); 179 | testParse( 180 | "noon pm lowercase", 181 | "2000-01-01 12pm", 182 | "YYYY-MM-DD hha", 183 | new Date(2000, 0, 1, 12) 184 | ); 185 | testParse( 186 | "24 hour time long", 187 | "2000-01-01 20", 188 | "YYYY-MM-DD HH", 189 | new Date(2000, 0, 1, 20) 190 | ); 191 | testParse( 192 | "24 hour time long 02", 193 | "2000-01-01 02", 194 | "YYYY-MM-DD HH", 195 | new Date(2000, 0, 1, 2) 196 | ); 197 | testParse( 198 | "24 hour time short", 199 | "2000-01-01 3", 200 | "YYYY-MM-DD H", 201 | new Date(2000, 0, 1, 3) 202 | ); 203 | testParse( 204 | "milliseconds time", 205 | "10:20:30.123", 206 | "HH:mm:ss.SSS", 207 | new Date(year, 0, 1, 10, 20, 30, 123) 208 | ); 209 | testParse( 210 | "milliseconds medium", 211 | "10:20:30.12", 212 | "HH:mm:ss.SS", 213 | new Date(year, 0, 1, 10, 20, 30, 120) 214 | ); 215 | testParse( 216 | "milliseconds short", 217 | "10:20:30.1", 218 | "HH:mm:ss.S", 219 | new Date(year, 0, 1, 10, 20, 30, 100) 220 | ); 221 | testParse( 222 | "hours short with 0", 223 | "0:20:30", 224 | "H:mm:ss", 225 | new Date(year, 0, 1, 0, 20, 30) 226 | ); 227 | testParse( 228 | "timezone offset", 229 | "09:20:31 GMT-0500 (EST)", 230 | "HH:mm:ss [GMT]ZZ [(EST)]", 231 | new Date(Date.UTC(year, 0, 1, 14, 20, 31)) 232 | ); 233 | testParse( 234 | "timezone offset with colon", 235 | "09:20:31 GMT-05:00 (EST)", 236 | "HH:mm:ss [GMT]ZZ [(EST)]", 237 | new Date(Date.UTC(year, 0, 1, 14, 20, 31)) 238 | ); 239 | testParse( 240 | "timezone offset with Z", 241 | "09:20:31 GMT-05:00 (EST)", 242 | "HH:mm:ss [GMT]Z [(EST)]", 243 | new Date(Date.UTC(year, 0, 1, 14, 20, 31)) 244 | ); 245 | testParse( 246 | "timezone offset positive", 247 | "09:20:31 GMT+0611", 248 | "HH:mm:ss [GMT]ZZ", 249 | new Date(Date.UTC(year, 0, 1, 3, 9, 31)) 250 | ); 251 | testParse( 252 | "timezone offset large", 253 | "09:20:31 GMT-2330 (EST)", 254 | "HH:mm:ss [GMT]ZZ [(EST)]", 255 | new Date(Date.UTC(year, 0, 2, 8, 50, 31)) 256 | ); 257 | testParse( 258 | "UTC timezone offset", 259 | "09:20:31 GMT-0000 (UTC)", 260 | "HH:mm:ss ZZ", 261 | new Date(Date.UTC(year, 0, 1, 9, 20, 31)) 262 | ); 263 | testParse( 264 | "UTC timezone offset without explicit offset", 265 | "09:20:31Z", 266 | "HH:mm:ssZZ", 267 | new Date(Date.UTC(year, 0, 1, 9, 20, 31)) 268 | ); 269 | testParse( 270 | "UTC timezone offset without explicit offset with Z", 271 | "09:20:31Z", 272 | "HH:mm:ssZ", 273 | new Date(Date.UTC(year, 0, 1, 9, 20, 31)) 274 | ); 275 | 276 | testParse( 277 | "UTC timezone offset without GMT", 278 | "09:20:31 -0000 (UTC)", 279 | "HH:mm:ss ZZ", 280 | new Date(Date.UTC(year, 0, 1, 9, 20, 31)) 281 | ); 282 | testParse("invalid date", "hello", "HH:mm:ss ZZ", null); 283 | testParse( 284 | "formatted date with brackets", 285 | "2019-04-12T15:53", 286 | "YYYY-MM-DD[T]HH:mm", 287 | new Date(2019, 3, 12, 15, 53) 288 | ); 289 | testParse( 290 | "extra characters no brackets", 291 | "xxxx 2000-01-01 xxxx", 292 | "xxxx YYYY-MM-DD xxxx", 293 | new Date(2000, 0, 1) 294 | ); 295 | testParse( 296 | "test parse isoDate format", 297 | "1996-02-09", 298 | "isoDate", 299 | new Date(1996, 1, 9) 300 | ); 301 | testParse( 302 | "test parse isoDateTime format", 303 | "1998-04-08T03:02:07+12:30", 304 | "isoDateTime", 305 | new Date(Date.UTC(1998, 3, 7, 14, 32, 7)) 306 | ); 307 | 308 | testParse( 309 | "test parse isoDateTime mask", 310 | "1998-04-08T03:02:07+12:30", 311 | "isoDateTime", 312 | new Date(Date.UTC(1998, 3, 7, 14, 32, 7)) 313 | ); 314 | 315 | testParse( 316 | "test format then parse isoDateTime mask", 317 | fecha.format(new Date(Date.UTC(1998, 3, 7, 14, 32, 7)), "isoDateTime"), 318 | "isoDateTime", 319 | new Date(Date.UTC(1998, 3, 7, 14, 32, 7)) 320 | ); 321 | 322 | testParse( 323 | "Daylights savings time in US. Should not affect UTC", 324 | "2022-03-13T02:00:00Z", 325 | "YYYY-MM-DDTHH:mm:ssZ", 326 | new Date(Date.UTC(2022, 2, 13, 2, 0, 0)) 327 | ); 328 | 329 | test.beforeEach(() => { 330 | fecha.setGlobalDateI18n(fecha.defaultI18n); 331 | }); 332 | test("test i18n settings override", function() { 333 | fecha.setGlobalDateI18n({ 334 | monthNamesShort: [ 335 | "aaa", 336 | "bbb", 337 | "ccc", 338 | "ddd", 339 | "eee", 340 | "fff", 341 | "ggg", 342 | "hhh", 343 | "iii", 344 | "jjj", 345 | "kkk", 346 | "lll" 347 | ] 348 | }); 349 | assert.equal(+fecha.parse("ddd 2120", "MMM YYYY"), +new Date(2120, 3, 1)); 350 | }); 351 | test("i18n month short parse", function() { 352 | assert.equal( 353 | +fecha.parse("Def 3rd, 2021", "MMM Do, YYYY", { 354 | monthNamesShort: [ 355 | "Adk", 356 | "Def", 357 | "Sdfs", 358 | "Sdf", 359 | "Sdh", 360 | "Tre", 361 | "Iis", 362 | "Swd", 363 | "Ews", 364 | "Sdf", 365 | "Qaas", 366 | "Ier" 367 | ] 368 | }), 369 | +new Date(2021, 1, 3) 370 | ); 371 | }); 372 | test("i18n month long parse", function() { 373 | assert.equal( 374 | +fecha.parse("Defg 3rd, 2021", "MMMM Do, YYYY", { 375 | monthNames: [ 376 | "Adk", 377 | "Defg", 378 | "Sdfs", 379 | "Sdf", 380 | "Sdh", 381 | "Tre", 382 | "Iis", 383 | "Swd", 384 | "Ews", 385 | "Sdf", 386 | "Qaas", 387 | "Ier" 388 | ] 389 | }), 390 | +new Date(2021, 1, 3) 391 | ); 392 | }); 393 | test("i18n pm parse", function() { 394 | assert.equal( 395 | +fecha.parse("2018-05-02 10GD", "YYYY-MM-DD hhA", { 396 | amPm: ["sd", "gd"] 397 | }), 398 | +new Date(2018, 4, 2, 22) 399 | ); 400 | }); 401 | test("i18n am parse", function() { 402 | assert.equal( 403 | +fecha.parse("2018-05-02 10SD", "YYYY-MM-DD hhA", { 404 | amPm: ["sd", "gd"] 405 | }), 406 | +new Date(2018, 4, 2, 10) 407 | ); 408 | }); 409 | test("invalid date no format", function() { 410 | assert.throws(function() { 411 | fecha.parse("hello"); 412 | }); 413 | }); 414 | test("no format specified", function() { 415 | assert.throws(function() { 416 | fecha.parse("2014-11-05", false); 417 | }); 418 | }); 419 | test("year format specified twice", function() { 420 | assert.throws(function() { 421 | fecha.parse("2014-2015", "YYYY-YYYY"); 422 | }); 423 | }); 424 | test("12 hour format without am/pm", function() { 425 | assert.throws(function() { 426 | fecha.parse("09:24", "hh:mm"); 427 | }); 428 | }); 429 | test("long input null", function() { 430 | var input = ""; 431 | for (var i = 0; i < 1002; i++) { 432 | input += "1"; 433 | } 434 | assert.equal(fecha.parse(input, "HH"), null); 435 | }); 436 | 437 | // // Day of the month 438 | testFormat("Day of the month", new Date(2014, 2, 5), "D", "5"); 439 | testFormat("Day of the month padded", new Date(2014, 2, 5), "DD", "05"); 440 | 441 | // Day of the week 442 | testFormat("Day of the week short", new Date(2015, 0, 8), "d", "4"); 443 | testFormat("Day of the week long", new Date(2015, 0, 10), "dd", "06"); 444 | testFormat("Day of the week short name", new Date(2014, 2, 5), "ddd", "Wed"); 445 | testFormat( 446 | "Day of the week long name", 447 | new Date(2014, 2, 5), 448 | "dddd", 449 | "Wednesday" 450 | ); 451 | 452 | // Month 453 | testFormat("Month", new Date(2014, 2, 5), "M", "3"); 454 | testFormat("Month padded", new Date(2014, 2, 5), "MM", "03"); 455 | testFormat("Month short name", new Date(2014, 2, 5), "MMM", "Mar"); 456 | testFormat("Month full name mmmm", new Date(2014, 2, 5), "MMMM", "March"); 457 | 458 | // Year 459 | testFormat("Year short", new Date(2001, 2, 5), "YY", "01"); 460 | testFormat("Year long", new Date(2001, 2, 5), "YYYY", "2001"); 461 | 462 | // Hour 463 | testFormat("Hour 12 hour short", new Date(2001, 2, 5, 6), "h", "6"); 464 | testFormat("Hour 12 hour padded", new Date(2001, 2, 5, 6), "hh", "06"); 465 | testFormat("Hour 12 hour short 2", new Date(2001, 2, 5, 14), "h", "2"); 466 | testFormat("Hour 12 hour short noon", new Date(2001, 2, 5, 12), "h", "12"); 467 | testFormat("Hour 12 hour short midnight", new Date(2001, 2, 5, 0), "h", "12"); 468 | testFormat("Hour 12 hour padded 2", new Date(2001, 2, 5, 14), "hh", "02"); 469 | testFormat("Hour 12 hour padded noon", new Date(2001, 2, 5, 12), "hh", "12"); 470 | testFormat("Hour 12 hour padded midnight", new Date(2001, 2, 5, 0), "hh", "12"); 471 | testFormat("Hour 24 hour short", new Date(2001, 2, 5, 13), "H", "13"); 472 | testFormat("Hour 24 hour padded", new Date(2001, 2, 5, 13), "HH", "13"); 473 | testFormat("Hour 24 hour short", new Date(2001, 2, 5, 3), "H", "3"); 474 | testFormat("Hour 24 hour padded", new Date(2001, 2, 5, 3), "HH", "03"); 475 | 476 | // Minute 477 | testFormat("Minutes short", new Date(2001, 2, 5, 6, 7), "m", "7"); 478 | testFormat("Minutes padded", new Date(2001, 2, 5, 6, 7), "mm", "07"); 479 | 480 | // Seconds 481 | testFormat("Seconds short", new Date(2001, 2, 5, 6, 7, 2), "s", "2"); 482 | testFormat("Seconds padded", new Date(2001, 2, 5, 6, 7, 2), "ss", "02"); 483 | 484 | // Milliseconds 485 | testFormat("milliseconds short", new Date(2001, 2, 5, 6, 7, 2, 500), "S", "5"); 486 | testFormat("milliseconds short 2", new Date(2001, 2, 5, 6, 7, 2, 2), "S", "0"); 487 | testFormat( 488 | "milliseconds medium", 489 | new Date(2001, 2, 5, 6, 7, 2, 300), 490 | "SS", 491 | "30" 492 | ); 493 | testFormat( 494 | "milliseconds medium 2", 495 | new Date(2001, 2, 5, 6, 7, 2, 10), 496 | "SS", 497 | "01" 498 | ); 499 | testFormat("milliseconds long", new Date(2001, 2, 5, 6, 7, 2, 5), "SSS", "005"); 500 | 501 | // AM PM 502 | testFormat("ampm am", new Date(2001, 2, 5, 3, 7, 2, 5), "a", "am"); 503 | testFormat("ampm pm", new Date(2001, 2, 5, 15, 7, 2, 5), "a", "pm"); 504 | testFormat("ampm AM", new Date(2001, 2, 5, 3, 7, 2, 5), "A", "AM"); 505 | testFormat("ampm PM", new Date(2001, 2, 5, 16, 7, 2, 5), "A", "PM"); 506 | 507 | // th, st, nd, rd 508 | testFormat("th 11", new Date(2001, 2, 11), "Do", "11th"); 509 | testFormat("th 6", new Date(2001, 2, 6), "Do", "6th"); 510 | testFormat("st", new Date(2001, 2, 21), "Do", "21st"); 511 | testFormat("nd", new Date(2001, 2, 2), "Do", "2nd"); 512 | testFormat("rd", new Date(2001, 2, 23), "Do", "23rd"); 513 | 514 | // Timezone offset 515 | test("timezone offset", function() { 516 | assert(fecha.format(new Date(2001, 2, 11), "ZZ").match(/^[\+\-]\d{4}$/)); 517 | }); 518 | test("timezone offset with colon", function() { 519 | assert(fecha.format(new Date(2001, 2, 11), "Z").match(/^[\+\-]\d{2}:\d{2}$/)); 520 | }); 521 | 522 | // Random groupings 523 | testFormat( 524 | "MM-DD-YYYY HH:mm:ss", 525 | new Date(2001, 2, 5, 6, 7, 2, 5), 526 | "MM-DD-YYYY HH:mm:ss", 527 | "03-05-2001 06:07:02" 528 | ); 529 | testFormat( 530 | "MMMM D, YY", 531 | new Date(1987, 0, 8, 6, 7, 2, 5), 532 | "MMMM D, YY", 533 | "January 8, 87" 534 | ); 535 | testFormat( 536 | "M MMMM MM YYYY, YY", 537 | new Date(1987, 0, 8, 6, 7, 2, 5), 538 | "M MMMM MM YYYY, YY", 539 | "1 January 01 1987, 87" 540 | ); 541 | testFormat( 542 | "YYYY/MM/DD HH:mm:ss", 543 | new Date(2031, 10, 29, 2, 1, 9, 5), 544 | "YYYY/MM/DD HH:mm:ss", 545 | "2031/11/29 02:01:09" 546 | ); 547 | testFormat( 548 | "D-M-YYYY", 549 | new Date(2043, 8, 18, 2, 1, 9, 5), 550 | "D-M-YYYY", 551 | "18-9-2043" 552 | ); 553 | testFormat("current date", new Date(), "YYYY", "" + new Date().getFullYear()); 554 | testFormat("mask", new Date(1999, 0, 2), "mediumDate", "Jan 2, 1999"); 555 | testFormat("mask isoDate", new Date(1999, 0, 2), "isoDate", "1999-01-02"); 556 | testFormat( 557 | "mask isoDateTime", 558 | new Date(1999, 0, 2, 5, 7, 9), 559 | "isoDateTime", 560 | "1999-01-02T05:07:09+00:00" 561 | ); 562 | testFormat( 563 | "number date", 564 | 1325376000000, 565 | "YYY-MM-DD HH:mm:ss", 566 | fecha.format(new Date(Date.UTC(2012, 0, 1)), "YYY-MM-DD HH:mm:ss") 567 | ); 568 | testFormat("compact date format", new Date(2012, 4, 3), "YYYYMMDD", "20120503"); 569 | test("i18n am format", function() { 570 | assert.equal( 571 | fecha.format(new Date(2018, 4, 2, 10), "YYYY-MM-DD HHA", { 572 | amPm: ["sd", "gd"], 573 | DoFn: function() {} 574 | }), 575 | "2018-05-02 10SD" 576 | ); 577 | }); 578 | test("no format", function() { 579 | assert.equal( 580 | fecha.format(new Date(2017, 4, 2, 10)), 581 | "Tue May 02 2017 10:00:00" 582 | ); 583 | }); 584 | testFormat( 585 | "date with leading zeros", 586 | new Date(999, 0, 1), 587 | "YYYY/MM/DD", 588 | "0999/01/01" 589 | ); 590 | testFormat( 591 | "date with leading zeros short", 592 | new Date(999, 0, 1), 593 | "YY/MM/DD", 594 | "99/01/01" 595 | ); 596 | testFormat( 597 | "date with extra data in format", 598 | new Date(1963, 0, 1), 599 | "xxx YY/MM/DD xxx", 600 | "xxx 63/01/01 xxx" 601 | ); 602 | 603 | // Literals 604 | var date = new Date(2009, 1, 14, 15, 25, 50, 125); 605 | 606 | testFormat( 607 | "literal in format", 608 | date, 609 | "[on] MM-DD-YYYY [at] HH:mm", 610 | "on 02-14-2009 at 15:25" 611 | ); 612 | testFormat("one literal", date, "[day]", "day"); 613 | testFormat("two literals", date, "[day] YY [YY]", "day 09 YY"); 614 | testFormat("incomplete literal", date, "[YY", "[09"); 615 | testFormat("literal inside literal", date, "[[YY]]", "[YY]"); 616 | testFormat("bracket inside literal", date, "[[]", "["); 617 | testFormat("new lines", date, "YYYY[\n]DD[\n]", "2009\n14\n"); 618 | test("Invalid date", function() { 619 | assert.throws(function() { 620 | fecha.format("hello", "YYYY"); 621 | }); 622 | }); 623 | test("Invalid date number", function() { 624 | assert.throws(function() { 625 | fecha.format(89237983724982374, "YYYY"); 626 | }); 627 | }); 628 | test("string date", function() { 629 | assert.throws(function() { 630 | fecha.format("2011-10-01", "MM-DD-YYYY"); 631 | }); 632 | }); 633 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "noImplicitAny": true, 5 | "sourceMap": false, 6 | "declaration": true, 7 | "declarationDir": "lib", 8 | "outDir": "ts-out/" 9 | }, 10 | "include": [ 11 | "src/**/*" 12 | ], 13 | } --------------------------------------------------------------------------------