├── .editorconfig ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── bench ├── index.js └── package.json ├── license ├── package.json ├── readme.md ├── sort.d.ts ├── src └── index.js └── test └── index.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = tab 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.{json,yml,md}] 13 | indent_style = space 14 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | name: Node.js v${{ matrix.nodejs }} 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | nodejs: [8, 10, 12] 12 | steps: 13 | - uses: actions/checkout@master 14 | with: 15 | fetch-depth: 1 16 | 17 | - uses: actions/setup-node@v1 18 | with: 19 | node-version: ${{ matrix.nodejs }} 20 | 21 | - name: Install 22 | run: | 23 | npm install 24 | npm install -g nyc 25 | 26 | - name: Test w/ Coverage 27 | run: nyc --include=src npm test 28 | 29 | - name: Report 30 | if: matrix.nodejs >= 12 31 | run: | 32 | nyc report --reporter=text-lcov > coverage.lcov 33 | bash <(curl -s https://codecov.io/bash) 34 | env: 35 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | *-lock.json 4 | *.lock 5 | *.log 6 | 7 | /dist 8 | -------------------------------------------------------------------------------- /bench/index.js: -------------------------------------------------------------------------------- 1 | const { Suite } = require('benchmark'); 2 | const sorter = require('../dist'); 3 | 4 | function pad(str) { 5 | return str + ' '.repeat(32 - str.length); 6 | } 7 | 8 | function naiive(foo, bar) { 9 | return +foo - +bar; 10 | } 11 | 12 | const date_strings = [ 13 | '2012-01-02', '2020-03-07T05:51:07.746Z', 14 | '2020-01-19', '2020-03-07T05:50:41.107Z', 15 | '2020-03-07T05:50:48.726Z', '2001-12-31', 16 | '2002-03-07T05:51:07.746Z', '1990-02-01', 17 | ]; 18 | 19 | const date_values = date_strings.map(x => new Date(x)); 20 | 21 | new Suite() 22 | .on('cycle', e => { 23 | console.log(' ' + e.target); 24 | }) 25 | .add( 26 | pad('Date[] -> Number'), 27 | () => date_values.slice().sort(naiive) 28 | ) 29 | .add( 30 | pad('string[].map(Date) -> Number'), 31 | () => date_strings.map(x => new Date(x)).sort(naiive) 32 | ) 33 | .add( 34 | pad('string[] -> sort-isostring'), 35 | () => date_strings.slice().sort(sorter) 36 | ) 37 | .run(); 38 | -------------------------------------------------------------------------------- /bench/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "devDependencies": { 4 | "benchmark": "2.1.4" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Luke Edwards (lukeed.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0", 3 | "name": "sort-isostring", 4 | "repository": "lukeed/sort-isostring", 5 | "description": "A tiny (110B) utility to sort ISO 8601 Date strings", 6 | "unpkg": "dist/index.min.js", 7 | "module": "dist/index.mjs", 8 | "main": "dist/index.js", 9 | "types": "sort.d.ts", 10 | "license": "MIT", 11 | "author": { 12 | "name": "Luke Edwards", 13 | "email": "luke.edwards05@gmail.com", 14 | "url": "https://lukeed.com" 15 | }, 16 | "engines": { 17 | "node": ">=8" 18 | }, 19 | "scripts": { 20 | "build": "bundt", 21 | "pretest": "npm run build", 22 | "test": "tape -r esm test/*.js | tap-spec" 23 | }, 24 | "files": [ 25 | "*.d.ts", 26 | "dist" 27 | ], 28 | "keywords": [ 29 | "iso", 30 | "compare", 31 | "isostring", 32 | "iso 8601", 33 | "sorting", 34 | "date" 35 | ], 36 | "devDependencies": { 37 | "bundt": "1.0.0", 38 | "esm": "3.2.25", 39 | "tap-spec": "5.0.0", 40 | "tape": "4.9.1" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | > **ARCHIVED**
Unless you're working with _very_ old browsers or Node.js runtimes, you do not need this library!
A regular `arr.sort()` will work identically, and is now much faster.
If sorting by recency (latest first), please [beware of the gotchas](https://github.com/lukeed/sort-isostring/issues/1#issuecomment-647164151). 2 | 3 | # sort-isostring [![build status](https://badgen.net/github/status/lukeed/sort-isostring)](https://github.com/lukeed/sort-isostring/actions) [![codecov](https://badgen.now.sh/codecov/c/github/lukeed/sort-isostring)](https://codecov.io/gh/lukeed/sort-isostring) 4 | 5 | > A tiny (110B) and [fast](#benchmarks) utility to sort [ISO 8601](http://en.wikipedia.org/wiki/ISO_8601) Date strings 6 | 7 | Converting strings to `Date` instances is expensive.
Unless you _truly_ need a `Date` instance (or have one anyway), you're better off relying on string comparison logic.
Gone are wasteful days of parsing Dates just to determine a sort order. 8 | 9 | While ISO 8601 stirngs are preferred (see [`Date.prototype.toISOString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)), all you _really_ need is a `YYYY-MM-DD` prefix for safe LTR character comparisons. 10 | 11 | **Note:** Formats like `MM/DD/YYYY` and `DD-MM-YYYY` will yield incorrect results. 12 | 13 | This module is delivered as: 14 | 15 | * **CommonJS**: [`dist/index.js`](https://unpkg.com/sort-isostring/dist/index.js) 16 | * **ES Module**: [`dist/index.mjs`](https://unpkg.com/sort-isostring/dist/index.mjs) 17 | * **UMD**: [`dist/index.min.js`](https://unpkg.com/sort-isostring/dist/index.min.js) 18 | 19 | ## Install 20 | 21 | ``` 22 | $ npm install --save sort-isostring 23 | ``` 24 | 25 | 26 | ## Usage 27 | 28 | ```js 29 | import sorter from 'sort-isostring'; 30 | 31 | const articles = [ 32 | { updated: '2019-12-01' }, 33 | { updated: '2020-03-07T05:51:07.746Z' }, 34 | { updated: '2018-01-07T05:50:41.107Z' }, 35 | { updated: '2020-02-21' }, 36 | ]; 37 | 38 | // Sort: Oldest first 39 | articles.sort((x, y) => sorter(x.updated, y.updated)); 40 | console.log(articles.map(x => x.updated)); 41 | //=> [ '2018-01-07T05:50:41.107Z', '2019-12-01', 42 | //=> '2020-02-21', '2020-03-07T05:51:07.746Z' ] 43 | 44 | 45 | // Sort: Newest first (aka, recency) 46 | articles.sort((x, y) => sorter(y.updated, x.updated)); 47 | console.log(articles.map(x => x.updated)); 48 | //=> [ '2020-03-07T05:51:07.746Z', '2020-02-21', 49 | //=> '2019-12-01', '2018-01-07T05:50:41.107Z' ] 50 | ``` 51 | 52 | 53 | ## API 54 | 55 | ### sort(foo, bar) 56 | Returns: `Number` 57 | 58 | As with any comparison function, when comparing `foo` and `bar`: 59 | 60 | * A `0` is returned if the values are equal 61 | * A `-1` is returned if `foo` is less than `bar` 62 | * A `1` is returned if `foo` is greater than `bar` 63 | 64 | 65 | #### foo 66 | Type: `String` 67 | 68 | A Date string in ISO 8601 (or similar) format.
See [`Date.prototype.toISOString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString). 69 | 70 | > **Important:** The string format must be identical to `bar`'s format. 71 | 72 | #### bar 73 | Type: `String` 74 | 75 | A Date string in ISO 8601 (or similar) format.
See [`Date.prototype.toISOString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString). 76 | 77 | > **Important:** The string format must be identical to `foo`'s format. 78 | 79 | 80 | ## Benchmarks 81 | 82 | > Running on Node.js v10.13.0 83 | 84 | ``` 85 | Date[] -> Number x 322,876 ops/sec ±0.30% (96 runs sampled) 86 | string[].map(Date) -> Number x 194,208 ops/sec ±0.77% (95 runs sampled) 87 | string[] -> sort-isostring x 1,443,499 ops/sec ±1.22% (94 runs sampled) 88 | ``` 89 | 90 | ## Related 91 | 92 | - [tinydate](https://github.com/lukeed/tinydate) - An extremely quick, tiny (349B), and reusable date formatter. 93 | 94 | 95 | ## License 96 | 97 | MIT © [Luke Edwards](https://lukeed.com) 98 | -------------------------------------------------------------------------------- /sort.d.ts: -------------------------------------------------------------------------------- 1 | export default function (x: string, y: string): number; 2 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export default function (foo, bar) { 2 | var i=0, r=0; 3 | for (; i < bar.length; i++) { 4 | if (r = foo.charCodeAt(i) - bar.charCodeAt(i)) return r; 5 | } 6 | return r; 7 | } 8 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | import test from 'tape'; 2 | import sort from '../src'; 3 | 4 | test('exports', t => { 5 | t.is(typeof sort, 'function', 'exports function'); 6 | t.end(); 7 | }); 8 | 9 | 10 | test('returns :: foo < bar', t => { 11 | let output = sort('2020-01-19', '2020-02-01'); 12 | t.is(typeof output, 'number', 'returns a number'); 13 | t.is(output, -1, '~> returns `-1` because foo < bar'); 14 | t.end(); 15 | }); 16 | 17 | 18 | test('returns :: foo > bar', t => { 19 | let output = sort('2020-02-01', '2019-02-01'); 20 | t.is(typeof output, 'number', 'returns a number'); 21 | t.is(output, 1, '~> returns `1` because foo > bar'); 22 | t.end(); 23 | }); 24 | 25 | 26 | test('returns :: foo == bar', t => { 27 | let output = sort('2020-02-01', '2020-02-01'); 28 | t.is(typeof output, 'number', 'returns a number'); 29 | t.is(output, 0, '~> returns `0` because foo > bar'); 30 | t.end(); 31 | }); 32 | 33 | 34 | test('full :: foo < bar', t => { 35 | let date = new Date(); 36 | let foo = date.toISOString(); 37 | 38 | date.setDate(date.getDate() + 1); 39 | let bar = date.toISOString(); 40 | 41 | let output = sort(foo, bar); 42 | t.is(output, -1); 43 | 44 | t.end(); 45 | }); 46 | 47 | 48 | test('full :: foo > bar', t => { 49 | let date = new Date(); 50 | let bar = date.toISOString(); 51 | 52 | date.setDate(date.getDate() + 1); 53 | let foo = date.toISOString(); 54 | 55 | let output = sort(foo, bar); 56 | t.is(output, 1); 57 | 58 | t.end(); 59 | }); 60 | 61 | 62 | test('full :: foo == bar', t => { 63 | let date = new Date(); 64 | let foo = date.toISOString(); 65 | let bar = date.toISOString(); 66 | 67 | let output = sort(foo, bar); 68 | t.is(output, 0); 69 | 70 | t.end(); 71 | }); 72 | --------------------------------------------------------------------------------