chrono-ms 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +334 -0
- package/dist/constants.d.ts +11 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/format.d.ts +19 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/index.cjs +264 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +249 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +168 -0
- package/dist/index.js.map +1 -0
- package/dist/ms.d.ts +19 -0
- package/dist/ms.d.ts.map +1 -0
- package/dist/parse.d.ts +49 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +75 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Francisco Luis Rios Vega
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# chrono-ms
|
|
2
|
+
|
|
3
|
+
A lightweight, TypeScript-first library for parsing and formatting time durations.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/chrono-ms)
|
|
6
|
+
[](https://www.npmjs.com/package/chrono-ms)
|
|
7
|
+
[](https://www.npmjs.com/package/chrono-ms)
|
|
8
|
+
[](https://github.com/iscodex/chrono-ms/actions)
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- ๐ **Lightweight**: Zero dependencies
|
|
13
|
+
- ๐ **TypeScript-first**: Full type safety and IntelliSense support
|
|
14
|
+
- ๐ **Bidirectional**: Parse strings to milliseconds and format milliseconds to strings
|
|
15
|
+
- ๐ฏ **Precise**: Handles decimal values and negative numbers
|
|
16
|
+
- ๐ **Comprehensive**: Supports all common time units including months
|
|
17
|
+
- ๐งช **Well-tested**: >95% test coverage
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install chrono-ms
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
yarn add chrono-ms
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pnpm add chrono-ms
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
### Basic Usage
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import ms from 'chrono-ms';
|
|
39
|
+
|
|
40
|
+
// Parse string to milliseconds
|
|
41
|
+
ms('2 hours'); // 7200000
|
|
42
|
+
ms('1d'); // 86400000
|
|
43
|
+
ms('10h'); // 36000000
|
|
44
|
+
ms('2.5 hrs'); // 9000000
|
|
45
|
+
ms('1y'); // 31557600000
|
|
46
|
+
|
|
47
|
+
// Format milliseconds to string
|
|
48
|
+
ms(60000); // "1m"
|
|
49
|
+
ms(2 * 60 * 1000); // "2m"
|
|
50
|
+
ms(ms('10 hours') as number); // "10h"
|
|
51
|
+
ms(60000, { long: true }); // "1 minute"
|
|
52
|
+
ms(2 * 60 * 1000, { long: true }); // "2 minutes"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Individual Functions
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { parse, format } from 'chrono-ms';
|
|
59
|
+
|
|
60
|
+
// Parse only
|
|
61
|
+
const milliseconds = parse('1.5h'); // 5400000
|
|
62
|
+
|
|
63
|
+
// Format only
|
|
64
|
+
const shortFormat = format(3600000); // "1h"
|
|
65
|
+
const longFormat = format(3600000, { long: true }); // "1 hour"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Compound Strings with `parseMultiple`
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { parseMultiple } from 'chrono-ms';
|
|
72
|
+
|
|
73
|
+
parseMultiple('1h 30m'); // 5400000
|
|
74
|
+
parseMultiple('2d 4h 30m'); // 189000000
|
|
75
|
+
parseMultiple('1w 3d'); // 864000000
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Safe Parsing with `tryParse`
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { tryParse } from 'chrono-ms';
|
|
82
|
+
|
|
83
|
+
// Returns null instead of throwing on invalid input
|
|
84
|
+
tryParse('2h'); // 7200000
|
|
85
|
+
tryParse('invalid'); // null
|
|
86
|
+
tryParse(''); // null
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Verbose Format
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { format } from 'chrono-ms';
|
|
93
|
+
|
|
94
|
+
format(5400000, { verbose: true }); // "1h 30m"
|
|
95
|
+
format(5400000, { verbose: true, long: true }); // "1 hour 30 minutes"
|
|
96
|
+
format(3661000, { verbose: true }); // "1h 1m 1s"
|
|
97
|
+
format(90000, { verbose: true }); // "1m 30s"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Advanced Usage
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import ms, {
|
|
104
|
+
parse,
|
|
105
|
+
format,
|
|
106
|
+
type FormatOptions,
|
|
107
|
+
type ParseOptions,
|
|
108
|
+
} from 'chrono-ms';
|
|
109
|
+
|
|
110
|
+
// Custom parsing options
|
|
111
|
+
const result = parse('30m', { maxLength: 50 });
|
|
112
|
+
|
|
113
|
+
// Custom formatting options
|
|
114
|
+
const formatted = format(7200000, { long: true });
|
|
115
|
+
|
|
116
|
+
// Type-safe string values
|
|
117
|
+
type TimeString = `${number}h` | `${number}m` | `${number}s`;
|
|
118
|
+
const timeValue: TimeString = '2h';
|
|
119
|
+
const parsed = ms(timeValue); // 7200000
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Supported Units
|
|
123
|
+
|
|
124
|
+
| Unit | Long Format | Short Format |
|
|
125
|
+
| ------------ | ---------------------------------------------- | ------------ |
|
|
126
|
+
| Years | `years`, `year`, `yrs`, `yr` | `y` |
|
|
127
|
+
| Weeks | `weeks`, `week` | `w` |
|
|
128
|
+
| Months | `months`, `month` | `mo` |
|
|
129
|
+
| Days | `days`, `day` | `d` |
|
|
130
|
+
| Hours | `hours`, `hour`, `hrs`, `hr` | `h` |
|
|
131
|
+
| Minutes | `minutes`, `minute`, `mins`, `min` | `m` |
|
|
132
|
+
| Seconds | `seconds`, `second`, `secs`, `sec` | `s` |
|
|
133
|
+
| Milliseconds | `milliseconds`, `millisecond`, `msecs`, `msec` | `ms` |
|
|
134
|
+
|
|
135
|
+
> **Note:** `mo` is used for months to avoid ambiguity with `m` (minutes). Month is defined as exactly 30 days.
|
|
136
|
+
|
|
137
|
+
All units are case-insensitive and support both singular and plural forms.
|
|
138
|
+
|
|
139
|
+
## API Reference
|
|
140
|
+
|
|
141
|
+
### `ms(value, options?)`
|
|
142
|
+
|
|
143
|
+
Main function that can parse strings or format numbers.
|
|
144
|
+
|
|
145
|
+
**Parameters:**
|
|
146
|
+
|
|
147
|
+
- `value: string | number` - String to parse or number to format
|
|
148
|
+
- `options?: FormatOptions | ParseOptions` - Configuration options
|
|
149
|
+
|
|
150
|
+
**Returns:**
|
|
151
|
+
|
|
152
|
+
- `number` when parsing strings
|
|
153
|
+
- `string` when formatting numbers
|
|
154
|
+
|
|
155
|
+
### `parse(value, options?)`
|
|
156
|
+
|
|
157
|
+
Parse a time string into milliseconds.
|
|
158
|
+
|
|
159
|
+
**Parameters:**
|
|
160
|
+
|
|
161
|
+
- `value: string` - Time string to parse
|
|
162
|
+
- `options?: ParseOptions` - Parsing configuration
|
|
163
|
+
|
|
164
|
+
**Returns:** `number` - Parsed time in milliseconds
|
|
165
|
+
|
|
166
|
+
**Options:**
|
|
167
|
+
|
|
168
|
+
- `maxLength?: number` - Maximum string length, must be a positive number (default: 100)
|
|
169
|
+
|
|
170
|
+
### `tryParse(value, options?)`
|
|
171
|
+
|
|
172
|
+
Parse a time string and return `null` instead of throwing on invalid input.
|
|
173
|
+
|
|
174
|
+
**Parameters:**
|
|
175
|
+
|
|
176
|
+
- `value: string` - Time string to parse
|
|
177
|
+
- `options?: ParseOptions` - Parsing configuration
|
|
178
|
+
|
|
179
|
+
**Returns:** `number | null` - Parsed milliseconds, or `null` on failure
|
|
180
|
+
|
|
181
|
+
### `parseMultiple(value, options?)`
|
|
182
|
+
|
|
183
|
+
Parse a compound time string with multiple space-separated tokens.
|
|
184
|
+
|
|
185
|
+
**Parameters:**
|
|
186
|
+
|
|
187
|
+
- `value: string` - Compound time string (e.g., `"1h 30m"`, `"2d 4h 30m"`)
|
|
188
|
+
- `options?: ParseOptions` - Parsing configuration applied to each token
|
|
189
|
+
|
|
190
|
+
**Returns:** `number` - Total duration in milliseconds
|
|
191
|
+
|
|
192
|
+
### `format(ms, options?)`
|
|
193
|
+
|
|
194
|
+
Format milliseconds into a human-readable string.
|
|
195
|
+
|
|
196
|
+
**Parameters:**
|
|
197
|
+
|
|
198
|
+
- `ms: number` - Milliseconds to format
|
|
199
|
+
- `options?: FormatOptions` - Formatting configuration
|
|
200
|
+
|
|
201
|
+
**Returns:** `string` - Formatted time string
|
|
202
|
+
|
|
203
|
+
**Options:**
|
|
204
|
+
|
|
205
|
+
- `long?: boolean` - Use long format (default: false)
|
|
206
|
+
- `verbose?: boolean` - Show all non-zero components decomposed (default: false)
|
|
207
|
+
|
|
208
|
+
## Examples
|
|
209
|
+
|
|
210
|
+
### Basic Parsing
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
ms('1s'); // 1000
|
|
214
|
+
ms('1m'); // 60000
|
|
215
|
+
ms('1h'); // 3600000
|
|
216
|
+
ms('1d'); // 86400000
|
|
217
|
+
ms('1w'); // 604800000
|
|
218
|
+
ms('1y'); // 31557600000
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Decimal Values
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
ms('1.5h'); // 5400000
|
|
225
|
+
ms('0.5d'); // 43200000
|
|
226
|
+
ms('2.5 hours'); // 9000000
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Negative Values
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
ms('-1h'); // -3600000
|
|
233
|
+
ms('-30m'); // -1800000
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Different Formats
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
// Short format (default)
|
|
240
|
+
ms(60000); // "1m"
|
|
241
|
+
ms(3600000); // "1h"
|
|
242
|
+
ms(604800000); // "1w"
|
|
243
|
+
ms(31557600000); // "1y"
|
|
244
|
+
|
|
245
|
+
// Long format
|
|
246
|
+
ms(60000, { long: true }); // "1 minute"
|
|
247
|
+
ms(120000, { long: true }); // "2 minutes"
|
|
248
|
+
ms(3600000, { long: true }); // "1 hour"
|
|
249
|
+
ms(7200000, { long: true }); // "2 hours"
|
|
250
|
+
|
|
251
|
+
// Verbose format (decomposed)
|
|
252
|
+
format(5400000, { verbose: true }); // "1h 30m"
|
|
253
|
+
format(5400000, { verbose: true, long: true }); // "1 hour 30 minutes"
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Months
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
parse('1mo'); // 2592000000 (30 days)
|
|
260
|
+
parse('6 months'); // 15552000000
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Error Handling
|
|
264
|
+
|
|
265
|
+
The library throws descriptive errors for invalid inputs:
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
try {
|
|
269
|
+
ms('invalid');
|
|
270
|
+
} catch (error) {
|
|
271
|
+
console.log(error.message); // "Invalid time format: "invalid""
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
try {
|
|
275
|
+
ms('a'.repeat(101));
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.log(error.message); // "String too long. Maximum length is 100 characters"
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
try {
|
|
281
|
+
format(NaN);
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.log(error.message); // "Value must be a finite number"
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Limitations
|
|
288
|
+
|
|
289
|
+
- Maximum string length is 100 characters by default (configurable via `maxLength`)
|
|
290
|
+
- Uses approximate year length (365.25 days)
|
|
291
|
+
- Month is defined as exactly 30 days (not calendar-aware)
|
|
292
|
+
- `format()` does not output months; use `parse('1mo')` for input only
|
|
293
|
+
|
|
294
|
+
## Development
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
# Install dependencies
|
|
298
|
+
pnpm install
|
|
299
|
+
|
|
300
|
+
# Run tests
|
|
301
|
+
pnpm test
|
|
302
|
+
|
|
303
|
+
# Run tests in watch mode
|
|
304
|
+
pnpm run test:watch
|
|
305
|
+
|
|
306
|
+
# Run tests with coverage
|
|
307
|
+
pnpm run test:coverage
|
|
308
|
+
|
|
309
|
+
# Build the package
|
|
310
|
+
pnpm run build
|
|
311
|
+
|
|
312
|
+
# Lint the code
|
|
313
|
+
pnpm run lint
|
|
314
|
+
|
|
315
|
+
# Type check
|
|
316
|
+
pnpm run type-check
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## Requirements
|
|
320
|
+
|
|
321
|
+
- Node.js >= 20.0.0
|
|
322
|
+
- Supports ES Modules
|
|
323
|
+
|
|
324
|
+
## Contributing
|
|
325
|
+
|
|
326
|
+
1. Fork the repository
|
|
327
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
328
|
+
3. Commit your changes (`git commit -m 'feat: add some amazing feature'`)
|
|
329
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
330
|
+
5. Open a Pull Request
|
|
331
|
+
|
|
332
|
+
## License
|
|
333
|
+
|
|
334
|
+
MIT ยฉ [Francisco Luis Rios Vega](https://github.com/alckordev)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time constants in milliseconds
|
|
3
|
+
*/
|
|
4
|
+
export declare const SECOND = 1000;
|
|
5
|
+
export declare const MINUTE: number;
|
|
6
|
+
export declare const HOUR: number;
|
|
7
|
+
export declare const DAY: number;
|
|
8
|
+
export declare const WEEK: number;
|
|
9
|
+
export declare const MONTH: number;
|
|
10
|
+
export declare const YEAR: number;
|
|
11
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,MAAM,OAAO,CAAC;AAC3B,eAAO,MAAM,MAAM,QAAc,CAAC;AAClC,eAAO,MAAM,IAAI,QAAc,CAAC;AAChC,eAAO,MAAM,GAAG,QAAY,CAAC;AAC7B,eAAO,MAAM,IAAI,QAAU,CAAC;AAC5B,eAAO,MAAM,KAAK,QAAW,CAAC;AAC9B,eAAO,MAAM,IAAI,QAAe,CAAC"}
|
package/dist/format.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { FormatOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Format milliseconds to a human-readable string.
|
|
4
|
+
*
|
|
5
|
+
* @param ms - Milliseconds to format
|
|
6
|
+
* @param options - Formatting options
|
|
7
|
+
* @returns Formatted string
|
|
8
|
+
* @throws {Error} When the input is not a finite number
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* format(7200000); // "2h"
|
|
13
|
+
* format(7200000, { long: true }); // "2 hours"
|
|
14
|
+
* format(5400000, { verbose: true }); // "1h 30m"
|
|
15
|
+
* format(5400000, { verbose: true, long: true }); // "1 hour 30 minutes"
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function format(ms: number, options?: FormatOptions): string;
|
|
19
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAUtE"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Time constants in milliseconds
|
|
7
|
+
*/
|
|
8
|
+
const SECOND = 1000;
|
|
9
|
+
const MINUTE = SECOND * 60;
|
|
10
|
+
const HOUR = MINUTE * 60;
|
|
11
|
+
const DAY = HOUR * 24;
|
|
12
|
+
const WEEK = DAY * 7;
|
|
13
|
+
const MONTH = DAY * 30;
|
|
14
|
+
const YEAR = DAY * 365.25;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Parse a time string and return milliseconds.
|
|
18
|
+
*
|
|
19
|
+
* @param value - Time string to parse (e.g., "2h", "30 minutes", "1d", "1mo")
|
|
20
|
+
* @param options - Parsing options
|
|
21
|
+
* @returns Parsed time in milliseconds
|
|
22
|
+
* @throws {Error} When the string format is invalid
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* parse("2h"); // 7200000
|
|
27
|
+
* parse("30 minutes"); // 1800000
|
|
28
|
+
* parse("1d"); // 86400000
|
|
29
|
+
* parse("1mo"); // 2592000000
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
function parse(value, options = {}) {
|
|
33
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
34
|
+
throw new Error('Value must be a non-empty string');
|
|
35
|
+
}
|
|
36
|
+
const { maxLength } = options;
|
|
37
|
+
if (maxLength !== undefined && maxLength <= 0) {
|
|
38
|
+
throw new Error('maxLength must be a positive number');
|
|
39
|
+
}
|
|
40
|
+
const resolvedMaxLength = maxLength ?? 100;
|
|
41
|
+
if (value.length > resolvedMaxLength) {
|
|
42
|
+
throw new Error(`String too long. Maximum length is ${resolvedMaxLength} characters`);
|
|
43
|
+
}
|
|
44
|
+
// months?|mo must appear before minutes?|mins?|m to avoid partial match ambiguity
|
|
45
|
+
const match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|months?|mo|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(value.trim());
|
|
46
|
+
if (!match) {
|
|
47
|
+
throw new Error(`Invalid time format: "${value}"`);
|
|
48
|
+
}
|
|
49
|
+
const num = parseFloat(match[1]);
|
|
50
|
+
/* istanbul ignore next */
|
|
51
|
+
if (!isFinite(num)) {
|
|
52
|
+
throw new Error(`Invalid number: "${match[1]}"`);
|
|
53
|
+
}
|
|
54
|
+
const unit = (match[2] || 'ms').toLowerCase();
|
|
55
|
+
switch (unit) {
|
|
56
|
+
case 'years':
|
|
57
|
+
case 'year':
|
|
58
|
+
case 'yrs':
|
|
59
|
+
case 'yr':
|
|
60
|
+
case 'y':
|
|
61
|
+
return num * YEAR;
|
|
62
|
+
case 'weeks':
|
|
63
|
+
case 'week':
|
|
64
|
+
case 'w':
|
|
65
|
+
return num * WEEK;
|
|
66
|
+
case 'months':
|
|
67
|
+
case 'month':
|
|
68
|
+
case 'mo':
|
|
69
|
+
return num * MONTH;
|
|
70
|
+
case 'days':
|
|
71
|
+
case 'day':
|
|
72
|
+
case 'd':
|
|
73
|
+
return num * DAY;
|
|
74
|
+
case 'hours':
|
|
75
|
+
case 'hour':
|
|
76
|
+
case 'hrs':
|
|
77
|
+
case 'hr':
|
|
78
|
+
case 'h':
|
|
79
|
+
return num * HOUR;
|
|
80
|
+
case 'minutes':
|
|
81
|
+
case 'minute':
|
|
82
|
+
case 'mins':
|
|
83
|
+
case 'min':
|
|
84
|
+
case 'm':
|
|
85
|
+
return num * MINUTE;
|
|
86
|
+
case 'seconds':
|
|
87
|
+
case 'second':
|
|
88
|
+
case 'secs':
|
|
89
|
+
case 'sec':
|
|
90
|
+
case 's':
|
|
91
|
+
return num * SECOND;
|
|
92
|
+
case 'milliseconds':
|
|
93
|
+
case 'millisecond':
|
|
94
|
+
case 'msecs':
|
|
95
|
+
case 'msec':
|
|
96
|
+
case 'ms':
|
|
97
|
+
return num;
|
|
98
|
+
/* istanbul ignore next */
|
|
99
|
+
default:
|
|
100
|
+
throw new Error(`Unknown unit: "${unit}"`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Parse a time string and return milliseconds, or `null` if the input is invalid.
|
|
105
|
+
* Useful when input is untrusted and exception handling would be verbose.
|
|
106
|
+
*
|
|
107
|
+
* @param value - Time string to parse
|
|
108
|
+
* @param options - Parsing options
|
|
109
|
+
* @returns Parsed time in milliseconds, or `null` on failure
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* tryParse("2h"); // 7200000
|
|
114
|
+
* tryParse("invalid"); // null
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
function tryParse(value, options) {
|
|
118
|
+
try {
|
|
119
|
+
return parse(value, options);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Parse a compound time string with multiple space-separated tokens.
|
|
127
|
+
*
|
|
128
|
+
* @param value - Compound time string (e.g., "1h 30m", "2d 4h 30m")
|
|
129
|
+
* @param options - Parsing options applied to each token
|
|
130
|
+
* @returns Total duration in milliseconds
|
|
131
|
+
* @throws {Error} When any token has an invalid format
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```ts
|
|
135
|
+
* parseMultiple("1h 30m"); // 5400000
|
|
136
|
+
* parseMultiple("2d 4h 30m"); // 189000000
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
function parseMultiple(value, options) {
|
|
140
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
141
|
+
throw new Error('Value must be a non-empty string');
|
|
142
|
+
}
|
|
143
|
+
return value
|
|
144
|
+
.trim()
|
|
145
|
+
.split(/\s+/)
|
|
146
|
+
.reduce((acc, token) => acc + parse(token, options), 0);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Format milliseconds to a human-readable string.
|
|
151
|
+
*
|
|
152
|
+
* @param ms - Milliseconds to format
|
|
153
|
+
* @param options - Formatting options
|
|
154
|
+
* @returns Formatted string
|
|
155
|
+
* @throws {Error} When the input is not a finite number
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* format(7200000); // "2h"
|
|
160
|
+
* format(7200000, { long: true }); // "2 hours"
|
|
161
|
+
* format(5400000, { verbose: true }); // "1h 30m"
|
|
162
|
+
* format(5400000, { verbose: true, long: true }); // "1 hour 30 minutes"
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
function format(ms, options = {}) {
|
|
166
|
+
if (typeof ms !== 'number' || !isFinite(ms)) {
|
|
167
|
+
throw new Error('Value must be a finite number');
|
|
168
|
+
}
|
|
169
|
+
if (options.verbose) {
|
|
170
|
+
return formatVerbose(ms, options.long ?? false);
|
|
171
|
+
}
|
|
172
|
+
return options.long ? formatLong(ms) : formatShort(ms);
|
|
173
|
+
}
|
|
174
|
+
function formatShort(ms) {
|
|
175
|
+
const absMs = Math.abs(ms);
|
|
176
|
+
if (absMs >= YEAR)
|
|
177
|
+
return Math.round(ms / YEAR) + 'y';
|
|
178
|
+
if (absMs >= WEEK)
|
|
179
|
+
return Math.round(ms / WEEK) + 'w';
|
|
180
|
+
if (absMs >= DAY)
|
|
181
|
+
return Math.round(ms / DAY) + 'd';
|
|
182
|
+
if (absMs >= HOUR)
|
|
183
|
+
return Math.round(ms / HOUR) + 'h';
|
|
184
|
+
if (absMs >= MINUTE)
|
|
185
|
+
return Math.round(ms / MINUTE) + 'm';
|
|
186
|
+
if (absMs >= SECOND)
|
|
187
|
+
return Math.round(ms / SECOND) + 's';
|
|
188
|
+
return ms + 'ms';
|
|
189
|
+
}
|
|
190
|
+
function formatLong(ms) {
|
|
191
|
+
const absMs = Math.abs(ms);
|
|
192
|
+
if (absMs >= YEAR)
|
|
193
|
+
return plural(ms, absMs, YEAR, 'year');
|
|
194
|
+
if (absMs >= WEEK)
|
|
195
|
+
return plural(ms, absMs, WEEK, 'week');
|
|
196
|
+
if (absMs >= DAY)
|
|
197
|
+
return plural(ms, absMs, DAY, 'day');
|
|
198
|
+
if (absMs >= HOUR)
|
|
199
|
+
return plural(ms, absMs, HOUR, 'hour');
|
|
200
|
+
if (absMs >= MINUTE)
|
|
201
|
+
return plural(ms, absMs, MINUTE, 'minute');
|
|
202
|
+
if (absMs >= SECOND)
|
|
203
|
+
return plural(ms, absMs, SECOND, 'second');
|
|
204
|
+
return ms + ' ms';
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Format milliseconds showing all non-zero components decomposed by unit.
|
|
208
|
+
* Handles negative values by prefixing the result with "-".
|
|
209
|
+
*/
|
|
210
|
+
function formatVerbose(ms, long) {
|
|
211
|
+
const negative = ms < 0;
|
|
212
|
+
let remaining = Math.abs(ms);
|
|
213
|
+
const parts = [];
|
|
214
|
+
const units = [
|
|
215
|
+
[YEAR, 'y', 'year'],
|
|
216
|
+
[WEEK, 'w', 'week'],
|
|
217
|
+
[DAY, 'd', 'day'],
|
|
218
|
+
[HOUR, 'h', 'hour'],
|
|
219
|
+
[MINUTE, 'm', 'minute'],
|
|
220
|
+
[SECOND, 's', 'second'],
|
|
221
|
+
];
|
|
222
|
+
for (const [unit, short, name] of units) {
|
|
223
|
+
if (remaining >= unit) {
|
|
224
|
+
const count = Math.floor(remaining / unit);
|
|
225
|
+
remaining -= count * unit;
|
|
226
|
+
parts.push(long
|
|
227
|
+
? `${count} ${count === 1 ? name : name + 's'}`
|
|
228
|
+
: `${count}${short}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (remaining > 0 || parts.length === 0) {
|
|
232
|
+
parts.push(long ? `${remaining} ms` : `${remaining}ms`);
|
|
233
|
+
}
|
|
234
|
+
const result = parts.join(' ');
|
|
235
|
+
return negative ? `-${result}` : result;
|
|
236
|
+
}
|
|
237
|
+
function plural(ms, absMs, unit, name) {
|
|
238
|
+
const isPlural = absMs >= unit * 1.5;
|
|
239
|
+
return Math.round(ms / unit) + ' ' + name + (isPlural ? 's' : '');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function ms(value, options) {
|
|
243
|
+
if (typeof value === 'string') {
|
|
244
|
+
return parse(value, options);
|
|
245
|
+
}
|
|
246
|
+
if (typeof value === 'number') {
|
|
247
|
+
return format(value, options);
|
|
248
|
+
}
|
|
249
|
+
throw new Error('Value must be a string or number');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
exports.DAY = DAY;
|
|
253
|
+
exports.HOUR = HOUR;
|
|
254
|
+
exports.MINUTE = MINUTE;
|
|
255
|
+
exports.MONTH = MONTH;
|
|
256
|
+
exports.SECOND = SECOND;
|
|
257
|
+
exports.WEEK = WEEK;
|
|
258
|
+
exports.YEAR = YEAR;
|
|
259
|
+
exports.default = ms;
|
|
260
|
+
exports.format = format;
|
|
261
|
+
exports.parse = parse;
|
|
262
|
+
exports.parseMultiple = parseMultiple;
|
|
263
|
+
exports.tryParse = tryParse;
|
|
264
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/constants.ts","../src/parse.ts","../src/format.ts","../src/ms.ts"],"sourcesContent":[null,null,null,null],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time constants in milliseconds
|
|
3
|
+
*/
|
|
4
|
+
const SECOND = 1000;
|
|
5
|
+
const MINUTE = SECOND * 60;
|
|
6
|
+
const HOUR = MINUTE * 60;
|
|
7
|
+
const DAY = HOUR * 24;
|
|
8
|
+
const WEEK = DAY * 7;
|
|
9
|
+
const MONTH = DAY * 30;
|
|
10
|
+
const YEAR = DAY * 365.25;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Parse a time string and return milliseconds.
|
|
14
|
+
*
|
|
15
|
+
* @param value - Time string to parse (e.g., "2h", "30 minutes", "1d", "1mo")
|
|
16
|
+
* @param options - Parsing options
|
|
17
|
+
* @returns Parsed time in milliseconds
|
|
18
|
+
* @throws {Error} When the string format is invalid
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* parse("2h"); // 7200000
|
|
23
|
+
* parse("30 minutes"); // 1800000
|
|
24
|
+
* parse("1d"); // 86400000
|
|
25
|
+
* parse("1mo"); // 2592000000
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
function parse(value, options = {}) {
|
|
29
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
30
|
+
throw new Error('Value must be a non-empty string');
|
|
31
|
+
}
|
|
32
|
+
const { maxLength } = options;
|
|
33
|
+
if (maxLength !== undefined && maxLength <= 0) {
|
|
34
|
+
throw new Error('maxLength must be a positive number');
|
|
35
|
+
}
|
|
36
|
+
const resolvedMaxLength = maxLength ?? 100;
|
|
37
|
+
if (value.length > resolvedMaxLength) {
|
|
38
|
+
throw new Error(`String too long. Maximum length is ${resolvedMaxLength} characters`);
|
|
39
|
+
}
|
|
40
|
+
// months?|mo must appear before minutes?|mins?|m to avoid partial match ambiguity
|
|
41
|
+
const match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|months?|mo|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(value.trim());
|
|
42
|
+
if (!match) {
|
|
43
|
+
throw new Error(`Invalid time format: "${value}"`);
|
|
44
|
+
}
|
|
45
|
+
const num = parseFloat(match[1]);
|
|
46
|
+
/* istanbul ignore next */
|
|
47
|
+
if (!isFinite(num)) {
|
|
48
|
+
throw new Error(`Invalid number: "${match[1]}"`);
|
|
49
|
+
}
|
|
50
|
+
const unit = (match[2] || 'ms').toLowerCase();
|
|
51
|
+
switch (unit) {
|
|
52
|
+
case 'years':
|
|
53
|
+
case 'year':
|
|
54
|
+
case 'yrs':
|
|
55
|
+
case 'yr':
|
|
56
|
+
case 'y':
|
|
57
|
+
return num * YEAR;
|
|
58
|
+
case 'weeks':
|
|
59
|
+
case 'week':
|
|
60
|
+
case 'w':
|
|
61
|
+
return num * WEEK;
|
|
62
|
+
case 'months':
|
|
63
|
+
case 'month':
|
|
64
|
+
case 'mo':
|
|
65
|
+
return num * MONTH;
|
|
66
|
+
case 'days':
|
|
67
|
+
case 'day':
|
|
68
|
+
case 'd':
|
|
69
|
+
return num * DAY;
|
|
70
|
+
case 'hours':
|
|
71
|
+
case 'hour':
|
|
72
|
+
case 'hrs':
|
|
73
|
+
case 'hr':
|
|
74
|
+
case 'h':
|
|
75
|
+
return num * HOUR;
|
|
76
|
+
case 'minutes':
|
|
77
|
+
case 'minute':
|
|
78
|
+
case 'mins':
|
|
79
|
+
case 'min':
|
|
80
|
+
case 'm':
|
|
81
|
+
return num * MINUTE;
|
|
82
|
+
case 'seconds':
|
|
83
|
+
case 'second':
|
|
84
|
+
case 'secs':
|
|
85
|
+
case 'sec':
|
|
86
|
+
case 's':
|
|
87
|
+
return num * SECOND;
|
|
88
|
+
case 'milliseconds':
|
|
89
|
+
case 'millisecond':
|
|
90
|
+
case 'msecs':
|
|
91
|
+
case 'msec':
|
|
92
|
+
case 'ms':
|
|
93
|
+
return num;
|
|
94
|
+
/* istanbul ignore next */
|
|
95
|
+
default:
|
|
96
|
+
throw new Error(`Unknown unit: "${unit}"`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Parse a time string and return milliseconds, or `null` if the input is invalid.
|
|
101
|
+
* Useful when input is untrusted and exception handling would be verbose.
|
|
102
|
+
*
|
|
103
|
+
* @param value - Time string to parse
|
|
104
|
+
* @param options - Parsing options
|
|
105
|
+
* @returns Parsed time in milliseconds, or `null` on failure
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* tryParse("2h"); // 7200000
|
|
110
|
+
* tryParse("invalid"); // null
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
function tryParse(value, options) {
|
|
114
|
+
try {
|
|
115
|
+
return parse(value, options);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Parse a compound time string with multiple space-separated tokens.
|
|
123
|
+
*
|
|
124
|
+
* @param value - Compound time string (e.g., "1h 30m", "2d 4h 30m")
|
|
125
|
+
* @param options - Parsing options applied to each token
|
|
126
|
+
* @returns Total duration in milliseconds
|
|
127
|
+
* @throws {Error} When any token has an invalid format
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* parseMultiple("1h 30m"); // 5400000
|
|
132
|
+
* parseMultiple("2d 4h 30m"); // 189000000
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
function parseMultiple(value, options) {
|
|
136
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
137
|
+
throw new Error('Value must be a non-empty string');
|
|
138
|
+
}
|
|
139
|
+
return value
|
|
140
|
+
.trim()
|
|
141
|
+
.split(/\s+/)
|
|
142
|
+
.reduce((acc, token) => acc + parse(token, options), 0);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Format milliseconds to a human-readable string.
|
|
147
|
+
*
|
|
148
|
+
* @param ms - Milliseconds to format
|
|
149
|
+
* @param options - Formatting options
|
|
150
|
+
* @returns Formatted string
|
|
151
|
+
* @throws {Error} When the input is not a finite number
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```ts
|
|
155
|
+
* format(7200000); // "2h"
|
|
156
|
+
* format(7200000, { long: true }); // "2 hours"
|
|
157
|
+
* format(5400000, { verbose: true }); // "1h 30m"
|
|
158
|
+
* format(5400000, { verbose: true, long: true }); // "1 hour 30 minutes"
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
function format(ms, options = {}) {
|
|
162
|
+
if (typeof ms !== 'number' || !isFinite(ms)) {
|
|
163
|
+
throw new Error('Value must be a finite number');
|
|
164
|
+
}
|
|
165
|
+
if (options.verbose) {
|
|
166
|
+
return formatVerbose(ms, options.long ?? false);
|
|
167
|
+
}
|
|
168
|
+
return options.long ? formatLong(ms) : formatShort(ms);
|
|
169
|
+
}
|
|
170
|
+
function formatShort(ms) {
|
|
171
|
+
const absMs = Math.abs(ms);
|
|
172
|
+
if (absMs >= YEAR)
|
|
173
|
+
return Math.round(ms / YEAR) + 'y';
|
|
174
|
+
if (absMs >= WEEK)
|
|
175
|
+
return Math.round(ms / WEEK) + 'w';
|
|
176
|
+
if (absMs >= DAY)
|
|
177
|
+
return Math.round(ms / DAY) + 'd';
|
|
178
|
+
if (absMs >= HOUR)
|
|
179
|
+
return Math.round(ms / HOUR) + 'h';
|
|
180
|
+
if (absMs >= MINUTE)
|
|
181
|
+
return Math.round(ms / MINUTE) + 'm';
|
|
182
|
+
if (absMs >= SECOND)
|
|
183
|
+
return Math.round(ms / SECOND) + 's';
|
|
184
|
+
return ms + 'ms';
|
|
185
|
+
}
|
|
186
|
+
function formatLong(ms) {
|
|
187
|
+
const absMs = Math.abs(ms);
|
|
188
|
+
if (absMs >= YEAR)
|
|
189
|
+
return plural(ms, absMs, YEAR, 'year');
|
|
190
|
+
if (absMs >= WEEK)
|
|
191
|
+
return plural(ms, absMs, WEEK, 'week');
|
|
192
|
+
if (absMs >= DAY)
|
|
193
|
+
return plural(ms, absMs, DAY, 'day');
|
|
194
|
+
if (absMs >= HOUR)
|
|
195
|
+
return plural(ms, absMs, HOUR, 'hour');
|
|
196
|
+
if (absMs >= MINUTE)
|
|
197
|
+
return plural(ms, absMs, MINUTE, 'minute');
|
|
198
|
+
if (absMs >= SECOND)
|
|
199
|
+
return plural(ms, absMs, SECOND, 'second');
|
|
200
|
+
return ms + ' ms';
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Format milliseconds showing all non-zero components decomposed by unit.
|
|
204
|
+
* Handles negative values by prefixing the result with "-".
|
|
205
|
+
*/
|
|
206
|
+
function formatVerbose(ms, long) {
|
|
207
|
+
const negative = ms < 0;
|
|
208
|
+
let remaining = Math.abs(ms);
|
|
209
|
+
const parts = [];
|
|
210
|
+
const units = [
|
|
211
|
+
[YEAR, 'y', 'year'],
|
|
212
|
+
[WEEK, 'w', 'week'],
|
|
213
|
+
[DAY, 'd', 'day'],
|
|
214
|
+
[HOUR, 'h', 'hour'],
|
|
215
|
+
[MINUTE, 'm', 'minute'],
|
|
216
|
+
[SECOND, 's', 'second'],
|
|
217
|
+
];
|
|
218
|
+
for (const [unit, short, name] of units) {
|
|
219
|
+
if (remaining >= unit) {
|
|
220
|
+
const count = Math.floor(remaining / unit);
|
|
221
|
+
remaining -= count * unit;
|
|
222
|
+
parts.push(long
|
|
223
|
+
? `${count} ${count === 1 ? name : name + 's'}`
|
|
224
|
+
: `${count}${short}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (remaining > 0 || parts.length === 0) {
|
|
228
|
+
parts.push(long ? `${remaining} ms` : `${remaining}ms`);
|
|
229
|
+
}
|
|
230
|
+
const result = parts.join(' ');
|
|
231
|
+
return negative ? `-${result}` : result;
|
|
232
|
+
}
|
|
233
|
+
function plural(ms, absMs, unit, name) {
|
|
234
|
+
const isPlural = absMs >= unit * 1.5;
|
|
235
|
+
return Math.round(ms / unit) + ' ' + name + (isPlural ? 's' : '');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function ms(value, options) {
|
|
239
|
+
if (typeof value === 'string') {
|
|
240
|
+
return parse(value, options);
|
|
241
|
+
}
|
|
242
|
+
if (typeof value === 'number') {
|
|
243
|
+
return format(value, options);
|
|
244
|
+
}
|
|
245
|
+
throw new Error('Value must be a string or number');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export { DAY, HOUR, MINUTE, MONTH, SECOND, WEEK, YEAR, ms as default, format, parse, parseMultiple, tryParse };
|
|
249
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/constants.ts","../src/parse.ts","../src/format.ts","../src/ms.ts"],"sourcesContent":[null,null,null,null],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Time constants in milliseconds
|
|
7
|
+
*/
|
|
8
|
+
const SECOND = 1000;
|
|
9
|
+
const MINUTE = SECOND * 60;
|
|
10
|
+
const HOUR = MINUTE * 60;
|
|
11
|
+
const DAY = HOUR * 24;
|
|
12
|
+
const WEEK = DAY * 7;
|
|
13
|
+
const YEAR = DAY * 365.25;
|
|
14
|
+
/**
|
|
15
|
+
* Parse a time string and return milliseconds
|
|
16
|
+
*
|
|
17
|
+
* @param value - Time string to parse (e.g., "2h", "30 minutes", "1d")
|
|
18
|
+
* @param options - Parsing options
|
|
19
|
+
* @returns Parsed time in milliseconds
|
|
20
|
+
* @throws {Error} When the string format is invalid
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* parse("2h"); // 7200000
|
|
25
|
+
* parse("30 minutes"); // 1800000
|
|
26
|
+
* parse("1d"); // 86400000
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
function parse(value, options = {}) {
|
|
30
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
31
|
+
throw new Error('Value must be a non-empty string');
|
|
32
|
+
}
|
|
33
|
+
const maxLength = options.maxLength ?? 100;
|
|
34
|
+
if (value.length > maxLength) {
|
|
35
|
+
throw new Error(`String too long. Maximum length is ${maxLength} characters`);
|
|
36
|
+
}
|
|
37
|
+
const match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(value.trim());
|
|
38
|
+
if (!match) {
|
|
39
|
+
throw new Error(`Invalid time format: "${value}"`);
|
|
40
|
+
}
|
|
41
|
+
const num = parseFloat(match[1]);
|
|
42
|
+
if (!isFinite(num)) {
|
|
43
|
+
throw new Error(`Invalid number: "${match[1]}"`);
|
|
44
|
+
}
|
|
45
|
+
const unit = (match[2] || 'ms').toLowerCase();
|
|
46
|
+
switch (unit) {
|
|
47
|
+
case 'years':
|
|
48
|
+
case 'year':
|
|
49
|
+
case 'yrs':
|
|
50
|
+
case 'yr':
|
|
51
|
+
case 'y':
|
|
52
|
+
return num * YEAR;
|
|
53
|
+
case 'weeks':
|
|
54
|
+
case 'week':
|
|
55
|
+
case 'w':
|
|
56
|
+
return num * WEEK;
|
|
57
|
+
case 'days':
|
|
58
|
+
case 'day':
|
|
59
|
+
case 'd':
|
|
60
|
+
return num * DAY;
|
|
61
|
+
case 'hours':
|
|
62
|
+
case 'hour':
|
|
63
|
+
case 'hrs':
|
|
64
|
+
case 'hr':
|
|
65
|
+
case 'h':
|
|
66
|
+
return num * HOUR;
|
|
67
|
+
case 'minutes':
|
|
68
|
+
case 'minute':
|
|
69
|
+
case 'mins':
|
|
70
|
+
case 'min':
|
|
71
|
+
case 'm':
|
|
72
|
+
return num * MINUTE;
|
|
73
|
+
case 'seconds':
|
|
74
|
+
case 'second':
|
|
75
|
+
case 'secs':
|
|
76
|
+
case 'sec':
|
|
77
|
+
case 's':
|
|
78
|
+
return num * SECOND;
|
|
79
|
+
case 'milliseconds':
|
|
80
|
+
case 'millisecond':
|
|
81
|
+
case 'msecs':
|
|
82
|
+
case 'msec':
|
|
83
|
+
case 'ms':
|
|
84
|
+
return num;
|
|
85
|
+
default:
|
|
86
|
+
throw new Error(`Unknown unit: "${unit}"`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Format milliseconds to a human-readable string
|
|
91
|
+
*
|
|
92
|
+
* @param ms - Milliseconds to format
|
|
93
|
+
* @param options - Formatting options
|
|
94
|
+
* @returns Formatted string
|
|
95
|
+
* @throws {Error} When the input is not a finite number
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* format(7200000); // "2h"
|
|
100
|
+
* format(7200000, { long: true }); // "2 hours"
|
|
101
|
+
* format(1800000); // "30m"
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
function format(ms, options = {}) {
|
|
105
|
+
if (typeof ms !== 'number' || !isFinite(ms)) {
|
|
106
|
+
throw new Error('Value must be a finite number');
|
|
107
|
+
}
|
|
108
|
+
return options.long ? formatLong(ms) : formatShort(ms);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Format milliseconds in short format (e.g., "2h", "30m")
|
|
112
|
+
*/
|
|
113
|
+
function formatShort(ms) {
|
|
114
|
+
const absMs = Math.abs(ms);
|
|
115
|
+
if (absMs >= DAY) {
|
|
116
|
+
return Math.round(ms / DAY) + 'd';
|
|
117
|
+
}
|
|
118
|
+
if (absMs >= HOUR) {
|
|
119
|
+
return Math.round(ms / HOUR) + 'h';
|
|
120
|
+
}
|
|
121
|
+
if (absMs >= MINUTE) {
|
|
122
|
+
return Math.round(ms / MINUTE) + 'm';
|
|
123
|
+
}
|
|
124
|
+
if (absMs >= SECOND) {
|
|
125
|
+
return Math.round(ms / SECOND) + 's';
|
|
126
|
+
}
|
|
127
|
+
return ms + 'ms';
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Format milliseconds in long format (e.g., "2 hours", "30 minutes")
|
|
131
|
+
*/
|
|
132
|
+
function formatLong(ms) {
|
|
133
|
+
const absMs = Math.abs(ms);
|
|
134
|
+
if (absMs >= DAY) {
|
|
135
|
+
return plural(ms, absMs, DAY, 'day');
|
|
136
|
+
}
|
|
137
|
+
if (absMs >= HOUR) {
|
|
138
|
+
return plural(ms, absMs, HOUR, 'hour');
|
|
139
|
+
}
|
|
140
|
+
if (absMs >= MINUTE) {
|
|
141
|
+
return plural(ms, absMs, MINUTE, 'minute');
|
|
142
|
+
}
|
|
143
|
+
if (absMs >= SECOND) {
|
|
144
|
+
return plural(ms, absMs, SECOND, 'second');
|
|
145
|
+
}
|
|
146
|
+
return ms + ' ms';
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Helper function for pluralization
|
|
150
|
+
*/
|
|
151
|
+
function plural(ms, absMs, unit, name) {
|
|
152
|
+
const isPlural = absMs >= unit * 1.5;
|
|
153
|
+
return Math.round(ms / unit) + ' ' + name + (isPlural ? 's' : '');
|
|
154
|
+
}
|
|
155
|
+
function ms(value, options) {
|
|
156
|
+
if (typeof value === 'string') {
|
|
157
|
+
return parse(value, options);
|
|
158
|
+
}
|
|
159
|
+
if (typeof value === 'number') {
|
|
160
|
+
return format(value, options);
|
|
161
|
+
}
|
|
162
|
+
throw new Error('Value must be a string or number');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
exports.default = ms;
|
|
166
|
+
exports.format = format;
|
|
167
|
+
exports.parse = parse;
|
|
168
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
package/dist/ms.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { StringValue, FormatOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Main function that can either parse a string or format a number.
|
|
4
|
+
*
|
|
5
|
+
* @param value - String to parse or number to format
|
|
6
|
+
* @param options - Options for parsing or formatting
|
|
7
|
+
* @returns Parsed milliseconds or formatted string
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* ms("2h"); // 7200000
|
|
12
|
+
* ms(7200000); // "2h"
|
|
13
|
+
* ms(7200000, { long: true }); // "2 hours"
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare function ms(value: StringValue): number;
|
|
17
|
+
declare function ms(value: number, options?: FormatOptions): string;
|
|
18
|
+
export default ms;
|
|
19
|
+
//# sourceMappingURL=ms.d.ts.map
|
package/dist/ms.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ms.d.ts","sourceRoot":"","sources":["../src/ms.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAgB,MAAM,SAAS,CAAC;AAExE;;;;;;;;;;;;;GAaG;AACH,iBAAS,EAAE,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAAC;AACxC,iBAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;AAgB5D,eAAe,EAAE,CAAC"}
|
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { ParseOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Parse a time string and return milliseconds.
|
|
4
|
+
*
|
|
5
|
+
* @param value - Time string to parse (e.g., "2h", "30 minutes", "1d", "1mo")
|
|
6
|
+
* @param options - Parsing options
|
|
7
|
+
* @returns Parsed time in milliseconds
|
|
8
|
+
* @throws {Error} When the string format is invalid
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* parse("2h"); // 7200000
|
|
13
|
+
* parse("30 minutes"); // 1800000
|
|
14
|
+
* parse("1d"); // 86400000
|
|
15
|
+
* parse("1mo"); // 2592000000
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function parse(value: string, options?: ParseOptions): number;
|
|
19
|
+
/**
|
|
20
|
+
* Parse a time string and return milliseconds, or `null` if the input is invalid.
|
|
21
|
+
* Useful when input is untrusted and exception handling would be verbose.
|
|
22
|
+
*
|
|
23
|
+
* @param value - Time string to parse
|
|
24
|
+
* @param options - Parsing options
|
|
25
|
+
* @returns Parsed time in milliseconds, or `null` on failure
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* tryParse("2h"); // 7200000
|
|
30
|
+
* tryParse("invalid"); // null
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function tryParse(value: string, options?: ParseOptions): number | null;
|
|
34
|
+
/**
|
|
35
|
+
* Parse a compound time string with multiple space-separated tokens.
|
|
36
|
+
*
|
|
37
|
+
* @param value - Compound time string (e.g., "1h 30m", "2d 4h 30m")
|
|
38
|
+
* @param options - Parsing options applied to each token
|
|
39
|
+
* @returns Total duration in milliseconds
|
|
40
|
+
* @throws {Error} When any token has an invalid format
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* parseMultiple("1h 30m"); // 5400000
|
|
45
|
+
* parseMultiple("2d 4h 30m"); // 189000000
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function parseMultiple(value: string, options?: ParseOptions): number;
|
|
49
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,MAAM,CAkFvE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAM7E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,CAS3E"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time units supported by the parser
|
|
3
|
+
*/
|
|
4
|
+
export type Unit = 'Years' | 'Year' | 'Yrs' | 'Yr' | 'Y' | 'Weeks' | 'Week' | 'W' | 'Months' | 'Month' | 'Mo' | 'Days' | 'Day' | 'D' | 'Hours' | 'Hour' | 'Hrs' | 'Hr' | 'H' | 'Minutes' | 'Minute' | 'Mins' | 'Min' | 'M' | 'Seconds' | 'Second' | 'Secs' | 'Sec' | 's' | 'Milliseconds' | 'Millisecond' | 'Msecs' | 'Msec' | 'Ms';
|
|
5
|
+
export type UnitAnyCase = Unit | Uppercase<Unit> | Lowercase<Unit>;
|
|
6
|
+
export type StringValue = `${number}` | `${number}${UnitAnyCase}` | `${number} ${UnitAnyCase}`;
|
|
7
|
+
/**
|
|
8
|
+
* Configuration options for formatting
|
|
9
|
+
*/
|
|
10
|
+
export interface FormatOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Use long format (e.g., "1 day" instead of "1d")
|
|
13
|
+
* @default false
|
|
14
|
+
*/
|
|
15
|
+
long?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Use verbose format, showing all non-zero components (e.g., "1h 30m" instead of "2h")
|
|
18
|
+
* @default false
|
|
19
|
+
*/
|
|
20
|
+
verbose?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Configuration options for parsing
|
|
24
|
+
*/
|
|
25
|
+
export interface ParseOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Maximum string length to parse. Must be a positive number.
|
|
28
|
+
* @default 100
|
|
29
|
+
*/
|
|
30
|
+
maxLength?: number;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,IAAI,GACZ,OAAO,GACP,MAAM,GACN,KAAK,GACL,IAAI,GACJ,GAAG,GACH,OAAO,GACP,MAAM,GACN,GAAG,GACH,QAAQ,GACR,OAAO,GACP,IAAI,GACJ,MAAM,GACN,KAAK,GACL,GAAG,GACH,OAAO,GACP,MAAM,GACN,KAAK,GACL,IAAI,GACJ,GAAG,GACH,SAAS,GACT,QAAQ,GACR,MAAM,GACN,KAAK,GACL,GAAG,GACH,SAAS,GACT,QAAQ,GACR,MAAM,GACN,KAAK,GACL,GAAG,GACH,cAAc,GACd,aAAa,GACb,OAAO,GACP,MAAM,GACN,IAAI,CAAC;AAET,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAEnE,MAAM,MAAM,WAAW,GACnB,GAAG,MAAM,EAAE,GACX,GAAG,MAAM,GAAG,WAAW,EAAE,GACzB,GAAG,MAAM,IAAI,WAAW,EAAE,CAAC;AAE/B;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "chrono-ms",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "A lightweight, TypeScript-first library for parsing and formatting time durations",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.esm.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE.md"
|
|
13
|
+
],
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"import": "./dist/index.esm.js",
|
|
17
|
+
"require": "./dist/index.cjs",
|
|
18
|
+
"types": "./dist/index.d.ts"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"time",
|
|
23
|
+
"duration",
|
|
24
|
+
"parser",
|
|
25
|
+
"formatter",
|
|
26
|
+
"chrono",
|
|
27
|
+
"ms",
|
|
28
|
+
"milliseconds",
|
|
29
|
+
"typescript"
|
|
30
|
+
],
|
|
31
|
+
"author": "Francisco Luis Rios Vega <alckordev@gmail.com>",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/iscodex/chrono-ms.git"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/iscodex/chrono-ms/issues"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/iscodex/chrono-ms#readme",
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@eslint/js": "^9.35.0",
|
|
43
|
+
"@rollup/plugin-typescript": "^12.1.4",
|
|
44
|
+
"@types/jest": "^30.0.0",
|
|
45
|
+
"@typescript-eslint/eslint-plugin": "^8.44.0",
|
|
46
|
+
"@typescript-eslint/parser": "^8.44.0",
|
|
47
|
+
"eslint": "^9.35.0",
|
|
48
|
+
"eslint-config-prettier": "^10.1.8",
|
|
49
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
50
|
+
"globals": "^16.4.0",
|
|
51
|
+
"jest": "^30.1.3",
|
|
52
|
+
"np": "^10.2.0",
|
|
53
|
+
"prettier": "^3.6.2",
|
|
54
|
+
"rimraf": "^6.0.1",
|
|
55
|
+
"rollup": "^4.50.2",
|
|
56
|
+
"ts-jest": "^29.4.3",
|
|
57
|
+
"typescript": "^5.9.2"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=20.0.0"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"build": "rollup -c",
|
|
64
|
+
"dev": "rollup -c -w",
|
|
65
|
+
"test": "jest --verbose",
|
|
66
|
+
"test:watch": "jest --watch --verbose",
|
|
67
|
+
"test:coverage": "jest --coverage --verbose",
|
|
68
|
+
"test:debug": "jest --detectOpenHandles --forceExit --verbose",
|
|
69
|
+
"lint": "eslint src/**/*.{js,ts}",
|
|
70
|
+
"lint:fix": "eslint src/**/*.{js,ts} --fix",
|
|
71
|
+
"type-check": "tsc --noEmit",
|
|
72
|
+
"clean": "rimraf dist",
|
|
73
|
+
"release": "np"
|
|
74
|
+
}
|
|
75
|
+
}
|