├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .github └── workflows │ ├── node.js.yml │ └── publish.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── MIGRATION.md ├── README.md ├── README.ru.md ├── images ├── avatar.png └── picture.png ├── lib ├── addCalendarMonths.ts ├── addDays.ts ├── addHours.ts ├── addMinutes.ts ├── addMonths.ts ├── addYears.ts ├── constants │ └── index.ts ├── formatDate.ts ├── formatTimeString.ts ├── getDay.ts ├── getDiffInCalendarDays.ts ├── getDiffInCalendarMonths.ts ├── getDiffInCalendarYears.ts ├── getDiffInDays.ts ├── getDiffInHours.ts ├── getDiffInMinutes.ts ├── getDiffInMonths.ts ├── getDiffInYears.ts ├── getDuration.ts ├── getEndOfDay.ts ├── getEndOfDecade.ts ├── getEndOfHours.ts ├── getEndOfMinutes.ts ├── getEndOfMonth.ts ├── getEndOfWeek.ts ├── getEndOfYear.ts ├── getHours.ts ├── getMinutes.ts ├── getMonth.ts ├── getMonthName.ts ├── getRelativeDate.ts ├── getStartOfDay.ts ├── getStartOfDecade.ts ├── getStartOfHours.ts ├── getStartOfMinutes.ts ├── getStartOfMonth.ts ├── getStartOfWeek.ts ├── getStartOfYear.ts ├── getTimezoneName.ts ├── getUnixTimestamp.ts ├── getUtcOffset.ts ├── getWeekdayName.ts ├── getYear.ts ├── helpers │ ├── ensureDate.ts │ └── parseTime.ts ├── index.ts ├── isSameDay.ts ├── isSameHour.ts ├── isSameMinute.ts ├── isSameMonth.ts ├── isSameYear.ts ├── isTimeValid.ts ├── parseDate.ts ├── subtractCalendarMonths.ts ├── subtractDays.ts ├── subtractHours.ts ├── subtractMinutes.ts ├── subtractMonths.ts └── subtractYears.ts ├── package-lock.json ├── package.json ├── tests └── index.ts ├── tsconfig.eslint.json └── tsconfig.json /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | android >= 4.4.4 3 | ios >= 9 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | '@funboxteam', 4 | 'plugin:@typescript-eslint/recommended', 5 | 'plugin:@typescript-eslint/recommended-requiring-type-checking', 6 | ], 7 | ignorePatterns: ['.eslintrc.js'], 8 | parser: '@typescript-eslint/parser', 9 | parserOptions: { 10 | project: 'tsconfig.eslint.json', 11 | tsconfigRootDir: '.', 12 | }, 13 | plugins: ['@typescript-eslint'], 14 | rules: { 15 | 'no-useless-constructor': 'off', 16 | '@typescript-eslint/explicit-function-return-type': 'error', 17 | '@typescript-eslint/no-useless-constructor': 'error', 18 | '@typescript-eslint/no-use-before-define': 'off', 19 | '@typescript-eslint/prefer-includes': 'off', 20 | 'import/extensions': [ 21 | 'error', 22 | 'ignorePackages', 23 | { 24 | js: 'never', 25 | jsx: 'never', 26 | ts: 'never', 27 | tsx: 'never' 28 | } 29 | ] 30 | }, 31 | settings: { 32 | 'import/extensions': ['.ts'], 33 | 'import/parsers': { 34 | '@typescript-eslint/parser': ['.ts'], 35 | }, 36 | 'import/resolver': { 37 | node: { 38 | extensions:['.ts', '.js'], 39 | } 40 | } 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, 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 | test: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [14.x, 16.x, 18.x] 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | 28 | # npm of 14.x is not compatible with lockfileVersion 3, that's why we use `install` here instead of `ci` 29 | - if: matrix.node-version == '14.x' 30 | run: npm install 31 | - if: matrix.node-version != '14.x' 32 | run: npm ci 33 | 34 | - run: | 35 | npm test 36 | npm run coverage 37 | 38 | - name: Coveralls Parallel 39 | uses: coverallsapp/github-action@master 40 | with: 41 | github-token: ${{ secrets.GITHUB_TOKEN }} 42 | flag-name: run-${{ matrix.node-version }} 43 | parallel: true 44 | 45 | finish: 46 | needs: test 47 | runs-on: ubuntu-latest 48 | steps: 49 | - name: Coveralls Finished 50 | uses: coverallsapp/github-action@master 51 | with: 52 | github-token: ${{ secrets.GITHUB_TOKEN }} 53 | parallel-finished: true 54 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Package to npmjs 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | 7 | defaults: 8 | run: 9 | shell: bash 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: actions/setup-node@v3 17 | with: 18 | node-version: '18.15.0' 19 | registry-url: 'https://registry.npmjs.org' 20 | scope: '@funboxteam' 21 | - run: npm ci 22 | - run: npm publish 23 | env: 24 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # -- Node.js -- 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | 8 | # Dependency directory 9 | /node_modules 10 | 11 | # Optional npm cache directory 12 | .npm 13 | 14 | 15 | # -- IDEA -- 16 | /.idea 17 | 18 | ## File-based project format: 19 | *.ipr 20 | *.iws 21 | *.iml 22 | 23 | 24 | # -- Vim -- 25 | 26 | # swap 27 | [._]*.s[a-w][a-z] 28 | [._]s[a-w][a-z] 29 | 30 | # session 31 | Session.vim 32 | 33 | # temporary 34 | .netrwhist 35 | *~ 36 | /tmp 37 | 38 | 39 | # -- Eclipse -- 40 | *.swp 41 | 42 | 43 | # -- VSCode -- 44 | /.vscode 45 | jsconfig.json 46 | 47 | 48 | # -- OS X -- 49 | .DS_Store 50 | 51 | 52 | # -- Public -- 53 | /public 54 | 55 | 56 | # -- Tests -- 57 | /test-reports 58 | /screenshots 59 | /test-logs 60 | /.nyc_output 61 | 62 | 63 | # -- Sass -- 64 | .sass-cache 65 | 66 | # -- Linters -- 67 | .eslintcache 68 | .stylelintcache 69 | /pre-commit-hook.sh 70 | 71 | 72 | # -- Deploy -- 73 | /config/database.yml 74 | target.tar.gz 75 | 76 | # -- Dist -- 77 | /dist 78 | /coverage 79 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 5.0.3 (23.05.2023) 4 | 5 | Fixed the content of the package. 6 | 7 | Previous release introduced an additional layer of subdirectories, which ruined all the imports on users' projects. 8 | 9 | 10 | ## 5.0.2 (29.05.2023) 11 | 12 | Ensured Chronos supports Node.js 18. 13 | 14 | Improved types of `parseDate`: `format` always has been an optional param, but has not been marked as such. 15 | 16 | Improved type coercions in the internal functions. 17 | 18 | 19 | ## 5.0.1 (04.04.2023) 20 | 21 | Fixed `getStartOfMonth` which returned wrong value when the second argument is passed 22 | and the difference between the current and the desired month is not equal to 0. 23 | 24 | 25 | ## 5.0.0 (27.01.2023) 26 | 27 | Added alternative functions to deal with both full and calendar days, months, years. 28 | 29 | Removed `getWeek` function. 30 | 31 | Colsult the [migration guide](./MIGRATION.md) for more. 32 | 33 | 34 | ## 4.1.2 (13.12.2022) 35 | 36 | Fixed rounding issues for negative values in `getDiffInDays`, `getDiffInHours` & `getDiffInMinutes`. 37 | 38 | 39 | ## 4.1.1 (22.06.2022) 40 | 41 | Fixed `getRelativeDate` return value for dates related to February. 42 | 43 | Also fixed several security vulnerabilities. 44 | 45 | 46 | ## 4.1.0 (08.12.2021) 47 | 48 | Improved typings for `getWeekdayName` and `getMonthName`. 49 | 50 | 51 | ## 4.0.0 (09.11.2021) 52 | 53 | Dropped Node.js 12 support. 54 | 55 | 56 | ## 3.3.0 (16.09.2021) 57 | 58 | Added token `ZZ` to `formatDate`. 59 | 60 | 61 | ## 3.2.2 (10.06.2021) 62 | 63 | Improved `formatDate` for older browsers. 64 | 65 | 66 | ## 3.2.1 (10.06.2021) 67 | 68 | Fixed several security vulnerabilities: 69 | 70 | - [Prototype Pollution](https://github.com/advisories/GHSA-qqgx-2p2h-9c37) in [ini](https://github.com/npm/ini). Updated from 1.3.5 to 1.3.8. 71 | 72 | - [Prototype Pollution](https://github.com/advisories/GHSA-c4w7-xm78-47vh) in [y18n](https://github.com/yargs/y18n). Updated from 4.0.0 to 4.0.1. 73 | 74 | - [Use of a Broken or Risky Cryptographic Algorithm](https://github.com/advisories/GHSA-r9p9-mrjm-926w) in [elliptic](https://github.com/indutny/elliptic). Updated from 6.5.3 to 6.5.4. 75 | 76 | - [Regular Expression Denial of Service](https://github.com/advisories/GHSA-43f8-2h32-f4cj) in [hosted-git-info](https://github.com/npm/hosted-git-info). Updated from 2.8.8 to 2.8.9. 77 | 78 | - [Command Injection](https://github.com/advisories/GHSA-35jh-r3h4-6jhm) in [lodash](https://github.com/lodash/lodash). Updated from 4.17.20 to 4.17.21. 79 | 80 | - [Regular Expression Denial of Service](https://www.npmjs.com/advisories/1751) in [glob-parent](https://www.npmjs.com/package/glob-parent). Updated from 5.1.1 to 5.1.2. Also led to nodemon update from 1.19.4 to 2.0.7. 81 | 82 | 83 | ## 3.2.0 (30.09.2020) 84 | 85 | Removed @funboxteam/diamonds from the deps. Instead we inlined 86 | the only one fn used — `getPlural` in `getRelativeDate`. 87 | 88 | 89 | ## 3.1.0 (28.09.2020) 90 | 91 | Rewrote `subtract*` functions using `add*` functions. It has led to decreasing 92 | the total size of the lib. 93 | 94 | 95 | ## 3.0.1 (21.09.2020) 96 | 97 | Added `types` field into package.json to fix `tsc` errors and improve IDE's 98 | autocomplete. 99 | 100 | 101 | ## 3.0.0 (03.09.2020) 102 | 103 | **Breaking change:** `getTime` has been renamed to `getUnixTimestamp`. The function's param type definition has been updated too. 104 | 105 | Prepared the package for publishing on GitHub. Updated all the deps, added tests coverage & improved tests. 106 | 107 | Fixed `formatTimeString` hour formatting (`H`). 108 | 109 | Check out the [migration guide](./MIGRATION.md). 110 | 111 | ## 2.1.0 (03.08.2020) 112 | 113 | Removed core-js from peer dependencies. 114 | 115 | Improved types declaration. 116 | 117 | 118 | ## 2.0.0 (22.07.2020) 119 | 120 | The package has been rewritten to TypeScript. 121 | 122 | Also `formatTime` has been renamed to `formatTimeString`. 123 | 124 | Check out the [migration guide](./MIGRATION.md). 125 | 126 | 127 | ## 1.8.0 (30.06.2020) 128 | 129 | Added polyfills. 130 | 131 | 132 | ## 1.7.1 (07.04.2020) 133 | 134 | Fixed `getEndOfMonth`. Earlier it might return incorrect value when it was fired 135 | with `diff` param passed. 136 | 137 | 138 | ## 1.7.0 (14.02.2020) 139 | 140 | Made `format` param of `parseDate` optional. When it is not passed 141 | it the function tries to parse the passed string using `Date.parse`. 142 | 143 | 144 | ## 1.6.2 (10.02.2020) 145 | 146 | Fixed `getRelativeDate` several years interval calculation. 147 | 148 | 149 | ## 1.6.1 (10.02.2020) 150 | 151 | Fixed `HH` value calculation in `formatDate`. Earlier it returned `24` 152 | instead of `00` for the beginning of a day. 153 | 154 | 155 | ## 1.6.0 (07.02.2020) 156 | 157 | Added `MMM` template into `formatDate`, which allows to add 158 | short month name into the result string (e.g. `янв.`). 159 | 160 | 161 | ## 1.5.0 (05.02.2020) 162 | 163 | Added `Z` template into `formatDate` supported templates list, which allows to add 164 | timezone offset into the result string (it's formatted as `±HH:mm`). 165 | 166 | Fixed `getUtcOffset`. Earlier it returned only positive values. 167 | 168 | Fixed `getRelativeDate`. Now if the returned entity is the only one, 169 | there won't be a number in returned string. E.g. `минуту назад` 170 | instead of `1 минуту назад`. 171 | 172 | Added `getTimezoneName`. It returns timezone name (e.g. `Europe/Moscow`) 173 | using Intl API when it's possible. If it's not then fallback value returned. 174 | [The list of fallback values](./lib/constants/index.js) contains integer offsets only. 175 | 176 | So, if there's a user from Colombo (Shi Lanka) with modern browser, 177 | `Asia/Colombo` will be returned (+05:30). But if they use IE 11, then `Asia/Yekaterinburg` 178 | will be returned (+05:00). More precise values aren't used to prevent the lib bloating. 179 | But may be added in future. 180 | 181 | ## 1.4.0 (13.01.2020) 182 | 183 | Add second param (`format`) to `getMonthName` and `getWeekdayName`. 184 | It may has two values: `long` or `short` like those that used 185 | in [`Date.prototype.toLocaleString()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString) 186 | in `options.month` and `options.weekday` accordingly. 187 | 188 | Add many new functions: 189 | 190 | - `addHours`; 191 | - `addMinutes`; 192 | - `getEndOfHours`; 193 | - `getEndOfMinutes`; 194 | - `getHours`; 195 | - `getMinutes`; 196 | - `getStartOfHours`; 197 | - `getStartOfMinutes`; 198 | - `getWeek`; 199 | - `isSameHour`; 200 | - `isSameMinute`; 201 | - `subtractHours`; 202 | - `subtractMinutes`. 203 | 204 | 205 | ## 1.3.0 (23.12.2019) 206 | 207 | Added `getRelativeDate` & `getDiffInHours`. 208 | 209 | 210 | ## 1.2.1 (20.12.2019) 211 | 212 | Fixed `formatDate` for IE 11 and old Edges. 213 | 214 | 215 | ## 1.2.0 (04.12.2019) 216 | 217 | Added new functions: 218 | 219 | - `getStartOfWeek`; 220 | - `getEndOfWeek`; 221 | - `formatTime`; 222 | - `isTimeValid`; 223 | - `parseDate`. 224 | 225 | Also added seconds to the object returned by `getDuration`. 226 | 227 | 228 | ## 1.1.2 (29.10.2019) 229 | 230 | Fixed hours formatting in `formatDate` (sometimes `HH` returned one digit instead of two), 231 | and values rounding in `getDiffInDays` & `getDiffInMinutes`. 232 | 233 | 234 | ## 1.1.1 (24.10.2019) 235 | 236 | Replaced `Number.isNaN` with `isNaN`, because the first one doesn't work in IE11. 237 | 238 | 239 | ## 1.1.0 (21.10.2019) 240 | 241 | Added the possibility to pass Unix Timestamp as a string to every function that accepts date. 242 | 243 | Added new two functions: `getStartOfDecade` and `getEndOfDecade`. 244 | 245 | Renamed functions `getDiffOf*` to `getDiffIn*` (e.g. there was `getDiffOfMinutes`, 246 | and now it's `getDiffInMinutes`). It's a breaking change, but the library isn't used anywhere, 247 | so we're not releasing a major version. 248 | 249 | 250 | ## 1.0.2 (16.10.2019) 251 | 252 | Added flag `files` into package.json, to prevent useless files from putting into npm-package. 253 | 254 | 255 | ## 1.0.1 (16.10.2019) 256 | 257 | Removed flag `private: true` from package.json, to make it possible to publish the package. 258 | 259 | 260 | ## 1.0.0 (16.10.2019) 261 | 262 | Initial version. 263 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Natalia Andreychenko and other contributors 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 | -------------------------------------------------------------------------------- /MIGRATION.md: -------------------------------------------------------------------------------- 1 | # Migration 2 | 3 | ## 4.1.2 → 5.0.0 4 | 5 | If you used `getWeek`, then make sure you've replaced this function with your own implementation. 6 | 7 | If you used [`getDiffInMonths`](lib/getDiffInMonths.ts) or [`getDiffInYears`](lib/getDiffInYears.ts), 8 | then check their sources. Ensure that they work exactly as you expect. It's possible that instead you'd like to use 9 | [`getDiffInCalendarMonths`](lib/getDiffInCalendarMonths.ts) and [`getDiffInCalendarYears`](lib/getDiffInCalendarYears.ts). 10 | 11 | Everything else should work as before. 12 | 13 | 14 | ## 3.3.0 → 4.0.0 15 | 16 | Nothing changed. 17 | 18 | The lib works fine with Node.js 12, but we've dropped the support, so major version bump is here. 19 | 20 | 21 | ## 2.1.0 → 3.0.0 22 | 23 | If the project was using `getTime` then this function should be replaced with 24 | `getUnixTimestamp`. Also the first param of this function accepts `ChronosDate` instead of `Date`. 25 | 26 | 27 | ## 1.8.0 → 2.0.0 28 | 29 | If the project was using `formatTime` then this function should be replaced with 30 | `formatTimeString`. It's the same function but different name. 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | Chronos avatar: white-on-black gloomy antique half-human half-clock face 3 |
4 | 5 |
6 | 7 |
8 | 9 | npm 10 | 11 | 12 | 13 | CI status 14 | 15 | 16 | 17 | Code coverage 18 | 19 |
20 | 21 |
22 | Chronos is a tiny, immutable, typed date manipulation library which does not bloat your JS bundle,
23 | but does everything you need. 24 |
25 | 26 | ## Features 27 | 28 | Chronos picture: gloomy antique half-human half-clock carved in stone face 29 | 30 | - **Immutable & pure function per file.** Every function does not have side effects, nor mutates the params. 31 | If you use a function, only this function is added to your bundle, not the whole lib. 32 | - **ESM & CommonJS.** Works in Node.js and browser. Setup the target browsers for transpiling ES6 by your own in your bundler. 33 | - **TypeScript.** Every function is typed and the typings are bundled with the package. 34 | - **Native API.** Uses `Date` and `Intl` under the hood. 35 | - **Russian locale only.** And it has docs [in Russian](./README.ru.md). 36 | 37 | ## Rationale 38 | 39 | When we started to develop our projects, we picked the most popular date library that existed back then. 40 | We had used only two methods it provided, but got all the bundled ones, with all the possible locales. 41 | 42 | OK, we set up our bundler configs to remove those locales, but still that library was the biggest that we used, but the profit wasn't so huge. 43 | We decided to look around for the date library that we need, but all of them had a lot of features that we didn't want to use. 44 | 45 | So we replaced it with small and lightweight functions that just worked. 46 | Step by step those functions have evolved into Chronos—simple yet useful date manipulation library that works in every our project. 47 | 48 | 49 | ## Table of Contents 50 | 51 | - [Getting Started](#getting-started) 52 | - [Types](#types) 53 | - [ChronosDate](#chronosdate) 54 | - [Duration](#duration) 55 | - [Functions](#functions) 56 | - [addMinutes](#addminutes-addhours-adddays-addmonths-addcalendarmonths-addyears) 57 | - [addHours](#addminutes-addhours-adddays-addmonths-addcalendarmonths-addyears) 58 | - [addDays](#addminutes-addhours-adddays-addmonths-addcalendarmonths-addyears) 59 | - [addMonths](#addminutes-addhours-adddays-addmonths-addcalendarmonths-addyears) 60 | - [addCalendarMonths](#addminutes-addhours-adddays-addmonths-addcalendarmonths-addyears) 61 | - [addYears](#addminutes-addhours-adddays-addmonths-addcalendarmonths-addyears) 62 | - [subtractMinutes](#subtractminutes-subtracthours-subtractdays-subtractmonths-subtractcalendarmonths-subtractyears) 63 | - [subtractHours](#subtractminutes-subtracthours-subtractdays-subtractmonths-subtractcalendarmonths-subtractyears) 64 | - [subtractDays](#subtractminutes-subtracthours-subtractdays-subtractmonths-subtractcalendarmonths-subtractyears) 65 | - [subtractMonths](#subtractminutes-subtracthours-subtractdays-subtractmonths-subtractcalendarmonths-subtractyears) 66 | - [subtractCalendarMonths](#subtractminutes-subtracthours-subtractdays-subtractmonths-subtractcalendarmonths-subtractyears) 67 | - [subtractYears](#subtractminutes-subtracthours-subtractdays-subtractmonths-subtractcalendarmonths-subtractyears) 68 | - [formatDate](#formatdate) 69 | - [formatTimeString](#formattimestring) 70 | - [getMinutes](#getminutes-gethours-getday-getmonth-getyear) 71 | - [getHours](#getminutes-gethours-getday-getmonth-getyear) 72 | - [getDay](#getminutes-gethours-getday-getmonth-getyear) 73 | - [getMonth](#getminutes-gethours-getday-getmonth-getyear) 74 | - [getYear](#getminutes-gethours-getday-getmonth-getyear) 75 | - [getWeekdayName](#getweekdayname-getmonthname) 76 | - [getMonthName](#getweekdayname-getmonthname) 77 | - [getDuration](#getduration) 78 | - [isSameMinute](#issameminute-issamehour-issameday-issamemonth-issameyear) 79 | - [isSameHour](#issameminute-issamehour-issameday-issamemonth-issameyear) 80 | - [isSameDay](#issameminute-issamehour-issameday-issamemonth-issameyear) 81 | - [isSameMonth](#issameminute-issamehour-issameday-issamemonth-issameyear) 82 | - [isSameYear](#issameminute-issamehour-issameday-issamemonth-issameyear) 83 | - [getDiffInMinutes](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 84 | - [getDiffInHours](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 85 | - [getDiffInDays](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 86 | - [getDiffInCalendarDays](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 87 | - [getDiffInMonths](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 88 | - [getDiffInCalendarMonths](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 89 | - [getDiffInYears](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 90 | - [getDiffInCalendarYears](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 91 | - [getStartOfMinutes](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 92 | - [getStartOfHours](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 93 | - [getStartOfDay](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 94 | - [getStartOfWeek](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 95 | - [getStartOfMonth](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 96 | - [getStartOfYear](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 97 | - [getStartOfDecade](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 98 | - [getEndOfMinutes](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 99 | - [getEndOfHours](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 100 | - [getEndOfDay](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 101 | - [getEndOfWeek](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 102 | - [getEndOfMonth](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 103 | - [getEndOfYear](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 104 | - [getEndOfDecade](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 105 | - [getRelativeDate](#getrelativedate) 106 | - [getUtcOffset](#getutcoffset) 107 | - [getUnixTimestamp](#getunixtimestamp) 108 | - [getTimezoneName](#gettimezonename) 109 | - [isTimeValid](#istimevalid) 110 | - [parseDate](#parsedate) 111 | - [Credits](#credits) 112 | 113 | ## Getting Started 114 | 115 | Add the package into deps: 116 | 117 | ```bash 118 | npm install --save @funboxteam/chronos 119 | ``` 120 | 121 | Import functions: 122 | 123 | ```js 124 | import { addYears } from '@funboxteam/chronos'; 125 | ``` 126 | 127 | 128 | ## Types 129 | 130 | The library exports several types that may be used elsewhere, but the most important that they used inside the lib 131 | to guarantee type safety. 132 | 133 | ### ChronosDate 134 | 135 | ```typescript 136 | declare type ChronosDate = Date | number | string; 137 | ``` 138 | 139 | Every function that accepts date as a first param expects to get an instance of `Date`, or a timestamp as number or string. 140 | 141 | The timestamp may be present as seconds or milliseconds (e.g. `1596803254000` and `1596803254` is the same value). 142 | 143 | ### Duration 144 | 145 | ```typescript 146 | declare type Duration = { 147 | days: number; 148 | hours: number; 149 | minutes: number; 150 | seconds: number; 151 | }; 152 | ``` 153 | 154 | Type describing return value of functions that work with time intervals. 155 | 156 | ## Functions 157 | 158 | Every function is immutable and those which accept `Date` instances and return `Date` instance always return 159 | new `Date` instance and do not mutate the passed one. 160 | 161 | ### [addMinutes](./lib/addMinutes.ts), [addHours](./lib/addHours.ts), [addDays](./lib/addDays.ts), [addMonths](./lib/addMonths.ts), [addCalendarMonths](./lib/addCalendarMonths.ts), [addYears](./lib/addYears.ts) 162 | 163 | ```typescript 164 | (value: ChronosDate, quantity: number) => Date; 165 | ``` 166 | 167 | #### Params 168 | 169 | - `value`, date value; 170 | - `quantity`, number of units to add. 171 | 172 | #### Example 173 | 174 | ```js 175 | addDays(new Date('2020-01-01T00:00:00.000Z'), 1); // 2020-01-02T00:00:00.000Z 176 | 177 | // 1577836800 is 2020-01-01T00:00:00.000Z 178 | addYears(1577836800, 1); // 2021-01-01T00:00:00.000Z 179 | 180 | addMonths(new Date(2020, 0, 1), 1); // == new Date(2020, 1, 1); 181 | addMonths(new Date(2020, 0, 31), 1); // == new Date(2020, 2, 2); 182 | 183 | addCalendarMonths(new Date(2020, 0, 1), 1); // == new Date(2020, 1, 1); 184 | addCalendarMonths(new Date(2020, 0, 31), 1); // == new Date(2020, 1, 29); 185 | ``` 186 | 187 | ### [subtractMinutes](./lib/subtractMinutes.ts), [subtractHours](./lib/subtractHours.ts), [subtractDays](./lib/subtractDays.ts), [subtractMonths](./lib/subtractMonths.ts), [subtractCalendarMonths](./lib/subtractCalendarMonths.ts), [subtractYears](./lib/subtractYears.ts) 188 | 189 | ```typescript 190 | (value: ChronosDate, quantity: number) => Date; 191 | ``` 192 | 193 | #### Params 194 | 195 | - `value`, date value; 196 | - `quantity`, number of units to subtract. 197 | 198 | #### Example 199 | 200 | ```js 201 | subtractDays(new Date('2020-01-01T00:00:00.000Z'), 1); // 2019-12-31T00:00:00.000Z 202 | 203 | // 1577836800 is 2020-01-01T00:00:00.000Z 204 | subtractYears(1577836800, 1); // 2019-01-01T00:00:00.000Z 205 | 206 | subtractMonths(new Date(2020, 0, 1), 1); // == new Date(2019, 11, 1); 207 | subtractMonths(new Date(2020, 2, 31), 1); // == new Date(2020, 2, 2); 208 | 209 | subtractCalendarMonths(new Date(2020, 0, 1), 1); // == new Date(2019, 11, 1); 210 | subtractCalendarMonths(new Date(2020, 2, 31), 1); // == new Date(2020, 1, 29); 211 | ``` 212 | 213 | ### [formatDate](./lib/formatDate.ts) 214 | 215 | ```typescript 216 | (value: ChronosDate, format: string) => string; 217 | ``` 218 | 219 | #### Params 220 | 221 | - `value`, date value; 222 | - `format`, desired format. 223 | 224 | #### Available format tokens 225 | 226 | | Type | Token | Value | 227 | |:----------------|:-------|:------------------------------------------------| 228 | | Second | `ss` | 00, 01, 02, ..., 57, 58, 59 | 229 | | Minute | `mm` | 00, 01, 02, ..., 57, 58, 59 | 230 | | Hour | `HH` | 00, 01, 02, ..., 21, 22, 23 | 231 | | Day of Week | `dddd` | понедельник, вторник, ..., суббота, воскресенье | 232 | | Day of Month | `DD` | 01, 02, 03, ..., 29, 30, 31 | 233 | | | `D` | 1, 2, 3, ..., 29, 30, 31 | 234 | | Month | `MMMM` | январь, февраль, ..., ноябрь, декабрь | 235 | | | `MMM` | янв, фев, ..., ноя, дек | 236 | | | `MM` | 01, 02, 03, ..., 10, 11, 12 | 237 | | Year | `YYYY` | Full year, e.g.: 1885, 1955, 1985, 2015 | 238 | | | `YY` | 00, 01, 02, ..., 97, 98, 99 | 239 | | UTC time offset | `ZZ` | -1200, -1100, ..., +1300, +1400 | 240 | | | `Z` | -12:00, -11:00, ..., +13:00, +14:00 | 241 | 242 | #### Example 243 | 244 | ```js 245 | formatDate(new Date(2020, 0, 1), 'YYYY-MM-DDTHH:mm:ssZ'); // '2020-01-01T00:00:00+03:00' (for GMT+3) 246 | 247 | // 1577836800 is 2020-01-01T00:00:00.000Z 248 | formatDate(1577836800, 'HH:mm:ss'); // '03:00:00' (for GMT+3) 249 | ``` 250 | 251 | #### Important notes 252 | 253 | Only Russian locale is supported for now! 254 | 255 | 256 | ### [formatTimeString](./lib/formatTimeString.ts) 257 | 258 | ```typescript 259 | (value: string, valueFormat: string, format: string) => string; 260 | ``` 261 | 262 | #### Params 263 | 264 | - `value`, time string; 265 | - `valueFormat`, template describing `value` format; 266 | - `format`, desired format. 267 | 268 | #### Available format tokens 269 | 270 | | Type | Token | Value | 271 | |:-------|:------|:----------------------------| 272 | | Second | `ss` | 00, 01, 02, ..., 57, 58, 59 | 273 | | Minute | `mm` | 00, 01, 02, ..., 57, 58, 59 | 274 | | Hour | `HH` | 00, 01, 02, ..., 21, 22, 23 | 275 | | | `H` | 0, 1, 2, ..., 21, 22, 23 | 276 | 277 | #### Example 278 | 279 | ```js 280 | formatTimeString('22:00', 'HH:mm', 'HH:mm:ss'); // '22:00:00' 281 | ``` 282 | 283 | 284 | ### [getMinutes](./lib/getMinutes.ts), [getHours](./lib/getHours.ts), [getDay](./lib/getDay.ts), [getMonth](./lib/getMonth.ts), [getYear](./lib/getYear.ts) 285 | 286 | ```typescript 287 | (value: ChronosDate) => number; 288 | ``` 289 | 290 | #### Params 291 | 292 | - `value`, date value. 293 | 294 | #### Example 295 | 296 | ```js 297 | getDay(new Date(2020, 0, 1)); // 1; 298 | 299 | // 1577836800 is 2020-01-01T00:00:00.000Z 300 | getYear(1577836800); // 2020 301 | ``` 302 | 303 | ### [getWeekdayName](./lib/getWeekdayName.ts), [getMonthName](./lib/getMonthName.ts) 304 | 305 | ```typescript 306 | (value: ChronosDate, format?: string) => string; 307 | ``` 308 | 309 | #### Params 310 | 311 | - `value`, date value; 312 | - `format`, format of the returned string. `'long'` (by default) or `'short'`. 313 | 314 | #### Example 315 | 316 | ```js 317 | getWeekdayName(new Date(2020, 11, 30)); // 'среда' (11th month in JS is December) 318 | getWeekdayName(new Date(2020, 11, 30), 'short'); // 'ср' 319 | getMonthName(new Date(2020, 0, 1)); // 'январь' 320 | getMonthName(new Date(2020, 0, 1), 'short'); // 'янв' 321 | ``` 322 | 323 | 324 | ### [getDuration](./lib/getDuration.ts) 325 | 326 | ```typescript 327 | (seconds: number) => Duration; 328 | ``` 329 | 330 | ### Params 331 | 332 | - `seconds`, interval value in seconds. 333 | 334 | #### Example 335 | 336 | ```js 337 | getDuration(1000000); // { days: 11, hours: 13, minutes: 46, seconds: 40 } 338 | ``` 339 | 340 | 341 | ### [isSameMinute](./lib/isSameMinute.ts), [isSameHour](./lib/isSameHour.ts), [isSameDay](./lib/isSameDay.ts), [isSameMonth](./lib/isSameMonth.ts), [isSameYear](./lib/isSameYear.ts) 342 | 343 | ```typescript 344 | (firstValue: ChronosDate, secondValue: ChronosDate) => boolean; 345 | ``` 346 | 347 | #### Params 348 | 349 | - `firstValue`, date value; 350 | - `secondValue`, date value. 351 | 352 | #### Example 353 | 354 | ```js 355 | // 1577750400 is 2019-12-31T00:00:00.000Z 356 | // 1577836800 is 2020-01-01T00:00:00.000Z 357 | isSameYear(1577750400, 1577836800); // false 358 | ``` 359 | 360 | 361 | ### [getDiffInMinutes](./lib/getDiffInMinutes.ts), [getDiffInHours](./lib/getDiffInHours.ts), [getDiffInDays](./lib/getDiffInDays.ts), [getDiffInCalendarDays](./lib/getDiffInCalendarDays.ts), [getDiffInMonths](./lib/getDiffInMonths.ts), [getDiffInCalendarMonths](./lib/getDiffInCalendarMonths.ts), [getDiffInYears](./lib/getDiffInYears.ts), [getDiffInCalendarYears](./lib/getDiffInCalendarYears.ts) 362 | 363 | ```typescript 364 | (firstValue: ChronosDate, secondValue: ChronosDate) => number; 365 | ``` 366 | 367 | #### Params 368 | 369 | - `firstValue`, date value; 370 | - `secondValue`, date value. 371 | 372 | #### Example 373 | 374 | ```js 375 | // 1577750400 is 2019-12-31T00:00:00.000Z 376 | // 1577836800 is 2020-01-01T00:00:00.000Z 377 | getDiffInDays(1577750400, 1577836800); // -1 378 | ``` 379 | 380 | 381 | ### [getStartOfMinutes](./lib/getStartOfMinutes.ts), [getStartOfHours](./lib/getStartOfHours.ts), [getStartOfDay](./lib/getStartOfDay.ts), [getStartOfWeek](./lib/getStartOfWeek), [getStartOfMonth](./lib/getStartOfMonth.ts), [getStartOfYear](./lib/getStartOfYear.ts), [getStartOfDecade](./lib/getStartOfDecade.ts) 382 | 383 | ```typescript 384 | (value: ChronosDate, diff?: number) => Date; 385 | ``` 386 | 387 | #### Params 388 | - `value`, date value; 389 | - `diff`, number of units to add to the result date. `0` by default. 390 | 391 | #### Example 392 | 393 | ```js 394 | // 1577836800 is 2020-01-01T00:00:00.000Z 395 | getStartOfDay(1577836800); // 2019-12-31T21:00:00.000Z (for GMT+3) 396 | getStartOfDay(1577836800, 1); // 2020-01-01T21:00:00.000Z (for GMT+3) 397 | getStartOfDay(1577836800, -1); // 2019-12-30T21:00:00.000Z (for GMT+3) 398 | ``` 399 | 400 | 401 | ### [getEndOfMinutes](./lib/getEndOfMinutes.ts), [getEndOfHours](./lib/getEndOfHours.ts), [getEndOfDay](./lib/getEndOfDay.ts), [getEndOfWeek](./lib/getEndOfWeek.ts), [getEndOfMonth](./lib/getEndOfMonth.ts), [getEndOfYear](./lib/getEndOfYear.ts), [getEndOfDecade](./lib/getEndOfDecade.ts) 402 | 403 | ```typescript 404 | (value: ChronosDate, diff?: number) => Date; 405 | ``` 406 | 407 | #### Params 408 | - `value`, date value; 409 | - `diff`, number of units to add to the result date. `0` by default. 410 | 411 | #### Example 412 | 413 | ```js 414 | // 1577836800 is 2020-01-01T00:00:00.000Z 415 | getEndOfDay(1577836800); // 2020-01-01T20:59:59.999Z (for GMT+3) 416 | getEndOfDay(1577836800, 1); // 2020-01-02T20:59:59.999Z (for GMT+3) 417 | getEndOfDay(1577836800, -1); // 2019-12-31T20:59:59.999Z (for GMT+3) 418 | ``` 419 | 420 | 421 | ### [getRelativeDate](./lib/getRelativeDate.ts) 422 | 423 | ```typescript 424 | (value: ChronosDate) => string; 425 | ``` 426 | 427 | #### Params 428 | 429 | - `value`, date value. 430 | 431 | #### Example 432 | 433 | ```js 434 | getRelativeDate(1577081613); // '2 месяца' (for 07.02.2020) 435 | getRelativeDate(new Date()); // 'меньше минуты' 436 | ``` 437 | 438 | 439 | ### [getUtcOffset](./lib/getUtcOffset.ts) 440 | 441 | ```typescript 442 | (value: ChronosDate) => number; 443 | ``` 444 | 445 | #### Params 446 | 447 | - `value`, date value. 448 | 449 | #### Example 450 | 451 | ```js 452 | getUtcOffset(new Date(2020, 0, 1)); // 3 (for GMT+3) 453 | ``` 454 | 455 | 456 | ### [getUnixTimestamp](./lib/getUnixTimestamp.ts) 457 | 458 | ```typescript 459 | (date?: Date) => number; 460 | ``` 461 | 462 | #### Params 463 | 464 | - `date`, Date instance. `new Date()` by default. 465 | 466 | #### Example 467 | 468 | ```js 469 | // now is 2020-02-07T08:26:59.422Z 470 | getUnixTimestamp(); // 1581064019 (unix timestamp for new Date()) 471 | 472 | getUnixTimestamp(new Date(2020, 0, 1)); // 1577826000 (for GMT+3) 473 | ``` 474 | 475 | 476 | ### [getTimezoneName](./lib/getTimezoneName.ts) 477 | 478 | ```typescript 479 | () => string; 480 | ``` 481 | 482 | #### Example 483 | 484 | ```js 485 | getTimezoneName(); // 'Europe/Moscow' (for any GMT+3 timezone in IE11 and for MSK in modern browsers) 486 | ``` 487 | 488 | #### Important notes 489 | 490 | In case of lack of Intl API support returns nearest to the user timezone 491 | which has _integer hours offset_. 492 | 493 | 494 | ### [isTimeValid](./lib/isTimeValid.ts) 495 | 496 | ```typescript 497 | (value: string, format: string) => boolean; 498 | ``` 499 | 500 | #### Params 501 | 502 | - `value`, time string; 503 | - `format`, format string that should be used for validation. 504 | 505 | #### Example 506 | 507 | ```js 508 | isTimeValid('22:30', 'HH:mm'); // true 509 | ``` 510 | 511 | 512 | ### [parseDate](./lib/parseDate.ts) 513 | 514 | ```typescript 515 | (value: string, format: string) => Date; 516 | ``` 517 | 518 | #### Params 519 | 520 | - `value`, date string; 521 | - `format`, format string that should be used for parsing. 522 | 523 | #### Available format tokens 524 | 525 | | Type | Token | Recognized values | 526 | |:-------------|:-------|:----------------------------------------| 527 | | Day of Month | `DD` | 01, 02, 03, ..., 29, 30, 31 | 528 | | | `D` | 1, 2, 3, ..., 29, 30, 31 | 529 | | Month | `MM` | 01, 02, 03, ..., 10, 11, 12 | 530 | | Year | `YYYY` | Full year, e.g.: 1885, 1955, 1985, 2015 | 531 | | | `YY` | 00, 01, 02, ..., 97, 98, 99 | 532 | 533 | #### Example 534 | 535 | ```js 536 | parseDate('2000-01-21', 'YYYY-MM-DD'); // == new Date(2000, 0, 21) 537 | parseDate('2020-01-01T00:00:00+03:00'); // == new Date(2020, 0, 1) (for GMT+3) 538 | ``` 539 | 540 | #### Important notes 541 | 542 | If `format` is not passed it tries to parse `value` using native 543 | `Date.parse`. It should support ISO 8601 and RFC 2822. Other formats 544 | are not recommended to parse without explicit `format` set. 545 | 546 | 547 | ## Credits 548 | 549 | Project's pictures were made by [Igor Garybaldi](https://pandabanda.com/). 550 | 551 | 552 | [![Sponsored by FunBox](https://funbox.ru/badges/sponsored_by_funbox_grayscale.svg)](https://funbox.ru) 553 | -------------------------------------------------------------------------------- /README.ru.md: -------------------------------------------------------------------------------- 1 |
2 | Аватар Хроноса: выполненное в чёрно-белом стиле изображение грозного античного лица полу-человека полу-часов 3 |
4 | 5 |
6 | 7 |
8 | 9 | npm 10 | 11 | 12 | 13 | CI status 14 | 15 | 16 | 17 | Code coverage 18 | 19 |
20 | 21 |
22 | Хронос — небольшая иммутабельная типизированная библиотека для работы с датами.
23 | Содержит всё необходимое и не раздувает бандл. 24 |
25 | 26 | ## Features 27 | 28 | КДПВ Хроноса: высеченное в камне грозное античное лицо полу-человека полу-часов 29 | 30 | - **Иммутабельные и чистые функции.** Каждая из них хранится в отдельном файле, не содержит сайд-эффектов, не мутирует параметры. 31 | При импорте функции в бандл добавляется только то, что необходимо для её работы, и ничего более. 32 | - **ESM & CommonJS.** Работает c Node.js и в браузере. Настройте самостоятельно список поддерживаемых браузеров для транспиляции ES6, чтобы получить минимальный набор полифиллов. 33 | - **TypeScript.** Каждая функция типизирована, и все типы поставляются вместе с пакетом. 34 | - **Нативное АПИ.** Использует `Date` и `Intl` под капотом. 35 | - **Только русская локаль.** Чтобы не добавлять ничего лишнего. 36 | 37 | ## Мотивация 38 | 39 | Давным-давно, когда мы начинали разрабатывать наши фронтенд-проекты, мы выбрали самую популярную на тот момент библиотеку для работы с датами. 40 | Мы использовали всего несколько методов, которые она предоставляла, но в бандл попали все существующие в ней, а в довесок и все имеющиеся локали. 41 | 42 | Тогда мы настроили конфиги бандлера таким обарзом, чтобы он вырезал эти локали. Однако, та библиотека всё ещё была самой большой из тех, 43 | что мы использовали, но пользы от неё было совсем немного. 44 | Мы попробовали поискать библиотеку, которая бы решала необходимые нам задачи, и при этом была бы небольшой и с удобным АПИ, но таковых не нашлось. 45 | 46 | Потому мы просто написали несколько небольших функций, которые делали дело. 47 | А со временем этот набор функций разросся и превратился в Хроноса — простую, но удобную библиотеку для работы с датами, которая работает в каждом нашем проекте. 48 | 49 | 50 | ## Содержание 51 | 52 | - [Установка и использование](#установка-и-использование) 53 | - [Типы](#типы) 54 | - [ChronosDate](#chronosdate) 55 | - [Duration](#duration) 56 | - [Функции](#функции) 57 | - [addMinutes](#addminutes-addhours-adddays-addmonths-addcalendarmonths-addyears) 58 | - [addHours](#addminutes-addhours-adddays-addmonths-addcalendarmonths-addyears) 59 | - [addDays](#addminutes-addhours-adddays-addmonths-addcalendarmonths-addyears) 60 | - [addMonths](#addminutes-addhours-adddays-addmonths-addcalendarmonths-addyears) 61 | - [addCalendarMonths](#addminutes-addhours-adddays-addmonths-addcalendarmonths-addyears) 62 | - [addYears](#addminutes-addhours-adddays-addmonths-addcalendarmonths-addyears) 63 | - [subtractMinutes](#subtractminutes-subtracthours-subtractdays-subtractmonths-subtractcalendarmonths-subtractyears) 64 | - [subtractHours](#subtractminutes-subtracthours-subtractdays-subtractmonths-subtractcalendarmonths-subtractyears) 65 | - [subtractDays](#subtractminutes-subtracthours-subtractdays-subtractmonths-subtractcalendarmonths-subtractyears) 66 | - [subtractMonths](#subtractminutes-subtracthours-subtractdays-subtractmonths-subtractcalendarmonths-subtractyears) 67 | - [subtractCalendarMonths](#subtractminutes-subtracthours-subtractdays-subtractmonths-subtractcalendarmonths-subtractyears) 68 | - [subtractYears](#subtractminutes-subtracthours-subtractdays-subtractmonths-subtractcalendarmonths-subtractyears) 69 | - [formatDate](#formatdate) 70 | - [formatTimeString](#formattimestring) 71 | - [getMinutes](#getminutes-gethours-getday-getmonth-getyear) 72 | - [getHours](#getminutes-gethours-getday-getmonth-getyear) 73 | - [getDay](#getminutes-gethours-getday-getmonth-getyear) 74 | - [getMonth](#getminutes-gethours-getday-getmonth-getyear) 75 | - [getYear](#getminutes-gethours-getday-getmonth-getyear) 76 | - [getWeekdayName](#getweekdayname-getmonthname) 77 | - [getMonthName](#getweekdayname-getmonthname) 78 | - [getDuration](#getduration) 79 | - [isSameMinute](#issameminute-issamehour-issameday-issamemonth-issameyear) 80 | - [isSameHour](#issameminute-issamehour-issameday-issamemonth-issameyear) 81 | - [isSameDay](#issameminute-issamehour-issameday-issamemonth-issameyear) 82 | - [isSameMonth](#issameminute-issamehour-issameday-issamemonth-issameyear) 83 | - [isSameYear](#issameminute-issamehour-issameday-issamemonth-issameyear) 84 | - [getDiffInMinutes](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 85 | - [getDiffInHours](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 86 | - [getDiffInDays](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 87 | - [getDiffInCalendarDays](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 88 | - [getDiffInMonths](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 89 | - [getDiffInCalendarMonths](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 90 | - [getDiffInYears](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 91 | - [getDiffInCalendarYears](#getdiffinminutes-getdiffinhours-getdiffindays-getdiffincalendardays-getdiffinmonths-getdiffincalendarmonths-getdiffinyears-getdiffincalendaryears) 92 | - [getStartOfMinutes](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 93 | - [getStartOfHours](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 94 | - [getStartOfDay](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 95 | - [getStartOfWeek](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 96 | - [getStartOfMonth](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 97 | - [getStartOfYear](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 98 | - [getStartOfDecade](#getstartofminutes-getstartofhours-getstartofday-getstartofweek-getstartofmonth-getstartofyear-getstartofdecade) 99 | - [getEndOfMinutes](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 100 | - [getEndOfHours](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 101 | - [getEndOfDay](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 102 | - [getEndOfWeek](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 103 | - [getEndOfMonth](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 104 | - [getEndOfYear](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 105 | - [getEndOfDecade](#getendofminutes-getendofhours-getendofday-getendofweek-getendofmonth-getendofyear-getendofdecade) 106 | - [getRelativeDate](#getrelativedate) 107 | - [getUtcOffset](#getutcoffset) 108 | - [getUnixTimestamp](#getunixtimestamp) 109 | - [getTimezoneName](#gettimezonename) 110 | - [isTimeValid](#istimevalid) 111 | - [parseDate](#parsedate) 112 | - [Благодарности](#благодарности) 113 | 114 | ## Установка и использование 115 | 116 | Добавить пакет в зависимости проекта: 117 | 118 | ```bash 119 | npm install --save @funboxteam/chronos 120 | ``` 121 | 122 | Импортировать необходимые функции в JS: 123 | 124 | ```bash 125 | import { addDate } from '@funboxteam/chronos'; 126 | ``` 127 | 128 | ## Типы 129 | 130 | Библиотека экспортирует несколько типов, доступных для использования где угодно. Но, что более важно, они используются 131 | внутри для обеспечения одинакового поведения функций. 132 | 133 | ### ChronosDate 134 | 135 | ```typescript 136 | declare type ChronosDate = Date | number | string; 137 | ``` 138 | 139 | Каждая функция, которая принимает дату в качестве первого параметра, ожидает получить или инстанс `Date`, 140 | или временную метку в виде строки или числа. 141 | 142 | Временная метка может быть выражена как в секундах, так и в миллисекундах (т. е. `1596803254000` и `1596803254` — одно и то же значение). 143 | 144 | ## Duration 145 | 146 | ```typescript 147 | declare type Duration = { 148 | days: number; 149 | hours: number; 150 | minutes: number; 151 | seconds: number; 152 | }; 153 | ``` 154 | 155 | Тип, описывающий возвращаемое значение функций, которые работают временными интервалами. 156 | 157 | ## Функции 158 | 159 | Каждая функция иммутабельна, а потому если передать в них инстанс `Date`, они всегда вернут новый инстанс `Date`, 160 | и не будут изменять переданный. 161 | 162 | ### [addMinutes](./lib/addMinutes.ts), [addHours](./lib/addHours.ts), [addDays](./lib/addDays.ts), [addMonths](./lib/addMonths.ts), [addCalendarMonths](./lib/addCalendarMonths.ts), [addYears](./lib/addYears.ts) 163 | 164 | ```typescript 165 | (value: ChronosDate, quantity: number) => Date; 166 | ``` 167 | 168 | #### Параметры 169 | 170 | - `value`, дата; 171 | - `quantity`, количество единиц, которые нужно добавить. 172 | 173 | #### Пример 174 | 175 | ```js 176 | addDays(new Date('2020-01-01T00:00:00.000Z'), 1); // 2020-01-02T00:00:00.000Z 177 | 178 | // 1577836800 — это 2020-01-01T00:00:00.000Z 179 | addYears(1577836800, 1); // 2021-01-01T00:00:00.000Z 180 | 181 | addMonths(new Date(2020, 0, 1), 1); // == new Date(2020, 1, 1); 182 | addMonths(new Date(2020, 0, 31), 1); // == new Date(2020, 2, 2); 183 | 184 | addCalendarMonths(new Date(2020, 0, 1), 1); // == new Date(2020, 1, 1); 185 | addCalendarMonths(new Date(2020, 0, 31), 1); // == new Date(2020, 1, 29); 186 | ``` 187 | 188 | ### [subtractMinutes](./lib/subtractMinutes.ts), [subtractHours](./lib/subtractHours.ts), [subtractDays](./lib/subtractDays.ts), [subtractMonths](./lib/subtractMonths.ts), [subtractCalendarMonths](./lib/subtractCalendarMonths.ts), [subtractYears](./lib/subtractYears.ts) 189 | 190 | ```typescript 191 | (value: ChronosDate, quantity: number) => Date; 192 | ``` 193 | 194 | #### Параметры 195 | 196 | - `value`, дата; 197 | - `quantity`, количество единиц, которые нужно вычесть. 198 | 199 | #### Пример 200 | 201 | ```js 202 | subtractDays(new Date('2020-01-01T00:00:00.000Z'), 1); // 2019-12-31T00:00:00.000Z 203 | 204 | // 1577836800 — это 2020-01-01T00:00:00.000Z 205 | subtractYears(1577836800, 1); // 2019-01-01T00:00:00.000Z 206 | 207 | subtractMonths(new Date(2020, 0, 1), 1); // == new Date(2019, 11, 1); 208 | subtractMonths(new Date(2020, 2, 31), 1); // == new Date(2020, 2, 2); 209 | 210 | subtractCalendarMonths(new Date(2020, 0, 1), 1); // == new Date(2019, 11, 1); 211 | subtractCalendarMonths(new Date(2020, 2, 31), 1); // == new Date(2020, 1, 29); 212 | ``` 213 | 214 | ### [formatDate](./lib/formatDate.ts) 215 | 216 | ```typescript 217 | (value: ChronosDate, format: string) => string; 218 | ``` 219 | 220 | #### Параметры 221 | 222 | - `value`, дата; 223 | - `format`, желаемый формат. 224 | 225 | #### Доступные ключи в формате 226 | 227 | | Тип | Ключ | Значение | 228 | |:-----------|:-------|:------------------------------------------------| 229 | | Секунды | `ss` | 00, 01, 02, ..., 57, 58, 59 | 230 | | Минуты | `mm` | 00, 01, 02, ..., 57, 58, 59 | 231 | | Часы | `HH` | 00, 01, 02, ..., 21, 22, 23 | 232 | | Дни недели | `dddd` | понедельник, вторник, ..., суббота, воскресенье | 233 | | Дни месяца | `DD` | 01, 02, 03, ..., 29, 30, 31 | 234 | | | `D` | 1, 2, 3, ..., 29, 30, 31 | 235 | | Месяцы | `MMMM` | январь, февраль, ..., ноябрь, декабрь | 236 | | | `MMM` | янв, фев, ..., ноя, дек | 237 | | | `MM` | 01, 02, 03, ..., 10, 11, 12 | 238 | | Годы | `YYYY` | Полный год, т. е.: 1885, 1955, 1985, 2015 | 239 | | | `YY` | 00, 01, 02, ..., 97, 98, 99 | 240 | | Смещение | `ZZ` | -1200, -1100, ..., +1300, +1400 | 241 | | | `Z` | -12:00, -11:00, ..., +13:00, +14:00 | 242 | 243 | #### Пример 244 | 245 | ```js 246 | formatDate(new Date(2020, 0, 1), 'YYYY-MM-DDTHH:mm:ssZ'); // '2020-01-01T00:00:00+03:00' (для GMT+3) 247 | 248 | // 1577836800 — это 2020-01-01T00:00:00.000Z 249 | formatDate(1577836800, 'HH:mm:ss'); // '03:00:00' (для GMT+3) 250 | ``` 251 | 252 | #### Важное замечание 253 | 254 | На текущий момент поддерживается только русская локаль! 255 | 256 | 257 | ### [formatTimeString](./lib/formatTimeString.ts) 258 | 259 | ```typescript 260 | (value: string, valueFormat: string, format: string) => string; 261 | ``` 262 | 263 | #### Параметры 264 | 265 | - `value`, время; 266 | - `valueFormat`, шаблон, описывающий формат `value`; 267 | - `format`, желаемый формат. 268 | 269 | #### Доступные ключи в формате 270 | 271 | | Тип | Ключ | Значение | 272 | |:--------|:-----|:----------------------------| 273 | | Секунды | `ss` | 00, 01, 02, ..., 57, 58, 59 | 274 | | Минуты | `mm` | 00, 01, 02, ..., 57, 58, 59 | 275 | | Часы | `HH` | 00, 01, 02, ..., 21, 22, 23 | 276 | | | `H` | 0, 1, 2, ..., 21, 22, 23 | 277 | 278 | #### Пример 279 | 280 | ```js 281 | formatTime('22:00', 'HH:mm', 'HH:mm:ss'); // '22:00:00' 282 | ``` 283 | 284 | 285 | ### [getMinutes](./lib/getMinutes.ts), [getHours](./lib/getHours.ts), [getDay](./lib/getDay.ts), [getMonth](./lib/getMonth.ts), [getYear](./lib/getYear.ts) 286 | 287 | ```typescript 288 | (value: ChronosDate) => number; 289 | ``` 290 | 291 | #### Параметры 292 | 293 | - `value`, дата. 294 | 295 | #### Пример 296 | 297 | ```js 298 | getDay(new Date(2020, 0, 1)); // 1; 299 | 300 | // 1577836800 — это 2020-01-01T00:00:00.000Z 301 | getYear(1577836800); // 2020 302 | ``` 303 | 304 | 305 | ### [getWeekdayName](./lib/getWeekdayName.ts), [getMonthName](./lib/getMonthName.ts) 306 | 307 | ```typescript 308 | (value: ChronosDate, format?: string) => string; 309 | ``` 310 | 311 | #### Параметры 312 | 313 | - `value`, дата; 314 | - `format`, формат возвращаемой строки. По умолчанию длинный (`'long'`), может быть короткий (`'short'`). 315 | 316 | #### Пример 317 | 318 | ```js 319 | getWeekdayName(new Date(2020, 11, 30)); // 'среда' (11-й месяц в JS — это декабрь) 320 | getWeekdayName(new Date(2020, 11, 30), 'short'); // 'ср' 321 | getMonthName(new Date(2020, 0, 1)); // 'январь' 322 | getMonthName(new Date(2020, 0, 1), 'short'); // 'янв' 323 | ``` 324 | 325 | 326 | ### [getDuration](./lib/getDuration.ts) 327 | 328 | ```typescript 329 | (seconds: number) => Duration; 330 | ``` 331 | 332 | #### Параметры 333 | 334 | - `seconds`, интервал времени в секундах. 335 | 336 | #### Пример 337 | 338 | ```js 339 | getDuration(1000000); // { days: 11, hours: 13, minutes: 46, seconds: 40 } 340 | ``` 341 | 342 | 343 | ### [isSameMinute](./lib/isSameMinute.ts), [isSameHour](./lib/isSameHour.ts), [isSameDay](./lib/isSameDay.ts), [isSameMonth](./lib/isSameMonth.ts), [isSameYear](./lib/isSameYear.ts) 344 | 345 | ```typescript 346 | (firstValue: ChronosDate, secondValue: ChronosDate) => boolean; 347 | ``` 348 | 349 | #### Параметры 350 | 351 | - `firstDate`, дата; 352 | - `secondDate`, дата. 353 | 354 | #### Пример 355 | 356 | ```js 357 | // 1577750400 — это 2019-12-31T00:00:00.000Z 358 | // 1577836800 — это 2020-01-01T00:00:00.000Z 359 | isSameYear(1577750400, 1577836800); // false 360 | ``` 361 | 362 | 363 | ### [getDiffInMinutes](./lib/getDiffInMinutes.ts), [getDiffInHours](./lib/getDiffInHours.ts), [getDiffInDays](./lib/getDiffInDays.ts), [getDiffInCalendarDays](./lib/getDiffInCalendarDays.ts), [getDiffInMonths](./lib/getDiffInMonths.ts), [getDiffInCalendarMonths](./lib/getDiffInCalendarMonths.ts), [getDiffInYears](./lib/getDiffInYears.ts), [getDiffInCalendarYears](./lib/getDiffInCalendarYears.ts) 364 | 365 | ```typescript 366 | (firstValue: ChronosDate, secondValue: ChronosDate) => number; 367 | ``` 368 | 369 | #### Параметры 370 | 371 | - `firstDate`, дата; 372 | - `secondDate`, дата. 373 | 374 | #### Пример 375 | 376 | ```js 377 | // 1577750400 — это 2019-12-31T00:00:00.000Z 378 | // 1577836800 — это 2020-01-01T00:00:00.000Z 379 | getDiffInDays(1577750400, 1577836800); // -1 380 | ``` 381 | 382 | 383 | ### [getStartOfMinutes](./lib/getStartOfMinutes.ts), [getStartOfHours](./lib/getStartOfHours.ts), [getStartOfDay](./lib/getStartOfDay.ts), [getStartOfWeek](./lib/getStartOfWeek), [getStartOfMonth](./lib/getStartOfMonth.ts), [getStartOfYear](./lib/getStartOfYear.ts), [getStartOfDecade](./lib/getStartOfDecade.ts) 384 | 385 | ```typescript 386 | (value: ChronosDate, diff?: number) => Date; 387 | ``` 388 | 389 | #### Параметры 390 | 391 | - `value`, дата; 392 | - `diff`, количество единиц, которые нужно добавить в итоговой дате. По умолчанию `0`. 393 | 394 | #### Пример 395 | 396 | ```js 397 | // 1577836800 — это 2020-01-01T00:00:00.000Z 398 | getStartOfDay(1577836800); // 2019-12-31T21:00:00.000Z (для GMT+3) 399 | getStartOfDay(1577836800, 1); // 2020-01-01T21:00:00.000Z (для GMT+3) 400 | getStartOfDay(1577836800, -1); // 2019-12-30T21:00:00.000Z (для GMT+3) 401 | ``` 402 | 403 | 404 | ### [getEndOfMinutes](./lib/getEndOfMinutes.ts), [getEndOfHours](./lib/getEndOfHours.ts), [getEndOfDay](./lib/getEndOfDay.ts), [getEndOfWeek](./lib/getEndOfWeek.ts), [getEndOfMonth](./lib/getEndOfMonth.ts), [getEndOfYear](./lib/getEndOfYear.ts), [getEndOfDecade](./lib/getEndOfDecade.ts) 405 | 406 | ```typescript 407 | (value: ChronosDate, diff?: number) => Date; 408 | ``` 409 | 410 | #### Параметры 411 | 412 | - `value`, дата; 413 | - `diff`, количество единиц, которые нужно добавить в итоговой дате. По умолчанию `0`. 414 | 415 | #### Пример 416 | 417 | ```js 418 | // 1577836800 — это 2020-01-01T00:00:00.000Z 419 | getEndOfDay(1577836800); // 2020-01-01T20:59:59.999Z (для GMT+3) 420 | getEndOfDay(1577836800, 1); // 2020-01-02T20:59:59.999Z (для GMT+3) 421 | getEndOfDay(1577836800, -1); // 2019-12-31T20:59:59.999Z (для GMT+3) 422 | ``` 423 | 424 | 425 | ### [getRelativeDate](./lib/getRelativeDate.ts) 426 | 427 | ```typescript 428 | (value: ChronosDate) => string; 429 | ``` 430 | 431 | #### Параметры 432 | 433 | - `value`, дата. 434 | 435 | #### Пример 436 | 437 | ```js 438 | getRelativeDate(1577081613); // '2 месяца' (для 07.02.2020) 439 | getRelativeDate(new Date()); // 'меньше минуты' 440 | ``` 441 | 442 | 443 | ### [getUtcOffset](./lib/getUtcOffset.ts) 444 | 445 | ```typescript 446 | (value: ChronosDate) => number; 447 | ``` 448 | 449 | #### Параметры 450 | 451 | - `value`, дата. 452 | 453 | #### Пример 454 | 455 | ```js 456 | getUtcOffset(new Date(2020, 0, 1)); // 3 (для GMT+3) 457 | ``` 458 | 459 | 460 | ### [getUnixTimestamp](./lib/getUnixTimestamp.ts) 461 | 462 | ```typescript 463 | (value?: ChronosDate) => number; 464 | ``` 465 | 466 | #### Параметры 467 | 468 | - `date`, объект Date. По умолчанию `new Date()`. 469 | 470 | #### Пример 471 | 472 | ```js 473 | // сейчас 2020-02-07T08:26:59.422Z 474 | getUnixTimestamp(); // 1581064019 (unixtime от new Date()) 475 | 476 | getUnixTimestamp(new Date(2020, 0, 1)); // 1577826000 (для GMT+3) 477 | ``` 478 | 479 | 480 | ### [getTimezoneName](./lib/getTimezoneName) 481 | 482 | ```typescript 483 | () => string; 484 | ``` 485 | 486 | #### Пример 487 | 488 | ```js 489 | getTimezoneName(); // 'Europe/Moscow' (для GMT+3 в ИЕ11 и для MSK в новых браузерах) 490 | ``` 491 | 492 | #### Важное замечение 493 | 494 | В случае отсутствия поддержки Intl API в текущем браузере, будет возвращена ближайшая к пользователю таймзона, 495 | смещение которое выражено _целым числом часов_. 496 | 497 | 498 | ### [isTimeValid](./lib/isTimeValid.ts) 499 | 500 | ```typescript 501 | (value: string, format: string) => boolean; 502 | ``` 503 | 504 | #### Параметры 505 | 506 | - `value`, строка с временем; 507 | - `format`, строка с форматом, который нужно использовать для валидации. 508 | 509 | #### Пример 510 | 511 | ```js 512 | isTimeValid('22:30', 'HH:mm'); // true 513 | ``` 514 | 515 | 516 | ### [parseDate](./lib/parseDate.ts) 517 | 518 | ```typescript 519 | (value: string, format: string) => Date; 520 | ``` 521 | 522 | #### Параметры 523 | 524 | - `value`, строка с датой; 525 | - `format`, строка с форматом, который нужно использовать для парсинга. 526 | 527 | #### Доступные ключи в формате 528 | 529 | | Тип | Ключ | Распознаваемые значения | 530 | |:------------|:-------|:----------------------------------------| 531 | | День месяца | `DD` | 01, 02, 03, ..., 29, 30, 31 | 532 | | | `D` | 1, 2, 3, ..., 29, 30, 31 | 533 | | Месяц | `MM` | 01, 02, 03, ..., 10, 11, 12 | 534 | | Год | `YYYY` | Full year, e.g.: 1885, 1955, 1985, 2015 | 535 | | | `YY` | 00, 01, 02, ..., 97, 98, 99 | 536 | 537 | #### Пример 538 | 539 | ```js 540 | parseDate('2000-01-21', 'YYYY-MM-DD'); // == new Date(2000, 0, 21) 541 | parseDate('2020-01-01T00:00:00+03:00'); // == new Date(2020, 0, 1) (для GMT+3) 542 | ``` 543 | 544 | #### Important notes 545 | 546 | Если `format` не передан, то функция пытается распарсить `value` используя встроенный `Date.parse`. 547 | Теоретически он поддерживает ISO 8691 и RFC 2822. Другие форматы не рекомендуется парсить без явного указания `format`. 548 | 549 | 550 | ## Благодарности 551 | 552 | Картинки для репозитория нарисовал [Игорь Гарибальди](https://pandabanda.com/). 553 | 554 | 555 | [![Sponsored by FunBox](https://funbox.ru/badges/sponsored_by_funbox_grayscale.svg)](https://funbox.ru) 556 | -------------------------------------------------------------------------------- /images/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funbox/chronos/5c8bbc7901d01b6298e35aef25155146dd070b19/images/avatar.png -------------------------------------------------------------------------------- /images/picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funbox/chronos/5c8bbc7901d01b6298e35aef25155146dd070b19/images/picture.png -------------------------------------------------------------------------------- /lib/addCalendarMonths.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Add calendar months to date 5 | * @param value 6 | * @param quantity 7 | * @return - Addition result 8 | */ 9 | export default (value: ChronosDate, quantity: number): Date => { 10 | const date = ensureDate(value); 11 | 12 | const desiredDayOfMonth = date.getDate(); 13 | 14 | date.setMonth(date.getMonth() + quantity + 1, 0); 15 | 16 | if (desiredDayOfMonth < date.getDate()) { 17 | date.setDate(desiredDayOfMonth); 18 | } 19 | 20 | return date; 21 | }; 22 | -------------------------------------------------------------------------------- /lib/addDays.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Add days to date 5 | * @param value 6 | * @param quantity 7 | * @return – Addition result 8 | */ 9 | export default (value: ChronosDate, quantity: number): Date => { 10 | const date = ensureDate(value); 11 | 12 | date.setDate(date.getDate() + quantity); 13 | 14 | return date; 15 | }; 16 | -------------------------------------------------------------------------------- /lib/addHours.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Add hours to date 5 | * @param value 6 | * @param quantity 7 | * @return - Addition result 8 | */ 9 | export default (value: ChronosDate, quantity: number): Date => { 10 | const date = ensureDate(value); 11 | 12 | date.setHours(date.getHours() + quantity); 13 | 14 | return date; 15 | }; 16 | -------------------------------------------------------------------------------- /lib/addMinutes.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Add minutes to date 5 | * @param value 6 | * @param quantity 7 | * @return - Addition result 8 | */ 9 | export default (value: ChronosDate, quantity: number): Date => { 10 | const date = ensureDate(value); 11 | 12 | date.setMinutes(date.getMinutes() + quantity); 13 | 14 | return date; 15 | }; 16 | -------------------------------------------------------------------------------- /lib/addMonths.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Add months to date 5 | * @param value 6 | * @param quantity 7 | * @return - Addition result 8 | */ 9 | export default (value: ChronosDate, quantity: number): Date => { 10 | const date = ensureDate(value); 11 | 12 | // When adding months to date in JS one should remember the amount of days 13 | // in the current and the result month. E.g. when we add 1 month to 31.01.2020 we get 02.03.2020, not 29.02.2020 14 | // Reference url: https://www.w3schools.com/jsref/jsref_setmonth.asp 15 | date.setMonth(date.getMonth() + quantity); 16 | 17 | return date; 18 | }; 19 | -------------------------------------------------------------------------------- /lib/addYears.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Add years to date 5 | * @param value 6 | * @param quantity 7 | * @return - Addition result 8 | */ 9 | export default (value: ChronosDate, quantity: number): Date => { 10 | const date = ensureDate(value); 11 | 12 | date.setFullYear(date.getFullYear() + quantity); 13 | 14 | return date; 15 | }; 16 | -------------------------------------------------------------------------------- /lib/constants/index.ts: -------------------------------------------------------------------------------- 1 | export const LOCALE = 'ru'; 2 | 3 | export const LOCALE_DAY_OPTIONS = { 4 | numeric: 'numeric', 5 | '2-digit': '2-digit', 6 | }; 7 | 8 | export const LOCALE_WEEKDAY_OPTIONS = { 9 | narrow: 'narrow', 10 | long: 'long', 11 | short: 'short', 12 | }; 13 | 14 | export const LOCALE_MONTH_OPTIONS = { 15 | numeric: 'numeric', 16 | '2-digit': '2-digit', 17 | long: 'long', 18 | short: 'short', 19 | narrow: 'narrow', 20 | }; 21 | 22 | export const TIMEZONE_NAMES = { 23 | 'Asia/Kamchatka': 12, 24 | 'Asia/Magadan': 11, 25 | 'Asia/Vladivostok': 10, 26 | 'Asia/Yakutsk': 9, 27 | 'Asia/Irkutsk': 8, 28 | 'Asia/Krasnoyarsk': 7, 29 | 'Asia/Omsk': 6, 30 | 'Asia/Yekaterinburg': 5, 31 | 'Europe/Samara': 4, 32 | 'Europe/Moscow': 3, 33 | 'Europe/Kaliningrad': 2, 34 | 'Europe/Oslo': 1, 35 | 'Europe/London': 0, 36 | 'Atlantic/Cape_Verde': -1, 37 | 'America/Noronha': -2, 38 | 'America/Bahia': -3, 39 | 'Atlantic/Bermuda': -4, 40 | 'America/New_York': -5, 41 | 'America/Chicago': -6, 42 | 'America/Phoenix': -7, 43 | 'America/Los_Angeles': -8, 44 | 'America/Anchorage': -9, 45 | 'Pacific/Honolulu': -10, 46 | 'Pacific/Niue': -11, 47 | 'Pacific/Baker_Island': -12, 48 | }; 49 | 50 | export type TimezoneNamesType = keyof typeof TIMEZONE_NAMES; 51 | 52 | export type TimeFormatType = 'ss' | 'mm' | 'HH' | 'H'; 53 | -------------------------------------------------------------------------------- /lib/formatDate.ts: -------------------------------------------------------------------------------- 1 | import { LOCALE, LOCALE_WEEKDAY_OPTIONS, LOCALE_MONTH_OPTIONS, LOCALE_DAY_OPTIONS } from './constants'; 2 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 3 | 4 | /** 5 | * Format date according to format string 6 | * @param value 7 | * @param format 8 | * @return - Formatted date result 9 | */ 10 | export default (value: ChronosDate, format: string): string => { 11 | const date = ensureDate(value); 12 | 13 | const hour = `0${date.getHours()}`.slice(-2); 14 | const minute = `0${date.getMinutes()}`.slice(-2); 15 | const second = `0${date.getSeconds()}`.slice(-2); 16 | 17 | // getTimezoneOffset returns offset in minutes with negative sign for timezones on the east of UTC. 18 | // So we divide it on -60 to get correct offset in hours. 19 | const timeZoneOffset = date.getTimezoneOffset(); 20 | const timeZoneOffsetInHours = Math.floor(timeZoneOffset / -60); 21 | const timeZoneOffsetMinutes = `0${Math.abs(timeZoneOffset % 60)}`.slice(-2); 22 | const formattedTimeZoneOffset = `0${Math.abs(timeZoneOffsetInHours)}`.slice(-2); 23 | 24 | format = format.replace('ss', second); 25 | format = format.replace('mm', minute); 26 | format = format.replace('HH', hour); 27 | format = format.replace('dddd', date.toLocaleString(LOCALE, { weekday: LOCALE_WEEKDAY_OPTIONS.long })); 28 | format = format.replace('DD', `0${date.getDate()}`.slice(-2)); 29 | format = format.replace('D', `${date.getDate()}`); // String.replace wants a string as a second parameter 30 | format = format.replace('MMMM', date.toLocaleString(LOCALE, { month: LOCALE_MONTH_OPTIONS.long, day: LOCALE_DAY_OPTIONS.numeric }).split(' ')[1]); 31 | format = format.replace('MMM', date.toLocaleString(LOCALE, { month: LOCALE_MONTH_OPTIONS.short })); 32 | format = format.replace('MM', `0${date.getMonth() + 1}`.slice(-2)); 33 | format = format.replace('YYYY', `${date.getFullYear()}`); 34 | format = format.replace('YY', `${date.getFullYear()}`.substring(2)); 35 | format = format.replace('ZZ', `${timeZoneOffsetInHours > 0 ? '+' : '-'}${formattedTimeZoneOffset}${timeZoneOffsetMinutes}`); 36 | format = format.replace('Z', `${timeZoneOffsetInHours > 0 ? '+' : '-'}${formattedTimeZoneOffset}:${timeZoneOffsetMinutes}`); 37 | 38 | /* 39 | IE 11 and old versions of MS Edge add into the result of 40 | `toLocaleString` additional symbol U+200E. 41 | 42 | It breaks other Chronos functions such as `parseDate`, 43 | so here we remove those symbols. 44 | */ 45 | format = format.replace(/\u200E/g, ''); 46 | 47 | return format; 48 | }; 49 | -------------------------------------------------------------------------------- /lib/formatTimeString.ts: -------------------------------------------------------------------------------- 1 | import parseTime from './helpers/parseTime'; 2 | 3 | /** 4 | * Format time according to format string 5 | * @param value 6 | * @param valueFormat 7 | * @param format 8 | * @return - Formatted time result 9 | */ 10 | export default (value: string, valueFormat: string, format: string): string => { 11 | const time = parseTime(value, valueFormat); 12 | 13 | const hours = time.H || time.HH || 0; 14 | 15 | format = format.replace('ss', time.ss || '00'); 16 | format = format.replace('mm', time.mm || '00'); 17 | format = format.replace('HH', `0${hours}`.slice(-2)); 18 | format = format.replace('H', `${+hours}`); 19 | 20 | return format; 21 | }; 22 | -------------------------------------------------------------------------------- /lib/getDay.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get day 5 | * @param value 6 | * @return - Day value 7 | */ 8 | export default (value: ChronosDate): number => { 9 | const date = ensureDate(value); 10 | 11 | return date.getDate(); 12 | }; 13 | -------------------------------------------------------------------------------- /lib/getDiffInCalendarDays.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Calculate difference of dates in calendar days 5 | * @param firstValue 6 | * @param secondValue 7 | * @return - Difference result 8 | */ 9 | export default (firstValue: ChronosDate, secondValue: ChronosDate): number => { 10 | const firstDate = ensureDate(firstValue); 11 | const secondDate = ensureDate(secondValue); 12 | 13 | const diff = (firstDate.setHours(0, 0, 0, 0) - secondDate.setHours(0, 0, 0, 0)) / (1e3 * 60 * 60 * 24); 14 | 15 | return diff >= 0 ? Math.floor(diff) : Math.ceil(diff); 16 | }; 17 | -------------------------------------------------------------------------------- /lib/getDiffInCalendarMonths.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Calculate difference of dates in calendar months 5 | * @param firstValue 6 | * @param secondValue 7 | * @return - Difference result 8 | */ 9 | export default (firstValue: ChronosDate, secondValue: ChronosDate): number => { 10 | const firstDate = ensureDate(firstValue); 11 | const secondDate = ensureDate(secondValue); 12 | let diff = 0; 13 | 14 | diff += (firstDate.getFullYear() - secondDate.getFullYear()) * 12; 15 | diff += firstDate.getMonth() - secondDate.getMonth(); 16 | 17 | return diff; 18 | }; 19 | -------------------------------------------------------------------------------- /lib/getDiffInCalendarYears.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Calculate difference of dates in calendar years 5 | * @param firstValue 6 | * @param secondValue 7 | * @return - Difference result 8 | */ 9 | export default (firstValue: ChronosDate, secondValue: ChronosDate): number => { 10 | const firstDate = ensureDate(firstValue); 11 | const secondDate = ensureDate(secondValue); 12 | 13 | return firstDate.getFullYear() - secondDate.getFullYear(); 14 | }; 15 | -------------------------------------------------------------------------------- /lib/getDiffInDays.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Calculate difference of dates in full days 5 | * @param firstValue 6 | * @param secondValue 7 | * @return - Difference result 8 | */ 9 | export default (firstValue: ChronosDate, secondValue: ChronosDate): number => { 10 | const firstDate = ensureDate(firstValue); 11 | const secondDate = ensureDate(secondValue); 12 | 13 | const diff = (firstDate.getTime() - secondDate.getTime()) / (1e3 * 60 * 60 * 24); 14 | 15 | return diff >= 0 ? Math.floor(diff) : Math.ceil(diff); 16 | }; 17 | -------------------------------------------------------------------------------- /lib/getDiffInHours.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Calculate difference of dates in full hours 5 | * @param firstValue 6 | * @param secondValue 7 | * @return - Difference result 8 | */ 9 | export default (firstValue: ChronosDate, secondValue: ChronosDate): number => { 10 | const firstDate = ensureDate(firstValue); 11 | const secondDate = ensureDate(secondValue); 12 | 13 | const diff = (firstDate.getTime() - secondDate.getTime()) / (1e3 * 60 * 60); 14 | 15 | return diff >= 0 ? Math.floor(diff) : Math.ceil(diff); 16 | }; 17 | -------------------------------------------------------------------------------- /lib/getDiffInMinutes.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Calculate difference of dates in full minutes 5 | * @param firstValue 6 | * @param secondValue 7 | * @return - Difference result 8 | */ 9 | export default (firstValue: ChronosDate, secondValue: ChronosDate): number => { 10 | const firstDate = ensureDate(firstValue); 11 | const secondDate = ensureDate(secondValue); 12 | 13 | const diff = (firstDate.getTime() - secondDate.getTime()) / (1e3 * 60); 14 | 15 | return diff >= 0 ? Math.floor(diff) : Math.ceil(diff); 16 | }; 17 | -------------------------------------------------------------------------------- /lib/getDiffInMonths.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | import getDiffInCalendarMonths from './getDiffInCalendarMonths'; 3 | 4 | /** 5 | * Calculate difference of dates in full months 6 | * @param firstValue 7 | * @param secondValue 8 | * @return - Difference result 9 | */ 10 | export default (firstValue: ChronosDate, secondValue: ChronosDate): number => { 11 | const firstDate = ensureDate(firstValue); 12 | const secondDate = ensureDate(secondValue); 13 | const diffInCalendarMonths = getDiffInCalendarMonths(firstDate, secondDate); 14 | 15 | let diff = Math.abs(diffInCalendarMonths); 16 | 17 | if (diff) { 18 | firstDate.setMonth(firstDate.getMonth() - diffInCalendarMonths); 19 | 20 | const datesDiff = firstDate.getTime() - secondDate.getTime(); 21 | const isNotFullMonth = diffInCalendarMonths < 0 ? datesDiff > 0 : datesDiff < 0; 22 | 23 | if (isNotFullMonth) { 24 | diff -= 1; 25 | } 26 | } 27 | 28 | return diffInCalendarMonths < 0 && diff !== 0 ? -diff : diff; 29 | }; 30 | -------------------------------------------------------------------------------- /lib/getDiffInYears.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Calculate difference of dates in full years 5 | * @param firstValue 6 | * @param secondValue 7 | * @return - Difference result 8 | */ 9 | export default (firstValue: ChronosDate, secondValue: ChronosDate): number => { 10 | const firstDate = ensureDate(firstValue); 11 | const secondDate = ensureDate(secondValue); 12 | 13 | const diffInCalendarYears = firstDate.getFullYear() - secondDate.getFullYear(); 14 | 15 | let diff = Math.abs(diffInCalendarYears); 16 | 17 | if (diff) { 18 | firstDate.setFullYear(firstDate.getFullYear() - diffInCalendarYears); 19 | 20 | const datesDiff = firstDate.getTime() - secondDate.getTime(); 21 | const isNotFullYear = diffInCalendarYears < 0 ? datesDiff > 0 : datesDiff < 0; 22 | 23 | if (isNotFullYear) { 24 | diff -= 1; 25 | } 26 | } 27 | 28 | return diffInCalendarYears < 0 && diff !== 0 ? -diff : diff; 29 | }; 30 | -------------------------------------------------------------------------------- /lib/getDuration.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Get duration object 3 | * @param seconds 4 | * @return - Duration result 5 | */ 6 | 7 | type Duration = { 8 | days: number; 9 | hours: number; 10 | minutes: number; 11 | seconds: number; 12 | }; 13 | 14 | export default (seconds: number): Duration => { 15 | const dayInSeconds = 60 * 60 * 24; 16 | const days = Math.floor(seconds / dayInSeconds); 17 | const hours = Math.floor((seconds - days * dayInSeconds) / (60 * 60)); 18 | const minutes = Math.floor((seconds - days * dayInSeconds - hours * 60 * 60) / 60); 19 | 20 | return { days, hours, minutes, seconds: seconds % 60 }; 21 | }; 22 | -------------------------------------------------------------------------------- /lib/getEndOfDay.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get end of day 5 | * @param value 6 | * @param diff 7 | * @return - End of date result 8 | */ 9 | export default (value: ChronosDate, diff = 0): Date => { 10 | const date = ensureDate(value); 11 | 12 | if (diff) { 13 | date.setDate(date.getDate() + diff); 14 | } 15 | 16 | date.setHours(23, 59, 59, 999); 17 | 18 | return date; 19 | }; 20 | -------------------------------------------------------------------------------- /lib/getEndOfDecade.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get end of decade 5 | * @param value 6 | * @param diff 7 | * @return - End of year result 8 | */ 9 | export default (value: ChronosDate, diff = 0): Date => { 10 | const date = ensureDate(value); 11 | 12 | date.setFullYear(Math.floor(date.getFullYear() / 10) * 10 + 9); 13 | 14 | if (diff) { 15 | date.setFullYear(date.getFullYear() + diff * 10); 16 | } 17 | 18 | date.setMonth(12); 19 | date.setDate(0); 20 | date.setHours(23, 59, 59, 999); 21 | 22 | return date; 23 | }; 24 | -------------------------------------------------------------------------------- /lib/getEndOfHours.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get end of hours 5 | * @param value 6 | * @param diff 7 | * @return - End of date result 8 | */ 9 | export default (value: ChronosDate, diff = 0): Date => { 10 | const date = ensureDate(value); 11 | 12 | if (diff) { 13 | date.setHours(date.getHours() + diff); 14 | } 15 | 16 | date.setMinutes(59, 59, 999); 17 | 18 | return date; 19 | }; 20 | -------------------------------------------------------------------------------- /lib/getEndOfMinutes.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get end of minutes 5 | * @param value 6 | * @param diff 7 | * @return - End of minute result 8 | */ 9 | export default (value: ChronosDate, diff = 0): Date => { 10 | const date = ensureDate(value); 11 | 12 | if (diff) { 13 | date.setMinutes(date.getMinutes() + diff); 14 | } 15 | 16 | date.setSeconds(59, 999); 17 | 18 | return date; 19 | }; 20 | -------------------------------------------------------------------------------- /lib/getEndOfMonth.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get end of month 5 | * @param value 6 | * @param diff 7 | * @return - End of month result 8 | */ 9 | export default (value: ChronosDate, diff = 0): Date => { 10 | const date = ensureDate(value); 11 | let monthValue = date.getMonth() + 1; 12 | 13 | if (diff) monthValue += diff; 14 | 15 | return new Date(date.getFullYear(), monthValue, 0, 23, 59, 59, 999); 16 | }; 17 | -------------------------------------------------------------------------------- /lib/getEndOfWeek.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | const SUNDAY = 7; 4 | const DAYS_IN_WEEK = 7; 5 | 6 | /** 7 | * Get end of week 8 | * @param value 9 | * @param diff 10 | * @return - Start of date result 11 | */ 12 | export default (value: ChronosDate, diff = 0): Date => { 13 | const date = ensureDate(value); 14 | const weekDay = date.getDay() || SUNDAY; 15 | 16 | date.setDate(date.getDate() + (DAYS_IN_WEEK - weekDay)); 17 | 18 | if (diff) { 19 | date.setDate(date.getDate() + diff * DAYS_IN_WEEK); 20 | } 21 | 22 | date.setHours(23, 59, 59, 999); 23 | 24 | return date; 25 | }; 26 | -------------------------------------------------------------------------------- /lib/getEndOfYear.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get end of year 5 | * @param value 6 | * @param diff 7 | * @return - End of year result 8 | */ 9 | export default (value: ChronosDate, diff = 0): Date => { 10 | const date = ensureDate(value); 11 | 12 | if (diff) { 13 | date.setFullYear(date.getFullYear() + diff); 14 | } 15 | 16 | date.setMonth(12); 17 | date.setDate(0); 18 | date.setHours(23, 59, 59, 999); 19 | 20 | return date; 21 | }; 22 | -------------------------------------------------------------------------------- /lib/getHours.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get hours 5 | * @param value 6 | * @return - Hour value 7 | */ 8 | export default (value: ChronosDate): number => { 9 | const date = ensureDate(value); 10 | 11 | return date.getHours(); 12 | }; 13 | -------------------------------------------------------------------------------- /lib/getMinutes.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get minutes 5 | * @param value 6 | * @return - Minute value 7 | */ 8 | export default (value: ChronosDate): number => { 9 | const date = ensureDate(value); 10 | 11 | return date.getMinutes(); 12 | }; 13 | -------------------------------------------------------------------------------- /lib/getMonth.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get month 5 | * @param value 6 | * @return - Month value 7 | */ 8 | export default (value: ChronosDate): number => { 9 | const date = ensureDate(value); 10 | 11 | return date.getMonth(); 12 | }; 13 | -------------------------------------------------------------------------------- /lib/getMonthName.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | import { LOCALE_MONTH_OPTIONS, LOCALE } from './constants'; 4 | 5 | /** 6 | * Get month name 7 | * @param value 8 | * @param format 9 | * @return - Month value 10 | */ 11 | export default (value: ChronosDate, format: 'long' | 'short' = 'long'): string => { 12 | const date = ensureDate(value); 13 | 14 | return date.toLocaleString(LOCALE, { month: LOCALE_MONTH_OPTIONS[format] }); 15 | }; 16 | -------------------------------------------------------------------------------- /lib/getRelativeDate.ts: -------------------------------------------------------------------------------- 1 | import { getDay, getDiffInDays, getDiffInHours, getDiffInMinutes, getDiffInMonths, getDiffInYears, getEndOfMonth } from '.'; 2 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 3 | 4 | /** 5 | * Get relative date 6 | * @param value 7 | * @return - Relative date value 8 | */ 9 | export default (value: ChronosDate): string => { 10 | const date = ensureDate(value); 11 | const currentDate = new Date(); 12 | 13 | const minutes = getDiffInMinutes(currentDate, date); 14 | const hours = getDiffInHours(currentDate, date); 15 | const days = getDiffInDays(currentDate, date); 16 | const months = getDiffInMonths(currentDate, date); 17 | const years = getDiffInYears(currentDate, date); 18 | 19 | let result = ''; 20 | 21 | if (!minutes) { 22 | result = 'меньше минуты'; 23 | } else if (minutes < 60) { 24 | result = `${minutes === 1 ? '' : `${minutes} `}${getPlural(minutes, 'минуту', 'минуты', 'минут')}`; 25 | } else if (hours < 24) { 26 | result = `${hours === 1 ? '' : `${hours} `}${getPlural(hours, 'час', 'часа', 'часов')}`; 27 | } else if (days < getDay(getEndOfMonth(date))) { 28 | result = `${days === 1 ? '' : `${days} `}${getPlural(days, 'день', 'дня', 'дней')}`; 29 | } else if (months < 12) { 30 | result = `${months === 1 ? '' : `${months} `}${getPlural(months, 'месяц', 'месяца', 'месяцев')}`; 31 | } else { 32 | result = `${years === 1 ? '' : `${years} `}${getPlural(years, 'год', 'года', 'лет')}`; 33 | } 34 | 35 | return result; 36 | }; 37 | 38 | function getPlural(n: number, one: string, few: string, many: string): string { 39 | if (n % 10 === 1 && n % 100 !== 11) { 40 | return one; 41 | } 42 | 43 | if (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20)) { 44 | return few; 45 | } 46 | 47 | return many; 48 | } 49 | -------------------------------------------------------------------------------- /lib/getStartOfDay.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get start of day 5 | * @param value 6 | * @param diff 7 | * @return - Start of date result 8 | */ 9 | export default (value: ChronosDate, diff = 0): Date => { 10 | const date = ensureDate(value); 11 | 12 | if (diff) { 13 | date.setDate(date.getDate() + diff); 14 | } 15 | 16 | date.setHours(0, 0, 0, 0); 17 | 18 | return date; 19 | }; 20 | -------------------------------------------------------------------------------- /lib/getStartOfDecade.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get start of decade 5 | * @param value 6 | * @param diff 7 | * @return - Start of date result 8 | */ 9 | export default (value: ChronosDate, diff = 0): Date => { 10 | const date = ensureDate(value); 11 | 12 | date.setFullYear(Math.floor(date.getFullYear() / 10) * 10); 13 | 14 | if (diff) { 15 | date.setFullYear(date.getFullYear() + diff * 10); 16 | } 17 | 18 | date.setMonth(0); 19 | date.setDate(1); 20 | date.setHours(0, 0, 0, 0); 21 | 22 | return date; 23 | }; 24 | -------------------------------------------------------------------------------- /lib/getStartOfHours.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get start of hours 5 | * @param value 6 | * @param diff 7 | * @return - Start of hour result 8 | */ 9 | export default (value: ChronosDate, diff = 0): Date => { 10 | const date = ensureDate(value); 11 | 12 | if (diff) { 13 | date.setHours(date.getHours() + diff); 14 | } 15 | 16 | date.setMinutes(0, 0, 0); 17 | 18 | return date; 19 | }; 20 | -------------------------------------------------------------------------------- /lib/getStartOfMinutes.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get start of minutes 5 | * @param value 6 | * @param diff 7 | * @return - Start of minute result 8 | */ 9 | export default (value: ChronosDate, diff = 0): Date => { 10 | const date = ensureDate(value); 11 | 12 | if (diff) { 13 | date.setMinutes(date.getMinutes() + diff); 14 | } 15 | 16 | date.setSeconds(0, 0); 17 | 18 | return date; 19 | }; 20 | -------------------------------------------------------------------------------- /lib/getStartOfMonth.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get start of month 5 | * @param value 6 | * @param diff 7 | * @return - Start of date result 8 | */ 9 | export default (value: ChronosDate, diff = 0): Date => { 10 | const date = ensureDate(value); 11 | 12 | date.setDate(1); 13 | 14 | if (diff) { 15 | date.setMonth(date.getMonth() + diff); 16 | } 17 | 18 | date.setHours(0, 0, 0, 0); 19 | 20 | return date; 21 | }; 22 | -------------------------------------------------------------------------------- /lib/getStartOfWeek.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | const SUNDAY = 7; 4 | const DAYS_IN_WEEK = 7; 5 | 6 | /** 7 | * Get start of week 8 | * @param value 9 | * @param diff 10 | * @return - Start of date result 11 | */ 12 | export default (value: ChronosDate, diff = 0): Date => { 13 | const date = ensureDate(value); 14 | const weekDay = date.getDay() || SUNDAY; 15 | 16 | // weekdays' indexes starts from 1, so we need to subtract 1 17 | // e.g. if today 18 | date.setDate(date.getDate() - (weekDay - 1)); 19 | 20 | if (diff) { 21 | date.setDate(date.getDate() + diff * DAYS_IN_WEEK); 22 | } 23 | 24 | date.setHours(0, 0, 0, 0); 25 | 26 | return date; 27 | }; 28 | -------------------------------------------------------------------------------- /lib/getStartOfYear.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get start of year 5 | * @param value 6 | * @param diff 7 | * @return - Start of date result 8 | */ 9 | export default (value: ChronosDate, diff = 0): Date => { 10 | const date = ensureDate(value); 11 | 12 | if (diff) { 13 | date.setFullYear(date.getFullYear() + diff); 14 | } 15 | 16 | date.setMonth(0); 17 | date.setDate(1); 18 | date.setHours(0, 0, 0, 0); 19 | 20 | return date; 21 | }; 22 | -------------------------------------------------------------------------------- /lib/getTimezoneName.ts: -------------------------------------------------------------------------------- 1 | import { TIMEZONE_NAMES, TimezoneNamesType } from './constants'; 2 | 3 | /** 4 | * Get current timezone name 5 | * @return - Timezone name result 6 | */ 7 | export default (): string => { 8 | let timezoneName = Intl.DateTimeFormat().resolvedOptions().timeZone; 9 | 10 | if (!timezoneName) { 11 | // IE does not support Intl API for getting timezone names, 12 | // so we calculate offset in hours and return the timezone name from our object. 13 | const timeZoneOffsetInHours = Math.floor(new Date().getTimezoneOffset() / -60); 14 | 15 | timezoneName = Object.keys(TIMEZONE_NAMES).find(key => TIMEZONE_NAMES[key as TimezoneNamesType] === timeZoneOffsetInHours) || ''; 16 | } 17 | 18 | return timezoneName; 19 | }; 20 | -------------------------------------------------------------------------------- /lib/getUnixTimestamp.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get unix timestamp from date 5 | * @param value 6 | * @return - Unix timestamp result 7 | */ 8 | export default (value: ChronosDate = new Date()): number => { 9 | const date = ensureDate(value); 10 | return Math.floor(date.getTime() / 1e3); 11 | }; 12 | -------------------------------------------------------------------------------- /lib/getUtcOffset.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get current timezone offset to UTC in hours 5 | * @param value 6 | * @return - Offset value in hours result 7 | */ 8 | export default (value: ChronosDate): number => { 9 | const date = ensureDate(value); 10 | 11 | return Math.floor(date.getTimezoneOffset() / -60); 12 | }; 13 | -------------------------------------------------------------------------------- /lib/getWeekdayName.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | import { LOCALE, LOCALE_WEEKDAY_OPTIONS } from './constants'; 3 | 4 | /** 5 | * Get weekday name 6 | * @param value 7 | * @param format 8 | * @return - Weekday value 9 | */ 10 | export default (value: ChronosDate, format: 'long' | 'short' = 'long'): string => { 11 | const date = ensureDate(value); 12 | 13 | return date.toLocaleString(LOCALE, { weekday: LOCALE_WEEKDAY_OPTIONS[format] }); 14 | }; 15 | -------------------------------------------------------------------------------- /lib/getYear.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Get year 5 | * @param value 6 | * @return - Year value 7 | */ 8 | export default (value: ChronosDate): number => { 9 | const date = ensureDate(value); 10 | 11 | return date.getFullYear(); 12 | }; 13 | -------------------------------------------------------------------------------- /lib/helpers/ensureDate.ts: -------------------------------------------------------------------------------- 1 | export type ChronosDate = Date | number | string; 2 | 3 | /** 4 | * Transforms param to Date object 5 | * @param value 6 | * @return - Date object result 7 | */ 8 | export const ensureDate = (value: ChronosDate): Date => { 9 | let dateValue = value; 10 | // It's possible to pass value as a ISO 8601 or RFC2822 string. Others string formats aren't recommended to pass. 11 | // Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse 12 | if (typeof dateValue === 'string' && isNaN(+dateValue)) { // eslint-disable-line no-restricted-globals 13 | dateValue = Date.parse(dateValue); 14 | } 15 | 16 | const date = new Date((`${dateValue.toString()}`).length === 10 ? +dateValue * 1e3 : +dateValue); 17 | 18 | // new Date('something') instanceof Date returns true, 19 | // so when date === Invalid Date we check that date isn't NaN 20 | // isNaN isn't secure, but Number.isNaN isn't supported by IE11 21 | if (!(date instanceof Date) || isNaN(+date)) { // eslint-disable-line no-restricted-globals 22 | throw new Error(`Invalid date value: ${value.toString()}`); 23 | } 24 | 25 | return date; 26 | }; 27 | -------------------------------------------------------------------------------- /lib/helpers/parseTime.ts: -------------------------------------------------------------------------------- 1 | import { TimeFormatType } from '../constants'; 2 | 3 | /** 4 | * Parse time string to object 5 | * @param value 6 | * @param format 7 | * @return - Time parts as object result 8 | */ 9 | export default (value: string, format: string): Record => { 10 | if (!value) { 11 | throw new Error('Empty value'); 12 | } 13 | 14 | if (!format) { 15 | throw new Error('Empty format'); 16 | } 17 | 18 | const time = value.split(':'); 19 | const formatParts = format.split(':'); 20 | 21 | if (time.length !== formatParts.length) { 22 | throw new Error(`Format doesn't match time: ${format}, ${value}`); 23 | } 24 | 25 | const timeObj = formatParts.reduce((acc: Record, part: string, i: number) => { 26 | let validTime = null; 27 | 28 | if (part === 'HH') { 29 | validTime = /^(0[0-9]|1[0-9]|2[0-3])$/.exec(time[i]); 30 | } else if (part === 'H') { 31 | validTime = /^([0-9]|1[0-9]|2[0-3])$/.exec(time[i]); 32 | } else { 33 | validTime = /^[0-5][0-9]$/.exec(time[i]); 34 | } 35 | 36 | if (!validTime) { 37 | throw new Error(`Invalid value: ${value}`); 38 | } 39 | 40 | acc[part] = validTime[0]; 41 | 42 | return acc; 43 | }, {}); 44 | 45 | return timeObj; 46 | }; 47 | -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | export { default as addDays } from './addDays'; 2 | export { default as addHours } from './addHours'; 3 | export { default as addMinutes } from './addMinutes'; 4 | export { default as addMonths } from './addMonths'; 5 | export { default as addCalendarMonths } from './addCalendarMonths'; 6 | export { default as addYears } from './addYears'; 7 | export { default as isSameDay } from './isSameDay'; 8 | export { default as isSameHour } from './isSameHour'; 9 | export { default as isSameMinute } from './isSameMinute'; 10 | export { default as isSameMonth } from './isSameMonth'; 11 | export { default as isSameYear } from './isSameYear'; 12 | export { default as getDiffInDays } from './getDiffInDays'; 13 | export { default as getDiffInCalendarDays } from './getDiffInCalendarDays'; 14 | export { default as getDiffInHours } from './getDiffInHours'; 15 | export { default as getDiffInMinutes } from './getDiffInMinutes'; 16 | export { default as getDiffInMonths } from './getDiffInMonths'; 17 | export { default as getDiffInCalendarMonths } from './getDiffInCalendarMonths'; 18 | export { default as getDiffInYears } from './getDiffInYears'; 19 | export { default as getDiffInCalendarYears } from './getDiffInCalendarYears'; 20 | export { default as getStartOfDay } from './getStartOfDay'; 21 | export { default as getStartOfDecade } from './getStartOfDecade'; 22 | export { default as getStartOfHours } from './getStartOfHours'; 23 | export { default as getStartOfMinutes } from './getStartOfMinutes'; 24 | export { default as getStartOfMonth } from './getStartOfMonth'; 25 | export { default as getStartOfWeek } from './getStartOfWeek'; 26 | export { default as getStartOfYear } from './getStartOfYear'; 27 | export { default as getEndOfDay } from './getEndOfDay'; 28 | export { default as getEndOfDecade } from './getEndOfDecade'; 29 | export { default as getEndOfHours } from './getEndOfHours'; 30 | export { default as getEndOfMinutes } from './getEndOfMinutes'; 31 | export { default as getEndOfMonth } from './getEndOfMonth'; 32 | export { default as getEndOfWeek } from './getEndOfWeek'; 33 | export { default as getEndOfYear } from './getEndOfYear'; 34 | export { default as getDay } from './getDay'; 35 | export { default as getHours } from './getHours'; 36 | export { default as getMinutes } from './getMinutes'; 37 | export { default as getMonth } from './getMonth'; 38 | export { default as getMonthName } from './getMonthName'; 39 | export { default as getWeekdayName } from './getWeekdayName'; 40 | export { default as getYear } from './getYear'; 41 | export { default as getDuration } from './getDuration'; 42 | export { default as getRelativeDate } from './getRelativeDate'; // eslint-disable-line import/no-cycle 43 | export { default as getTimezoneName } from './getTimezoneName'; 44 | export { default as getUnixTimestamp } from './getUnixTimestamp'; 45 | export { default as getUtcOffset } from './getUtcOffset'; 46 | export { default as formatDate } from './formatDate'; 47 | export { default as formatTimeString } from './formatTimeString'; 48 | export { default as isTimeValid } from './isTimeValid'; 49 | export { default as parseDate } from './parseDate'; // eslint-disable-line import/no-cycle 50 | export { default as subtractDays } from './subtractDays'; 51 | export { default as subtractHours } from './subtractHours'; 52 | export { default as subtractMinutes } from './subtractMinutes'; 53 | export { default as subtractMonths } from './subtractMonths'; 54 | export { default as subtractCalendarMonths } from './subtractCalendarMonths'; 55 | export { default as subtractYears } from './subtractYears'; 56 | -------------------------------------------------------------------------------- /lib/isSameDay.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Compares if dates are equal 5 | * @param firstValue 6 | * @param secondValue 7 | * @return - Date units equality result 8 | */ 9 | export default (firstValue: ChronosDate, secondValue: ChronosDate): boolean => { 10 | const firstDate = ensureDate(firstValue); 11 | const secondDate = ensureDate(secondValue); 12 | 13 | return firstDate.getDate() === secondDate.getDate() 14 | && firstDate.getMonth() === secondDate.getMonth() 15 | && firstDate.getFullYear() === secondDate.getFullYear(); 16 | }; 17 | -------------------------------------------------------------------------------- /lib/isSameHour.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Compares if hours of the same date are equal 5 | * @param firstValue 6 | * @param secondValue 7 | * @return - Hours units equality result 8 | */ 9 | export default (firstValue: ChronosDate, secondValue: ChronosDate): boolean => { 10 | const firstDate = ensureDate(firstValue); 11 | const secondDate = ensureDate(secondValue); 12 | 13 | return firstDate.getFullYear() === secondDate.getFullYear() 14 | && firstDate.getMonth() === secondDate.getMonth() 15 | && firstDate.getDate() === secondDate.getDate() 16 | && firstDate.getHours() === secondDate.getHours(); 17 | }; 18 | -------------------------------------------------------------------------------- /lib/isSameMinute.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Compares if minutes of the same date are equal 5 | * @param firstValue 6 | * @param secondValue 7 | * @return - Minutes units equality result 8 | */ 9 | export default (firstValue: ChronosDate, secondValue: ChronosDate): boolean => { 10 | const firstDate = ensureDate(firstValue); 11 | const secondDate = ensureDate(secondValue); 12 | 13 | return firstDate.getFullYear() === secondDate.getFullYear() 14 | && firstDate.getMonth() === secondDate.getMonth() 15 | && firstDate.getDate() === secondDate.getDate() 16 | && firstDate.getHours() === secondDate.getHours() 17 | && firstDate.getMinutes() === secondDate.getMinutes(); 18 | }; 19 | -------------------------------------------------------------------------------- /lib/isSameMonth.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Compares if months of dates are equal 5 | * @param firstValue 6 | * @param secondValue 7 | * @return - Date units equality result 8 | */ 9 | export default (firstValue: ChronosDate, secondValue: ChronosDate): boolean => { 10 | const firstDate = ensureDate(firstValue); 11 | const secondDate = ensureDate(secondValue); 12 | 13 | return firstDate.getMonth() === secondDate.getMonth() && firstDate.getFullYear() === secondDate.getFullYear(); 14 | }; 15 | -------------------------------------------------------------------------------- /lib/isSameYear.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate, ensureDate } from './helpers/ensureDate'; 2 | 3 | /** 4 | * Compares if years of dates are equal 5 | * @param firstValue 6 | * @param secondValue 7 | * @return - Equality result 8 | */ 9 | export default (firstValue: ChronosDate, secondValue: ChronosDate): boolean => { 10 | const firstDate = ensureDate(firstValue); 11 | const secondDate = ensureDate(secondValue); 12 | 13 | return firstDate.getFullYear() === secondDate.getFullYear(); 14 | }; 15 | -------------------------------------------------------------------------------- /lib/isTimeValid.ts: -------------------------------------------------------------------------------- 1 | import parseTime from './helpers/parseTime'; 2 | 3 | /** 4 | * Checks if time string is valid 5 | * @param value 6 | * @param format 7 | * @return - Validation result 8 | */ 9 | export default (value: string, format: string): boolean => { 10 | try { 11 | return !!parseTime(value, format); 12 | } catch (e) { 13 | return false; 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /lib/parseDate.ts: -------------------------------------------------------------------------------- 1 | import { ensureDate } from './helpers/ensureDate'; 2 | import { getYear } from '.'; 3 | 4 | /** 5 | * Parse string to Date object 6 | * @param value 7 | * @param [format] 8 | * @return - Date object result 9 | */ 10 | export default (value: string, format?: string): Date => { 11 | if (!value) { 12 | throw new Error('Empty value'); 13 | } 14 | 15 | if (!format) { 16 | return ensureDate(value); 17 | } 18 | 19 | const dateSeparators = /[.,-/\s]/; 20 | const formatArray = format.split(dateSeparators); 21 | const valueArray = value.split(dateSeparators); 22 | 23 | if (formatArray.length > valueArray.length) { 24 | throw new Error(`Format doesn't match value: ${format}, ${value}`); 25 | } 26 | 27 | const dateObj = formatArray.reduce((acc: Record, item: string, i: number) => { 28 | if (item === 'YYYY') { 29 | acc.year = valueArray[i].length === 4 && +valueArray[i]; 30 | } else if (item === 'YY') { 31 | const hundreds = valueArray[i] > getYear(new Date()).toString().slice(-2) ? 19 : 20; 32 | acc.year = valueArray[i].length === 2 && +`${hundreds}${valueArray[i]}`; 33 | } else if (item === 'MM') { 34 | acc.month = +valueArray[i] <= 12 && +valueArray[i] - 1; 35 | } else if (item === 'D' || item === 'DD') { 36 | acc.date = +valueArray[i] <= 31 && +valueArray[i]; 37 | } else { 38 | throw new Error(`Unknown format item: ${item}`); 39 | } 40 | 41 | return acc; 42 | }, {}); 43 | 44 | if (Object.keys(dateObj).some(key => dateObj[key] === false)) { 45 | throw new Error(`Invalid value: ${value}`); 46 | } 47 | 48 | return ensureDate(new Date(+dateObj.year, +dateObj.month, +dateObj.date)); 49 | }; 50 | -------------------------------------------------------------------------------- /lib/subtractCalendarMonths.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate } from './helpers/ensureDate'; 2 | import addCalendarMonths from './addCalendarMonths'; 3 | 4 | /** 5 | * Subtract months from date 6 | * @param value 7 | * @param quantity 8 | * @return - Subtraction result 9 | */ 10 | export default (value: ChronosDate, quantity: number): Date => addCalendarMonths(value, -quantity); 11 | -------------------------------------------------------------------------------- /lib/subtractDays.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate } from './helpers/ensureDate'; 2 | import addDays from './addDays'; 3 | 4 | /** 5 | * Subtract days from date 6 | * @param value 7 | * @param quantity 8 | * @return - Subtraction result 9 | */ 10 | export default (value: ChronosDate, quantity: number): Date => addDays(value, -quantity); 11 | -------------------------------------------------------------------------------- /lib/subtractHours.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate } from './helpers/ensureDate'; 2 | import addHours from './addHours'; 3 | 4 | /** 5 | * Subtract hours from date 6 | * @param value 7 | * @param quantity 8 | * @return - Subtraction result 9 | */ 10 | export default (value: ChronosDate, quantity: number): Date => addHours(value, -quantity); 11 | -------------------------------------------------------------------------------- /lib/subtractMinutes.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate } from './helpers/ensureDate'; 2 | import addMinutes from './addMinutes'; 3 | 4 | /** 5 | * Subtract minutes from date 6 | * @param value 7 | * @param quantity 8 | * @return - Subtraction result 9 | */ 10 | export default (value: ChronosDate, quantity: number): Date => addMinutes(value, -quantity); 11 | -------------------------------------------------------------------------------- /lib/subtractMonths.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate } from './helpers/ensureDate'; 2 | import addMonths from './addMonths'; 3 | 4 | /** 5 | * Subtract months from date 6 | * @param value 7 | * @param quantity 8 | * @return - Subtraction result 9 | */ 10 | export default (value: ChronosDate, quantity: number): Date => addMonths(value, -quantity); 11 | -------------------------------------------------------------------------------- /lib/subtractYears.ts: -------------------------------------------------------------------------------- 1 | import { ChronosDate } from './helpers/ensureDate'; 2 | import addYears from './addYears'; 3 | 4 | /** 5 | * Subtract years from date 6 | * @param value 7 | * @param quantity 8 | * @return - Subtraction result 9 | */ 10 | export default (value: ChronosDate, quantity: number): Date => addYears(value, -quantity); 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@funboxteam/chronos", 3 | "version": "5.0.3", 4 | "description": "One library to rule the time", 5 | "main": "dist/cjs/index.js", 6 | "module": "dist/esm/index.js", 7 | "sideEffects": false, 8 | "author": "Natalia Andreychenko (https://github.com/natrey)", 9 | "license": "MIT", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/funbox/chronos" 13 | }, 14 | "files": [ 15 | "dist/", 16 | "MIGRATION.md", 17 | "CHANGELOG.md" 18 | ], 19 | "types": "dist/types/", 20 | "scripts": { 21 | "build": "npm run clean && npm run build-esm-and-types && npm run build-cjs", 22 | "build-cjs": "tsc --outDir ./dist/cjs --module CommonJS", 23 | "build-esm-and-types": "tsc --outDir ./dist/esm --module ES6 --declaration true --declarationDir ./dist/types", 24 | "clean": "rm -rf dist/", 25 | "lint": "eslint --cache -c .eslintrc.js --ext .ts lib tests", 26 | "prebuild": "npm run lint", 27 | "prepublishOnly": "if [ -z \"$CI\" ]; then lawyer; fi && npm run build", 28 | "test": "npm run lint && nyc mocha -- --require ts-node/register tests/*.ts", 29 | "start": "nodemon -e ts,js,json --exec 'npm test'", 30 | "coverage": "mkdir -p ./coverage/ && nyc report --reporter=text-lcov > ./coverage/lcov.info", 31 | "prepack": "npm run build" 32 | }, 33 | "devDependencies": { 34 | "@funboxteam/eslint-config": "7.3.0", 35 | "@types/chai": "4.2.11", 36 | "@types/chai-datetime": "0.0.37", 37 | "@types/mocha": "8.0.0", 38 | "@types/node": "14.6.0", 39 | "@typescript-eslint/eslint-plugin": "5.59.7", 40 | "@typescript-eslint/parser": "5.59.7", 41 | "chai": "4.2.0", 42 | "chai-datetime": "1.5.0", 43 | "eslint": "7.32.0", 44 | "husky": "3.0.8", 45 | "lint-staged": "10.2.11", 46 | "mocha": "10.2.0", 47 | "nodemon": "2.0.20", 48 | "nyc": "15.1.0", 49 | "ts-node": "8.10.2", 50 | "typescript": "3.9.6" 51 | }, 52 | "husky": { 53 | "hooks": { 54 | "pre-commit": "lint-staged -q" 55 | } 56 | }, 57 | "lint-staged": { 58 | "lib/**/*.{js,ts}": [ 59 | "eslint --fix --cache -c .eslintrc.js" 60 | ], 61 | "tests/**/*.js": [ 62 | "eslint --fix --cache -c tests/.eslintrc.js" 63 | ] 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/index.ts: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'mocha'; 2 | import { use as chaiUse, expect } from 'chai'; 3 | import chaiDatetime from 'chai-datetime'; 4 | 5 | import { 6 | addMinutes, 7 | addHours, 8 | addDays, 9 | addMonths, 10 | addCalendarMonths, 11 | addYears, 12 | subtractMinutes, 13 | subtractHours, 14 | subtractDays, 15 | subtractMonths, 16 | subtractCalendarMonths, 17 | subtractYears, 18 | formatDate, 19 | formatTimeString, 20 | getHours, 21 | getMinutes, 22 | getDay, 23 | getMonth, 24 | getYear, 25 | getWeekdayName, 26 | getMonthName, 27 | getDuration, 28 | isSameMinute, 29 | isSameHour, 30 | isSameDay, 31 | isSameMonth, 32 | isSameYear, 33 | getDiffInMinutes, 34 | getDiffInHours, 35 | getDiffInDays, 36 | getDiffInCalendarDays, 37 | getDiffInMonths, 38 | getDiffInCalendarMonths, 39 | getDiffInYears, 40 | getDiffInCalendarYears, 41 | getStartOfMinutes, 42 | getStartOfHours, 43 | getStartOfDay, 44 | getStartOfWeek, 45 | getStartOfMonth, 46 | getStartOfYear, 47 | getStartOfDecade, 48 | getEndOfMinutes, 49 | getEndOfHours, 50 | getEndOfDay, 51 | getEndOfWeek, 52 | getEndOfMonth, 53 | getEndOfYear, 54 | getEndOfDecade, 55 | getRelativeDate, 56 | getUtcOffset, 57 | getUnixTimestamp, 58 | getTimezoneName, 59 | isTimeValid, 60 | parseDate, 61 | } from '../lib'; 62 | 63 | chaiUse(chaiDatetime); 64 | 65 | const newYear2020UnixTime = new Date(2020, 0, 1).getTime() / 1e3; 66 | const localUTCOffset = `0${Math.abs(getUtcOffset(new Date(2020, 0, 1)))}`.slice(-2); 67 | 68 | describe('addMinutes, addHours, addDays, addMonths, addCalendarMonths, addYears', () => { 69 | it('adds 1 minute', () => { 70 | expect(addMinutes(newYear2020UnixTime, 1)).to.equalTime(new Date(2020, 0, 1, 0, 1)); 71 | }); 72 | 73 | it('adds 1 hour', () => { 74 | expect(addHours(newYear2020UnixTime, 1)).to.equalTime(new Date(2020, 0, 1, 1)); 75 | }); 76 | 77 | it('adds 1 day', () => { 78 | expect(addDays(newYear2020UnixTime, 1)).to.equalTime(new Date(2020, 0, 2)); 79 | }); 80 | 81 | it('adds 1 full month', () => { 82 | expect(addMonths(newYear2020UnixTime, 1)).to.equalTime(new Date(2020, 1, 1)); 83 | }); 84 | 85 | it('adds 1 full month to the end of the month w/ overflowing', () => { 86 | expect(addMonths(new Date(2020, 0, 31), 1)).to.equalTime(new Date(2020, 2, 2)); 87 | }); 88 | 89 | it('adds 1 full month to the end of the month w/o overflowing', () => { 90 | expect(addMonths(new Date(2020, 1, 28), 1)).to.equalTime(new Date(2020, 2, 28)); 91 | }); 92 | 93 | it('adds 1 calendar month', () => { 94 | expect(addCalendarMonths(newYear2020UnixTime, 1)).to.equalTime(new Date(2020, 1, 1)); 95 | }); 96 | 97 | it('adds 1 calendar month to the end of the month', () => { 98 | expect(addCalendarMonths(new Date(2023, 0, 31), 1)).to.equalTime(new Date(2023, 1, 28)); 99 | expect(addCalendarMonths(new Date(2023, 1, 28), 1)).to.equalTime(new Date(2023, 2, 28)); 100 | expect(addCalendarMonths(new Date(2023, 4, 31, 15), 1)).to.equalTime(new Date(2023, 5, 30, 15)); 101 | }); 102 | 103 | it('adds 1 year', () => { 104 | expect(addYears(newYear2020UnixTime, 1)).to.equalTime(new Date(2021, 0, 1)); 105 | }); 106 | }); 107 | 108 | describe('subtractMinutes, subtractHours, subtractDays, subtractMonths, subtractCalendarMonths, subtractYears', () => { 109 | it('subtracts 1 minute', () => { 110 | expect(subtractMinutes(newYear2020UnixTime, 1)).to.equalTime(new Date(2019, 11, 31, 23, 59)); 111 | }); 112 | 113 | it('subtracts 1 hour', () => { 114 | expect(subtractHours(newYear2020UnixTime, 1)).to.equalTime(new Date(2019, 11, 31, 23)); 115 | }); 116 | 117 | it('subtracts 1 day', () => { 118 | expect(subtractDays(newYear2020UnixTime, 1)).to.equalTime(new Date(2019, 11, 31)); 119 | }); 120 | 121 | it('subtracts 1 full month', () => { 122 | expect(subtractMonths(newYear2020UnixTime, 1)).to.equalTime(new Date(2019, 11, 1)); 123 | }); 124 | 125 | it('subtracts 1 full month from the end of the month w/ overflowing', () => { 126 | expect(subtractMonths(new Date(2020, 2, 31), 1)).to.equalTime(new Date(2020, 2, 2)); 127 | }); 128 | 129 | it('subtracts 1 full month from the end of the month w/o overflowing', () => { 130 | expect(subtractMonths(new Date(2020, 1, 29), 1)).to.equalTime(new Date(2020, 0, 29)); 131 | }); 132 | 133 | it('subtracts 1 calendar month', () => { 134 | expect(subtractCalendarMonths(newYear2020UnixTime, 1)).to.equalTime(new Date(2019, 11, 1)); 135 | }); 136 | 137 | it('subtracts 1 calendar month from the end of the month', () => { 138 | expect(subtractCalendarMonths(new Date(2023, 1, 28), 1)).to.equalTime(new Date(2023, 0, 28)); 139 | expect(subtractCalendarMonths(new Date(2023, 2, 31), 1)).to.equalTime(new Date(2023, 1, 28)); 140 | expect(subtractCalendarMonths(new Date(2023, 5, 30, 15), 1)).to.equalTime(new Date(2023, 4, 30, 15)); 141 | expect(subtractCalendarMonths(new Date(2023, 4, 31, 18), 1)).to.equalTime(new Date(2023, 3, 30, 18)); 142 | }); 143 | 144 | it('subtracts 1 year', () => { 145 | expect(subtractYears(newYear2020UnixTime, 1)).to.equalTime(new Date(2019, 0, 1)); 146 | }); 147 | }); 148 | 149 | describe('formatDate', () => { 150 | it('formats unix timestamp to \'HH:mm:ss\'', () => { 151 | expect(formatDate(newYear2020UnixTime, 'HH:mm:ss')).to.equal('00:00:00'); 152 | }); 153 | 154 | it('formats unix timestamp to \'DD.MM.YYYY\'', () => { 155 | expect(formatDate(newYear2020UnixTime, 'DD.MM.YYYY')).to.equal('01.01.2020'); 156 | }); 157 | 158 | it('formats unix timestamp to \'D MMM YYYY\'', () => { 159 | expect(formatDate(newYear2020UnixTime, 'D MMM YYYY')).to.equal('1 янв. 2020'); 160 | }); 161 | 162 | it('formats Date instance to \'YYYY-MM-DD\'', () => { 163 | expect(formatDate(new Date(2020, 0, 1), 'YYYY-MM-DD')).to.equal('2020-01-01'); 164 | }); 165 | 166 | it('formats Date instance to \'YYYY-MM-DDTHH:mm:ssZ\'', () => { 167 | const formattedDateRegexp = new RegExp(`^2020-01-01T00:00:00[+-]${localUTCOffset}:00$`); 168 | expect(formatDate(new Date(2020, 0, 1), 'YYYY-MM-DDTHH:mm:ssZ')).to.match(formattedDateRegexp); 169 | }); 170 | 171 | it('formats Date instance to \'YYYY-MM-DDTHH:mm:ssZZ\'', () => { 172 | const formattedDateRegexp = new RegExp(`^2020-01-01T00:00:00[+-]${localUTCOffset}00$`); 173 | expect(formatDate(new Date(2020, 0, 1), 'YYYY-MM-DDTHH:mm:ssZZ')).to.match(formattedDateRegexp); 174 | }); 175 | 176 | it('formats Date instance to \'dddd, DD.MM.YYYY в HH:mm:ss\'', () => { 177 | expect(formatDate(new Date(2020, 0, 1), 'dddd, DD.MM.YYYY в HH:mm:ss')).to.equal('среда, 01.01.2020 в 00:00:00'); 178 | }); 179 | 180 | it('formats Date instance of midnight to \'HH\' as 00', () => { 181 | expect(formatDate(new Date(2020, 0, 1, 0), 'HH')).to.equal('00'); 182 | }); 183 | 184 | it('formats Date instance of midday to \'HH\' as 12', () => { 185 | expect(formatDate(new Date(2020, 0, 1, 12), 'HH')).to.equal('12'); 186 | }); 187 | }); 188 | 189 | describe('formatTimeString', () => { 190 | it('returns string formatted as \'HH:mm:ss\'', () => { 191 | expect(formatTimeString('1:30', 'H:mm', 'HH:mm:ss')).to.equal('01:30:00'); 192 | }); 193 | 194 | it('returns string formatted as \'H:mm:ss\'', () => { 195 | expect(formatTimeString('1:30', 'H:mm', 'H:mm:ss')).to.equal('1:30:00'); 196 | }); 197 | 198 | it('returns string formatted as \'mm:ss\'', () => { 199 | expect(formatTimeString('11:30', 'mm:ss', 'HH:mm:ss')).to.equal('00:11:30'); 200 | }); 201 | 202 | it('returns 00 hours string formatted as \'HH:mm:ss\'', () => { 203 | expect(formatTimeString('00', 'HH', 'HH:mm:ss')).to.equal('00:00:00'); 204 | }); 205 | 206 | it('returns 00 minutes string formatted as \'HH:mm:ss\'', () => { 207 | expect(formatTimeString('00', 'mm', 'HH:mm:ss')).to.equal('00:00:00'); 208 | }); 209 | 210 | it('returns 00 seconds string formatted as \'HH:mm:ss\'', () => { 211 | expect(formatTimeString('00', 'mm', 'HH:mm:ss')).to.equal('00:00:00'); 212 | }); 213 | 214 | it('throws an error when get invalid time', () => { 215 | expect(() => formatTimeString('33:30', 'HH:mm', 'HH:mm:ss')).to.throw('Invalid value: 33:30'); 216 | }); 217 | 218 | it('throws an error when get empty string as value', () => { 219 | expect(() => formatTimeString('', 'HH', 'HH:mm:ss')).to.throw('Empty value'); 220 | }); 221 | 222 | it('throws an error when get empty string as format', () => { 223 | expect(() => formatTimeString('00', '', 'HH:mm:ss')).to.throw('Empty format'); 224 | }); 225 | 226 | it('throws an error when format does not match time', () => { 227 | expect(() => formatTimeString('00', 'HH:mm:ss', 'HH:mm:ss')).to.throw('Format doesn\'t match time: HH:mm:ss, 00'); 228 | }); 229 | }); 230 | 231 | describe('getMinutes, getHours, getDay, getMonth, getYear', () => { 232 | it('returns minute of unix timestamp', () => { 233 | expect(getMinutes(newYear2020UnixTime)).to.equal(0); 234 | }); 235 | 236 | it('returns hour of unix timestamp', () => { 237 | expect(getHours(newYear2020UnixTime)).to.equal(0); 238 | }); 239 | 240 | it('returns day of unix timestamp', () => { 241 | expect(getDay(newYear2020UnixTime)).to.equal(1); 242 | }); 243 | 244 | it('returns month of unix timestamp', () => { 245 | expect(getMonth(newYear2020UnixTime)).to.equal(0); 246 | }); 247 | 248 | it('returns year of unix timestamp', () => { 249 | expect(getYear(newYear2020UnixTime)).to.equal(2020); 250 | }); 251 | }); 252 | 253 | describe('getWeekdayName, getMonthName', () => { 254 | it('returns weekday name in short format', () => { 255 | expect(getWeekdayName(newYear2020UnixTime, 'short')).to.eql('ср'); 256 | }); 257 | 258 | it('returns weekday name in long format', () => { 259 | expect(getWeekdayName(newYear2020UnixTime, 'long')).to.eql('среда'); 260 | }); 261 | 262 | it('returns weekday name in long format by default', () => { 263 | expect(getWeekdayName(newYear2020UnixTime)).to.eql('среда'); 264 | }); 265 | 266 | it('returns month name in short format', () => { 267 | expect(getMonthName(newYear2020UnixTime, 'short')).to.eql('янв.'); 268 | }); 269 | 270 | it('returns month name in long format', () => { 271 | expect(getMonthName(newYear2020UnixTime, 'long')).to.eql('январь'); 272 | }); 273 | 274 | it('returns month name in long format by default', () => { 275 | expect(getMonthName(newYear2020UnixTime)).to.eql('январь'); 276 | }); 277 | }); 278 | 279 | describe('getDuration', () => { 280 | it('returns duration as days, hours and minutes', () => { 281 | expect(getDuration(1000000)).to.deep.equal({ days: 11, hours: 13, minutes: 46, seconds: 40 }); 282 | }); 283 | 284 | it('returns duration as hours and minutes', () => { 285 | expect(getDuration(10000)).to.deep.equal({ days: 0, hours: 2, minutes: 46, seconds: 40 }); 286 | }); 287 | 288 | it('returns duration as minutes', () => { 289 | expect(getDuration(1000)).to.deep.equal({ days: 0, hours: 0, minutes: 16, seconds: 40 }); 290 | }); 291 | }); 292 | 293 | describe('isSameMinute, isSameHour, isSameDay, isSameMonth, isSameYear', () => { 294 | it('compares same minutes', () => { 295 | expect(isSameMinute(new Date(2020, 0, 1, 23, 50), new Date(2020, 0, 1, 23, 50, 30))).to.equal(true); 296 | }); 297 | 298 | it('compares different minutes', () => { 299 | expect(isSameMinute(new Date(2020, 0, 1, 23, 50), new Date(2019, 0, 1, 23, 51))).to.equal(false); 300 | }); 301 | 302 | it('compares different minutes of different years', () => { 303 | expect(isSameMinute(new Date(2020, 0, 1, 23), new Date(2019, 0, 1, 23))).to.equal(false); 304 | }); 305 | 306 | it('compares same hours', () => { 307 | expect(isSameHour(new Date(2020, 0, 1, 23), new Date(2020, 0, 1, 23, 50))).to.equal(true); 308 | }); 309 | 310 | it('compares different hours', () => { 311 | expect(isSameHour(new Date(2020, 0, 1, 23), new Date(2019, 0, 1, 22))).to.equal(false); 312 | }); 313 | 314 | it('compares different hours of different years', () => { 315 | expect(isSameHour(new Date(2020, 0, 1, 23), new Date(2019, 0, 1, 23))).to.equal(false); 316 | }); 317 | 318 | it('compares same days', () => { 319 | expect(isSameDay(new Date(2020, 0, 1), new Date(2020, 0, 1, 5))).to.equal(true); 320 | }); 321 | 322 | it('compares different days', () => { 323 | expect(isSameDay(new Date(2020, 0, 1), new Date(2019, 0, 2))).to.equal(false); 324 | }); 325 | 326 | it('compares different days of different years', () => { 327 | expect(isSameDay(new Date(2020, 0, 1), new Date(2019, 0, 1))).to.equal(false); 328 | }); 329 | 330 | it('compares same months', () => { 331 | expect(isSameMonth(new Date(2020, 0, 1), new Date(2020, 0, 2))).to.equal(true); 332 | }); 333 | 334 | it('compares different months', () => { 335 | expect(isSameMonth(new Date(2020, 0, 1), new Date(2019, 1, 1))).to.equal(false); 336 | }); 337 | 338 | it('compares different months of different years', () => { 339 | expect(isSameMonth(new Date(2020, 0, 1), new Date(2019, 0, 1))).to.equal(false); 340 | }); 341 | 342 | it('compares same years', () => { 343 | expect(isSameYear(new Date(2020, 0, 1), new Date(2020, 0, 2))).to.equal(true); 344 | }); 345 | 346 | it('compares different years', () => { 347 | expect(isSameYear(new Date(2020, 0, 1), new Date(2019, 11, 31))).to.equal(false); 348 | }); 349 | }); 350 | 351 | describe('getDiffInMinutes, getDiffInHours, getDiffInDays, getDiffInCalendarDays, getDiffInMonths, getDiffInCalendarMonths, getDiffInYears, getDiffInCalendarYears', () => { 352 | it('returns diff in minutes', () => { 353 | expect(getDiffInMinutes(new Date(2020, 0, 1), new Date(2020, 0, 1, 1))).to.equal(-60); 354 | }); 355 | 356 | it('returns diff in minutes of two unix timestamps', () => { 357 | expect(getDiffInMinutes(1572348594627, 1572348283627)).to.equal(5); 358 | }); 359 | 360 | it('returns diff in minutes of different days', () => { 361 | expect(getDiffInMinutes(new Date(2020, 0, 1), new Date(2020, 0, 2, 1))).to.equal(-(60 * 25)); 362 | }); 363 | 364 | it('returns 0 when diff in minutes in [0; 1)', () => { 365 | expect(getDiffInMinutes(new Date(2020, 0, 1, 0, 0, 59), new Date(2020, 0, 1, 0, 0, 0))).to.equal(0); 366 | }); 367 | 368 | it('returns 0 when diff in minutes in (-1; 0]', () => { 369 | expect(getDiffInMinutes(new Date(2020, 0, 1, 0, 0, 0), new Date(2020, 0, 1, 0, 0, 59))).to.equal(0); 370 | }); 371 | 372 | it('returns diff in hours', () => { 373 | expect(getDiffInHours(new Date(2020, 0, 1, 5), new Date(2020, 0, 1))).to.equal(5); 374 | }); 375 | 376 | it('returns diff in hours of different days', () => { 377 | expect(getDiffInHours(new Date(2020, 0, 2, 5), new Date(2020, 0, 1))).to.equal(29); 378 | }); 379 | 380 | it('returns 0 when diff in hours in [0; 1)', () => { 381 | expect(getDiffInHours(new Date(2020, 0, 1, 0, 59), new Date(2020, 0, 1, 0, 0))).to.equal(0); 382 | }); 383 | 384 | it('returns 0 when diff in hours in (-1; 0]', () => { 385 | expect(getDiffInHours(new Date(2020, 0, 1, 0, 0), new Date(2020, 0, 1, 0, 59))).to.equal(0); 386 | }); 387 | 388 | it('returns diff in days of two unix timestamps', () => { 389 | expect(getDiffInDays(1572348594627, 1572248594627)).to.equal(1); 390 | }); 391 | 392 | it('returns diff in days of different years', () => { 393 | expect(getDiffInDays(new Date(2019, 0, 1), new Date(2020, 0, 5))).to.equal(-369); 394 | }); 395 | 396 | it('returns 0 when diff in days in [0; 1)', () => { 397 | expect(getDiffInDays(new Date(2020, 0, 1, 23), new Date(2020, 0, 1, 0))).to.equal(0); 398 | }); 399 | 400 | it('returns 0 when diff in days in (-1; 0]', () => { 401 | expect(getDiffInDays(new Date(2020, 0, 1, 0), new Date(2020, 0, 1, 23))).to.equal(0); 402 | }); 403 | 404 | it('returns diff in calendar days', () => { 405 | expect(getDiffInCalendarDays(new Date(2023, 0, 2, 0, 1), new Date(2023, 0, 1, 23, 59))).to.equal(1); 406 | }); 407 | 408 | it('returns diff in calendar days of different years', () => { 409 | expect(getDiffInCalendarDays(new Date(2019, 3, 1, 23), new Date(2020, 3, 1))).to.equal(-366); 410 | }); 411 | 412 | it('returns diff in full months', () => { 413 | expect(getDiffInMonths(new Date(2023, 0, 31), new Date(2023, 1, 28))).to.equal(0); 414 | expect(getDiffInMonths(new Date(2023, 1, 28), new Date(2023, 0, 31))).to.equal(0); 415 | 416 | expect(getDiffInMonths(new Date(2023, 1, 28), new Date(2023, 2, 28))).to.equal(-1); 417 | expect(getDiffInMonths(new Date(2023, 2, 28), new Date(2023, 1, 28))).to.equal(1); 418 | 419 | expect(getDiffInMonths(new Date(2023, 1, 28), new Date(2023, 2, 31))).to.equal(-1); 420 | expect(getDiffInMonths(new Date(2023, 2, 31), new Date(2023, 1, 28))).to.equal(1); 421 | 422 | expect(getDiffInMonths(new Date(2023, 0, 30), new Date(2023, 3, 15))).to.equal(-2); 423 | }); 424 | 425 | it('returns diff in full months of different years', () => { 426 | expect(getDiffInMonths(new Date(2022, 0, 5), new Date(2023, 4, 1))).to.equal(-15); 427 | expect(getDiffInMonths(new Date(2023, 4, 1), new Date(2022, 0, 5))).to.equal(15); 428 | }); 429 | 430 | it('returns diff in calendar months', () => { 431 | expect(getDiffInCalendarMonths(new Date(2020, 0, 1), new Date(2020, 4, 1))).to.equal(-4); 432 | }); 433 | 434 | it('returns diff in calendar months of different years', () => { 435 | expect(getDiffInCalendarMonths(new Date(2019, 0, 1), new Date(2020, 4, 1))).to.equal(-16); 436 | }); 437 | 438 | it('returns diff in full years', () => { 439 | expect(getDiffInYears(new Date(2020, 0, 1), new Date(2019, 0, 1))).to.equal(1); 440 | expect(getDiffInYears(new Date(2023, 0, 1), new Date(2021, 5, 1))).to.equal(1); 441 | }); 442 | 443 | it('returns diff in calendar years', () => { 444 | expect(getDiffInCalendarYears(new Date(2020, 0, 1), new Date(2019, 0, 1))).to.equal(1); 445 | expect(getDiffInCalendarYears(new Date(2023, 0, 1), new Date(2021, 5, 1))).to.equal(2); 446 | }); 447 | 448 | it('returns diff in years in days', () => { 449 | expect(getDiffInDays(new Date(2020, 0, 1), new Date(2020, 0, 5))).to.equal(-4); 450 | }); 451 | }); 452 | 453 | describe('getStartOfMinutes, getStartOfHours, getStartOfDay, getStartOfWeek, getStartOfMonth, getStartOfYear, getStartOfDecade', () => { 454 | it('returns date of start of minutes', () => { 455 | expect(getStartOfMinutes(new Date(2020, 1, 1, 23, 59, 30))).to.equalTime(new Date(2020, 1, 1, 23, 59, 0)); 456 | }); 457 | 458 | it('returns date of start of minutes + 1', () => { 459 | expect(getStartOfMinutes(new Date(2020, 1, 1, 23, 59, 30), 1)).to.equalTime(new Date(2020, 1, 2, 0, 0, 0)); 460 | }); 461 | 462 | it('returns date of start of minutes - 1', () => { 463 | expect(getStartOfMinutes(new Date(2020, 1, 1, 23, 59, 30), -1)).to.equalTime(new Date(2020, 1, 1, 23, 58, 0)); 464 | }); 465 | 466 | it('returns date of start of hours', () => { 467 | expect(getStartOfHours(new Date(2020, 1, 1, 23, 59))).to.equalTime(new Date(2020, 1, 1, 23, 0)); 468 | }); 469 | 470 | it('returns date of start of hours + 1', () => { 471 | expect(getStartOfHours(new Date(2020, 1, 1, 23, 59), 1)).to.equalTime(new Date(2020, 1, 2, 0, 0)); 472 | }); 473 | 474 | it('returns date of start of hours - 1', () => { 475 | expect(getStartOfHours(new Date(2020, 1, 1, 23, 59), -1)).to.equalTime(new Date(2020, 1, 1, 22, 0)); 476 | }); 477 | 478 | it('returns date of start of day', () => { 479 | const result = getStartOfDay(new Date(2020, 2, 2, 23, 59)); 480 | expect(result.getTime()).to.equal(new Date(2020, 2, 2, 0, 0, 0, 0).getTime()); 481 | }); 482 | 483 | it('returns date of start of day + 1', () => { 484 | const result = getStartOfDay(new Date(2020, 2, 2, 23, 59), 1); 485 | expect(result.getTime()).to.equal(new Date(2020, 2, 3, 0, 0, 0, 0).getTime()); 486 | }); 487 | 488 | it('returns date of start of day - 1', () => { 489 | const result = getStartOfDay(new Date(2020, 2, 2, 23, 59), -1); 490 | expect(result.getTime()).to.equal(new Date(2020, 2, 1, 0, 0, 0, 0).getTime()); 491 | }); 492 | 493 | it('returns date of start of week', () => { 494 | const result = getStartOfWeek(new Date(2020, 0, 1)); 495 | expect(result.getTime()).to.equal(new Date(2019, 11, 30, 0, 0, 0, 0).getTime()); 496 | }); 497 | 498 | it('returns date of start of week when it is already monday', () => { 499 | const result = getStartOfWeek(new Date(2020, 7, 10, 1, 0)); 500 | expect(result.getTime()).to.equal(new Date(2020, 7, 10, 0, 0, 0, 0).getTime()); 501 | }); 502 | 503 | it('returns date of start of week when it is sunday', () => { 504 | const result = getStartOfWeek(new Date(2020, 7, 9, 0, 0)); 505 | expect(result.getTime()).to.equal(new Date(2020, 7, 3, 0, 0, 0, 0).getTime()); 506 | }); 507 | 508 | it('returns date of start of week + 1', () => { 509 | const result = getStartOfWeek(new Date(2020, 0, 1), 1); 510 | expect(result.getTime()).to.equal(new Date(2020, 0, 6, 0, 0, 0, 0).getTime()); 511 | }); 512 | 513 | it('returns date of start of week - 1', () => { 514 | const result = getStartOfWeek(new Date(2020, 0, 1), -1); 515 | expect(result.getTime()).to.equal(new Date(2019, 11, 23, 0, 0, 0, 0).getTime()); 516 | }); 517 | 518 | it('returns date of start of month', () => { 519 | expect(getStartOfMonth(new Date(2020, 2, 2, 23, 59))).to.equalTime(new Date(2020, 2, 1, 0, 0)); 520 | }); 521 | 522 | it('returns date of start of month + 1', () => { 523 | expect(getStartOfMonth(new Date(2020, 2, 2, 23, 59), 1)).to.equalTime(new Date(2020, 3, 1, 0, 0)); 524 | }); 525 | 526 | it('returns date of start of month - 1', () => { 527 | expect(getStartOfMonth(new Date(2020, 2, 2, 23, 59), -1)).to.equalTime(new Date(2020, 1, 1, 0, 0)); 528 | }); 529 | 530 | it('returns date of start of month - 1', () => { 531 | expect(getStartOfMonth(new Date(2023, 2, 31, 23, 59), -1)).to.equalTime(new Date(2023, 1, 1, 0, 0)); 532 | }); 533 | 534 | it('returns date of start of year', () => { 535 | expect(getStartOfYear(new Date(2020, 1, 1, 23, 59))).to.equalTime(new Date(2020, 0, 1, 0, 0)); 536 | }); 537 | 538 | it('returns date of start of year + 1', () => { 539 | expect(getStartOfYear(new Date(2020, 1, 1, 23, 59), 1)).to.equalTime(new Date(2021, 0, 1, 0, 0)); 540 | }); 541 | 542 | it('returns date of start of year - 1', () => { 543 | expect(getStartOfYear(new Date(2020, 1, 1, 23, 59), -1)).to.equalTime(new Date(2019, 0, 1, 0, 0)); 544 | }); 545 | 546 | it('returns date of start of decade', () => { 547 | expect(getStartOfDecade(new Date(2025, 1, 1, 23, 59))).to.equalTime(new Date(2020, 0, 1, 0, 0)); 548 | }); 549 | 550 | it('returns date of start of decade + 1', () => { 551 | expect(getStartOfDecade(new Date(2025, 1, 1, 23, 59), 1)).to.equalTime(new Date(2030, 0, 1, 0, 0)); 552 | }); 553 | 554 | it('returns date of start of decade - 1', () => { 555 | expect(getStartOfDecade(new Date(2025, 1, 1, 23, 59), -1)).to.equalTime(new Date(2010, 0, 1, 0, 0)); 556 | }); 557 | }); 558 | 559 | describe('getEndOfMinutes, getEndOfHours, getEndOfDay, getEndOfWeek, getEndOfMonth, getEndOfYear, getEndOfDecade', () => { 560 | it('returns date of end of minute', () => { 561 | expect(getEndOfMinutes(new Date(2025, 1, 1, 22, 30, 30))).to.equalTime(new Date(2025, 1, 1, 22, 30, 59, 999)); 562 | }); 563 | 564 | it('returns date of end of minute + 1', () => { 565 | expect(getEndOfMinutes(new Date(2025, 1, 1, 23, 30), 1)).to.equalTime(new Date(2025, 1, 1, 23, 31, 59, 999)); 566 | }); 567 | 568 | it('returns date of end of minute - 1', () => { 569 | expect(getEndOfMinutes(new Date(2025, 1, 1, 23, 30), -1)).to.equalTime(new Date(2025, 1, 1, 23, 29, 59, 999)); 570 | }); 571 | 572 | it('returns date of end of hour', () => { 573 | expect(getEndOfHours(new Date(2025, 1, 1, 22, 30))).to.equalTime(new Date(2025, 1, 1, 22, 59, 59, 999)); 574 | }); 575 | 576 | it('returns date of end of hour + 1', () => { 577 | expect(getEndOfHours(new Date(2025, 1, 1, 23, 30), 1)).to.equalTime(new Date(2025, 1, 2, 0, 59, 59, 999)); 578 | }); 579 | 580 | it('returns date of end of hour - 1', () => { 581 | expect(getEndOfHours(new Date(2025, 1, 1, 23, 30), -1)).to.equalTime(new Date(2025, 1, 1, 22, 59, 59, 999)); 582 | }); 583 | 584 | it('returns date of end of day', () => { 585 | const result = getEndOfDay(new Date(2020, 1, 1, 0, 0)); 586 | expect(result.getTime()).to.equal(new Date(2020, 1, 1, 23, 59, 59, 999).getTime()); 587 | }); 588 | 589 | it('returns date of end of day + 1', () => { 590 | const result = getEndOfDay(new Date(2020, 1, 1, 0, 0), 1); 591 | expect(result.getTime()).to.equal(new Date(2020, 1, 2, 23, 59, 59, 999).getTime()); 592 | }); 593 | 594 | it('returns date of end of day - 1', () => { 595 | const result = getEndOfDay(new Date(2020, 1, 1, 0, 0), -1); 596 | expect(result.getTime()).to.equal(new Date(2020, 0, 31, 23, 59, 59, 999).getTime()); 597 | }); 598 | 599 | it('returns date of end of week', () => { 600 | const result = getEndOfWeek(new Date(2020, 0, 1, 0, 0)); 601 | expect(result.getTime()).to.equal(new Date(2020, 0, 5, 23, 59, 59, 999).getTime()); 602 | }); 603 | 604 | it('returns date of end of week when it is already sunday', () => { 605 | const result = getEndOfWeek(new Date(2020, 7, 9, 0, 0)); 606 | expect(result.getTime()).to.equal(new Date(2020, 7, 9, 23, 59, 59, 999).getTime()); 607 | }); 608 | 609 | it('returns date of end of week + 1', () => { 610 | const result = getEndOfWeek(new Date(2020, 0, 1, 0, 0), 1); 611 | expect(result.getTime()).to.equal(new Date(2020, 0, 12, 23, 59, 59, 999).getTime()); 612 | }); 613 | 614 | it('returns date of end of week - 1', () => { 615 | const result = getEndOfWeek(new Date(2020, 0, 1, 0, 0), -1); 616 | expect(result.getTime()).to.equal(new Date(2019, 11, 29, 23, 59, 59, 999).getTime()); 617 | }); 618 | 619 | it('returns date of end of month', () => { 620 | expect(getEndOfMonth(new Date(2020, 1, 1))).to.equalTime(new Date(2020, 1, 29, 23, 59, 59, 999)); 621 | }); 622 | 623 | it('returns date of end of month when current date overflows its month', () => { 624 | expect(getEndOfMonth(new Date(2020, 2, 31))).to.equalDate(new Date(2020, 2, 31, 23, 59, 59, 999)); 625 | }); 626 | 627 | it('returns date of end of month + 1', () => { 628 | expect(getEndOfMonth(new Date(2020, 1, 1), 1)).to.equalTime(new Date(2020, 2, 31, 23, 59, 59, 999)); 629 | }); 630 | 631 | it('returns date of end of month - 1', () => { 632 | expect(getEndOfMonth(new Date(2020, 1, 1), -1)).to.equalTime(new Date(2020, 0, 31, 23, 59, 59, 999)); 633 | }); 634 | 635 | it('returns date of end of year', () => { 636 | expect(getEndOfYear(new Date(2020, 1, 1))).to.equalTime(new Date(2020, 11, 31, 23, 59, 59, 999)); 637 | }); 638 | 639 | it('returns date of end of year + 1', () => { 640 | expect(getEndOfYear(new Date(2020, 1, 1), 1)).to.equalTime(new Date(2021, 11, 31, 23, 59, 59, 999)); 641 | }); 642 | 643 | it('returns date of end of year - 1', () => { 644 | expect(getEndOfYear(new Date(2020, 1, 1), -1)).to.equalTime(new Date(2019, 11, 31, 23, 59, 59, 999)); 645 | }); 646 | 647 | it('returns date of end of decade', () => { 648 | expect(getEndOfDecade(new Date(2025, 1, 1))).to.equalTime(new Date(2029, 11, 31, 23, 59, 59, 999)); 649 | }); 650 | 651 | it('returns date of end of decade + 1', () => { 652 | expect(getEndOfDecade(new Date(2025, 1, 1), 1)).to.equalTime(new Date(2039, 11, 31, 23, 59, 59, 999)); 653 | }); 654 | 655 | it('returns date of end of decade - 1', () => { 656 | expect(getEndOfDecade(new Date(2025, 1, 1), -1)).to.equalTime(new Date(2019, 11, 31, 23, 59, 59, 999)); 657 | }); 658 | }); 659 | 660 | describe('getRelativeDate', () => { 661 | it('returns interval string for less than a minute', () => { 662 | expect(getRelativeDate(new Date())).to.equal('меньше минуты'); 663 | }); 664 | 665 | it('returns interval string for 1 minute', () => { 666 | const date = new Date(); 667 | date.setMinutes(date.getMinutes() - 1); 668 | 669 | expect(getRelativeDate(date)).to.equal('минуту'); 670 | }); 671 | 672 | it('returns interval string for 2 minutes', () => { 673 | const date = new Date(); 674 | date.setMinutes(date.getMinutes() - 2); 675 | 676 | expect(getRelativeDate(date)).to.equal('2 минуты'); 677 | }); 678 | 679 | it('returns interval string for 22 minutes', () => { 680 | const date = new Date(); 681 | date.setMinutes(date.getMinutes() - 22); 682 | 683 | expect(getRelativeDate(date)).to.equal('22 минуты'); 684 | }); 685 | 686 | it('returns interval string for 5 minutes', () => { 687 | const date = new Date(); 688 | date.setMinutes(date.getMinutes() - 5); 689 | 690 | expect(getRelativeDate(date)).to.equal('5 минут'); 691 | }); 692 | 693 | it('returns interval string for 1 hour', () => { 694 | const date = new Date(); 695 | date.setHours(date.getHours() - 1); 696 | 697 | expect(getRelativeDate(date)).to.equal('час'); 698 | }); 699 | 700 | it('returns interval string for 2 hours', () => { 701 | const date = new Date(); 702 | date.setHours(date.getHours() - 2); 703 | 704 | expect(getRelativeDate(date)).to.equal('2 часа'); 705 | }); 706 | 707 | it('returns interval string for 5 hours', () => { 708 | const date = new Date(); 709 | date.setHours(date.getHours() - 5); 710 | 711 | expect(getRelativeDate(date)).to.equal('5 часов'); 712 | }); 713 | 714 | it('returns interval string for 1 day', () => { 715 | const date = new Date(); 716 | date.setDate(date.getDate() - 1); 717 | 718 | expect(getRelativeDate(date)).to.equal('день'); 719 | }); 720 | 721 | it('returns interval string for 2 days', () => { 722 | const date = new Date(); 723 | date.setDate(date.getDate() - 2); 724 | 725 | expect(getRelativeDate(date)).to.equal('2 дня'); 726 | }); 727 | 728 | it('returns interval string for 5 days', () => { 729 | const date = new Date(); 730 | date.setDate(date.getDate() - 5); 731 | 732 | expect(getRelativeDate(date)).to.equal('5 дней'); 733 | }); 734 | 735 | it('returns interval string for 1 month', () => { 736 | const date = new Date(); 737 | date.setMonth(date.getMonth() - 1); 738 | 739 | expect(getRelativeDate(date)).to.equal('месяц'); 740 | }); 741 | 742 | it('returns interval string for 2 months', () => { 743 | const date = new Date(); 744 | date.setMonth(date.getMonth() - 2); 745 | 746 | expect(getRelativeDate(date)).to.equal('2 месяца'); 747 | }); 748 | 749 | it('returns interval string for 5 months', () => { 750 | const date = new Date(); 751 | date.setMonth(date.getMonth() - 5); 752 | 753 | expect(getRelativeDate(date)).to.equal('5 месяцев'); 754 | }); 755 | 756 | it('returns interval string for 1 year', () => { 757 | const date = new Date(); 758 | date.setFullYear(date.getFullYear() - 1); 759 | 760 | expect(getRelativeDate(date)).to.equal('год'); 761 | }); 762 | 763 | it('returns interval string for 2 years', () => { 764 | const date = new Date(); 765 | date.setFullYear(date.getFullYear() - 2); 766 | 767 | expect(getRelativeDate(date)).to.equal('2 года'); 768 | }); 769 | 770 | it('returns interval string for 5 years', () => { 771 | const date = new Date(); 772 | date.setFullYear(date.getFullYear() - 5); 773 | 774 | expect(getRelativeDate(date)).to.equal('5 лет'); 775 | }); 776 | }); 777 | 778 | describe('getUtcOffset', () => { 779 | it('returns UTC offset in hours', () => { 780 | expect(getUtcOffset(new Date(2020, 0, 1))).to.equal(+localUTCOffset); 781 | }); 782 | }); 783 | 784 | describe('getUnixTimestamp', () => { 785 | it('returns unix timestamp from Date instance', () => { 786 | expect(getUnixTimestamp(new Date(2020, 0, 1))).to.equal(newYear2020UnixTime); 787 | }); 788 | 789 | it('returns unix timestamp from timestamp in ms', () => { 790 | expect(getUnixTimestamp(newYear2020UnixTime * 1e3)).to.equal(newYear2020UnixTime); 791 | }); 792 | 793 | it('returns unix timestamp from timestamp in s', () => { 794 | expect(getUnixTimestamp(newYear2020UnixTime)).to.equal(newYear2020UnixTime); 795 | }); 796 | 797 | it('returns current unix timestamp if nothing passed', () => { 798 | expect(getUnixTimestamp()).to.equal(Math.floor(new Date().getTime() / 1000)); 799 | }); 800 | }); 801 | 802 | describe('getTimezoneName', () => { 803 | it('returns name of the current timezone', () => { 804 | expect(getTimezoneName()).to.equal(Intl.DateTimeFormat().resolvedOptions().timeZone); 805 | }); 806 | }); 807 | 808 | describe('isTimeValid', () => { 809 | it('passes correct time string formatted as \'H:mm\'', () => { 810 | expect(isTimeValid('1:30', 'H:mm')).to.equal(true); 811 | }); 812 | 813 | it('does not pass incorrect time string formatted as \'H:mm\'', () => { 814 | expect(isTimeValid('100:30', 'H:mm')).to.equal(false); 815 | }); 816 | 817 | it('passes correct time string formatted as \'HH:mm\'', () => { 818 | expect(isTimeValid('22:30', 'HH:mm')).to.equal(true); 819 | }); 820 | 821 | it('does not pass incorrect time string formatted as \'HH:mm\'', () => { 822 | expect(isTimeValid('25:30', 'HH:mm')).to.equal(false); 823 | }); 824 | 825 | it('does not pass incorrect time string formatted as \'HH:mm:ss\'', () => { 826 | expect(isTimeValid('25:30:80', 'HH:mm:ss')).to.equal(false); 827 | }); 828 | 829 | it('does not pass empty string as a time string', () => { 830 | expect(isTimeValid('', 'HH:mm:ss')).to.equal(false); 831 | }); 832 | }); 833 | 834 | describe('parseDate', () => { 835 | it('throws when empty value is passed', () => { 836 | expect(() => parseDate('', '')).to.throw('Empty value'); 837 | }); 838 | 839 | it('throws when format has more parts than value', () => { 840 | expect(() => parseDate('2000-01', 'YYYY-MM-DD')).to.throw('Format doesn\'t match value: YYYY-MM-DD, 2000-01'); 841 | }); 842 | 843 | it('parses the string formatted as \'YYYY-MM-DD\'', () => { 844 | expect(parseDate('2000-01-01', 'YYYY-MM-DD')).to.equalTime(new Date(2000, 0, 1)); 845 | }); 846 | 847 | it('parses the string formatted as \'DD.MM.YYYY\'', () => { 848 | expect(parseDate('31.12.2019', 'DD.MM.YYYY')).to.equalTime(new Date(2019, 11, 31)); 849 | }); 850 | 851 | it('parses the string formatted as \'D.MM.YYYY\'', () => { 852 | expect(parseDate('1.12.2019', 'D.MM.YYYY')).to.equalTime(new Date(2019, 11, 1)); 853 | }); 854 | 855 | it('parses the string formatted as \'DD.MM.YY\'', () => { 856 | expect(parseDate('01.01.01', 'DD.MM.YY')).to.equalTime(new Date(2001, 0, 1)); 857 | }); 858 | 859 | it('parses the string formatted as \'DD.MM.YY\' where YY is from 20th century', () => { 860 | expect(parseDate('01.01.99', 'DD.MM.YY')).to.equalTime(new Date(1999, 0, 1)); 861 | }); 862 | 863 | it('throws when string formatted as \'D.MM.YYYY\' does not contain valid date', () => { 864 | expect(() => parseDate('1.120.2019', 'D.MM.YYYY')).to.throw('Invalid value: 1.120.2019'); 865 | }); 866 | 867 | it('throws when string formatted as \'DD.MM.YYYY\' does not contain valid date', () => { 868 | expect(() => parseDate('99.99.2019', 'D.MM.YYYY')).to.throw('Invalid value: 99.99.2019'); 869 | }); 870 | 871 | it('throws when unknown format item is passed', () => { 872 | expect(() => parseDate('01.01.2019', 'AA.MM.YYYY')).to.throw('Unknown format item: AA'); 873 | }); 874 | 875 | it('returns parse the string formatted as ISO 8601 but w/o explicit format set', () => { 876 | expect(parseDate(`2020-01-01T00:00:00+${localUTCOffset}:00`)).to.equalTime(new Date(2020, 0, 1)); 877 | }); 878 | 879 | it('throws when string is not formatted as ISO 8601 and the format is not passed', () => { 880 | expect(() => parseDate('1.120.2019')).to.throw('Invalid date value: 1.120.2019'); 881 | }); 882 | }); 883 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["lib/**/*", "tests"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://www.typescriptlang.org/docs/handbook/compiler-options.html to read more about this file */ 4 | 5 | /* Basic Options */ 6 | "target": "es5", 7 | "module": "commonjs", 8 | "lib": ["dom", "es6"], 9 | "types" : ["node", "mocha", "chai"], 10 | 11 | /* Strict Type-Checking Options */ 12 | "noEmitOnError": true, 13 | "noImplicitAny": true, 14 | "strictNullChecks": true, 15 | "strictFunctionTypes": true, 16 | "noImplicitThis": true, 17 | /* Module Resolution Options */ 18 | "moduleResolution": "node", 19 | 20 | /* Advanced Options */ 21 | "forceConsistentCasingInFileNames": true, 22 | "esModuleInterop": true 23 | }, 24 | "include": ["lib/**/*"], 25 | "exclude": ["node_modules", "dist"] 26 | } 27 | --------------------------------------------------------------------------------