├── .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 |
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 | [](https://funbox.ru)
553 |
--------------------------------------------------------------------------------
/README.ru.md:
--------------------------------------------------------------------------------
1 |
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 | [](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