datevolt 1.0.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
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,339 @@
1
+ # tempox
2
+
3
+ [![npm version](https://img.shields.io/npm/v/tempox.svg)](https://www.npmjs.com/package/tempox)
4
+ [![license](https://img.shields.io/npm/l/tempox.svg)](LICENSE)
5
+
6
+ > **A complete, lightweight, zero-dependency JavaScript date library** with a `moment.js`-compatible chainable API.
7
+
8
+ - ⚡ **~8 KB** gzipped vs moment's ~72 KB
9
+ - 📦 **Zero dependencies** — no node_modules bloat
10
+ - 🔗 **moment.js-style API** — `parse`, `format`, `add/subtract`, `diff`, `fromNow`, `calendar`, `duration`, `locale`
11
+ - 🌍 **Timezone & UTC support** — `utc()`, `utcOffset()`, `isDST()`
12
+ - 🗓 **Built-in locales**: `en`, `hi`, `es`, `fr`, `de`, `ar`, `ja` — extend with `defineLocale()`
13
+ - 📱 **React Native ready** — pure JS Date math, no `Intl` dependency, Metro bundler compatible
14
+
15
+ ---
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm install tempox
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```js
26
+ const tempox = require('tempox');
27
+
28
+ // Current date/time
29
+ tempox().format('YYYY-MM-DD HH:mm:ss');
30
+
31
+ // Parse ISO string
32
+ tempox('2024-06-15').format('dddd, MMMM D, YYYY'); // "Saturday, June 15, 2024"
33
+
34
+ // Add / subtract
35
+ tempox('2024-01-31').add(1, 'month').format('YYYY-MM-DD'); // "2024-02-29"
36
+
37
+ // Relative time
38
+ tempox('2024-01-01').fromNow(); // "6 months ago"
39
+ tempox().add(2, 'hours').toNow(); // "in 2 hours"
40
+
41
+ // Diff
42
+ tempox('2024-06-15').diff('2024-01-01', 'days'); // 166
43
+
44
+ // Compare
45
+ tempox('2024-06-15').isBefore('2024-12-31'); // true
46
+ ```
47
+
48
+ ---
49
+
50
+ ## API Reference
51
+
52
+ ### Parsing
53
+
54
+ ```js
55
+ tempox() // now
56
+ tempox('2024-06-15') // ISO date string (local midnight)
57
+ tempox('2024-06-15T10:30:00') // ISO datetime
58
+ tempox('2024-06-15T10:30:00Z') // UTC
59
+ tempox('2024-06-15T10:30:00+05:30') // with offset
60
+ tempox('15/06/2024', 'DD/MM/YYYY') // with format string
61
+ tempox('15/06/2024', ['DD/MM/YYYY', 'YYYY-MM-DD']) // multiple formats
62
+ tempox([2024, 5, 15]) // array [Y, M(0-based), D]
63
+ tempox([2024, 5, 15, 14, 30, 0, 0]) // array with time
64
+ tempox({ year:2024, month:5, day:15 }) // object
65
+ tempox(1718438400000) // unix milliseconds
66
+ tempox.unix(1718438400) // unix seconds
67
+ tempox.utc('2024-06-15T10:30:00') // UTC mode
68
+
69
+ // Validation
70
+ tempox('2024-06-15').isValid() // true
71
+ tempox('not-a-date').isValid() // false
72
+ ```
73
+
74
+ ### Get + Set
75
+
76
+ ```js
77
+ var d = tempox('2024-06-15T14:30:45.123');
78
+
79
+ d.year() // 2024 d.year(2025)
80
+ d.month() // 5 (0-based) d.month(0)
81
+ d.date() // 15 d.date(1)
82
+ d.day() // 6 (Saturday) d.day(1) // set to Monday
83
+ d.hour() // 14 d.hour(9)
84
+ d.minute() // 30 d.minute(0)
85
+ d.second() // 45 d.second(0)
86
+ d.millisecond() // 123
87
+
88
+ d.quarter() // 2 (Apr–Jun)
89
+ d.dayOfYear() // 167
90
+ d.daysInMonth() // 30
91
+ d.week() // ISO week number
92
+ d.isoWeek()
93
+ d.weeksInYear()
94
+ d.isoWeekday() // 1=Mon ... 7=Sun
95
+
96
+ // Generic
97
+ d.get('year') // 2024
98
+ d.set('year', 2025) // chainable
99
+ ```
100
+
101
+ ### Manipulate
102
+
103
+ ```js
104
+ tempox().add(7, 'days')
105
+ tempox().add(1, 'month')
106
+ tempox().add(2, 'years')
107
+ tempox().add(3, 'hours')
108
+ tempox().add(30, 'minutes')
109
+ tempox().add(15, 'seconds')
110
+ tempox().add({ days: 1, hours: 2, minutes: 30 }) // object form
111
+
112
+ tempox().subtract(1, 'week')
113
+ tempox().subtract(3, 'months')
114
+
115
+ // Chained
116
+ tempox('2024-01-01').add(1,'year').subtract(3,'months').startOf('month')
117
+
118
+ // startOf / endOf
119
+ tempox().startOf('year') // Jan 1, 00:00:00.000
120
+ tempox().startOf('month') // 1st of month, 00:00:00.000
121
+ tempox().startOf('week') // locale-aware week start
122
+ tempox().startOf('day') // 00:00:00.000
123
+ tempox().startOf('hour')
124
+ tempox().startOf('minute')
125
+ tempox().startOf('second')
126
+ tempox().startOf('quarter')
127
+ tempox().startOf('isoWeek')
128
+
129
+ tempox().endOf('year') // Dec 31, 23:59:59.999
130
+ tempox().endOf('month') // last day, 23:59:59.999
131
+
132
+ tempox().clone() // immutable copy
133
+ ```
134
+
135
+ ### Format
136
+
137
+ ```js
138
+ tempox().format() // "1:30 PM" (LT)
139
+ tempox().format('YYYY-MM-DD') // "2024-06-15"
140
+ tempox().format('YYYY-MM-DD HH:mm:ss') // "2024-06-15 14:30:45"
141
+ tempox().format('dddd, MMMM D, YYYY') // "Saturday, June 15, 2024"
142
+ tempox().format('MMM Do, YYYY') // "Jun 15th, 2024"
143
+ tempox().format('h:mm A') // "2:30 PM"
144
+ tempox().format('[Today is] dddd') // "Today is Saturday"
145
+ tempox().format('L') // "06/15/2024"
146
+ tempox().format('LL') // "June 15, 2024"
147
+ tempox().format('LLL') // "June 15, 2024 2:30 PM"
148
+ tempox().format('LLLL') // "Saturday, June 15, 2024 2:30 PM"
149
+ ```
150
+
151
+ | Token | Output | Description |
152
+ |-------|--------|-------------|
153
+ | `YYYY` | 2024 | Full year |
154
+ | `YY` | 24 | 2-digit year |
155
+ | `MMMM` | June | Month name |
156
+ | `MMM` | Jun | Short month |
157
+ | `MM` | 06 | Month 2-digit |
158
+ | `M` | 6 | Month |
159
+ | `DD` | 15 | Day 2-digit |
160
+ | `Do` | 15th | Ordinal day |
161
+ | `D` | 15 | Day |
162
+ | `dddd` | Saturday | Weekday name |
163
+ | `ddd` | Sat | Short weekday |
164
+ | `HH` | 14 | 24-hour |
165
+ | `h` | 2 | 12-hour |
166
+ | `mm` | 30 | Minutes |
167
+ | `ss` | 45 | Seconds |
168
+ | `SSS` | 123 | Milliseconds |
169
+ | `A` | PM | AM/PM |
170
+ | `Z` | +05:30 | Timezone |
171
+ | `X` | 1718438400 | Unix seconds |
172
+ | `x` | 1718438400000 | Unix ms |
173
+ | `Q` | 2 | Quarter |
174
+
175
+ ### Relative Time
176
+
177
+ ```js
178
+ tempox('2024-01-01').fromNow() // "6 months ago"
179
+ tempox().add(2,'hours').fromNow() // "in 2 hours"
180
+ tempox().subtract(3,'days').fromNow(true) // "3 days" (without suffix)
181
+
182
+ tempox('2024-01-01').from('2024-06-15') // "6 months ago"
183
+ tempox().add(5,'minutes').toNow() // "in 5 minutes"
184
+ tempox('2024-01-01').to('2024-06-15') // "in 6 months"
185
+ ```
186
+
187
+ ### Calendar
188
+
189
+ ```js
190
+ tempox().calendar() // "Today at 2:30 PM"
191
+ tempox().add(1,'day').calendar() // "Tomorrow at 2:30 PM"
192
+ tempox().subtract(1,'day').calendar() // "Yesterday at 2:30 PM"
193
+ tempox().add(3,'days').calendar() // "Tuesday at 2:30 PM"
194
+ tempox().subtract(7,'days').calendar() // "06/08/2024"
195
+ ```
196
+
197
+ ### Diff
198
+
199
+ ```js
200
+ tempox('2024-06-15').diff('2024-01-01', 'days') // 166
201
+ tempox('2024-06-15').diff('2024-01-01', 'months') // 5
202
+ tempox('2024-06-15').diff('2020-01-01', 'years') // 4
203
+ tempox('2024-06-15T12:00').diff('2024-06-15T10:00', 'hours') // 2
204
+ tempox('2024-06-15').diff('2024-01-01', 'days', true) // 166.xxx (float)
205
+ ```
206
+
207
+ ### Query / Comparison
208
+
209
+ ```js
210
+ tempox('2024-01-01').isBefore('2024-06-15') // true
211
+ tempox('2024-06-15').isAfter('2024-01-01') // true
212
+ tempox('2024-06-15T10:00').isSame('2024-06-15T18:00', 'day') // true
213
+ tempox('2024-01-01').isSameOrBefore('2024-01-01') // true
214
+ tempox('2024-06-15').isSameOrAfter('2024-06-15') // true
215
+ tempox('2024-03-15').isBetween('2024-01-01','2024-12-31') // true
216
+ tempox('2024-01-01').isBetween('2024-01-01','2024-12-31',null,'[]') // inclusive
217
+
218
+ tempox('2024-06-15').isLeapYear() // true
219
+ tempox().isDST() // true/false
220
+ tempox.isMoment(tempox()) // true (also isTempox)
221
+ tempox.isDate(new Date()) // true
222
+ ```
223
+
224
+ ### UTC & Timezone
225
+
226
+ ```js
227
+ // UTC mode
228
+ tempox.utc('2024-06-15T10:30:00').format('HH:mm') // always UTC hours
229
+ tempox.utc().isUTC() // true
230
+ tempox.utc().local() // switch to local mode
231
+
232
+ // UTC offset
233
+ tempox().utcOffset() // current offset in minutes
234
+ tempox().utcOffset('+05:30') // set offset
235
+ tempox().utcOffset(330) // set by minutes
236
+ tempox().utcOffset(0, true) // keep local time, change offset
237
+ ```
238
+
239
+ ### Duration
240
+
241
+ ```js
242
+ var d = tempox.duration(2, 'days');
243
+ d.asDays() // 2
244
+ d.asHours() // 48
245
+ d.asMinutes() // 2880
246
+
247
+ tempox.duration({ hours: 1, minutes: 30 }).asMinutes() // 90
248
+ tempox.duration('P1Y2M3DT4H5M6S') // ISO 8601 duration string
249
+ tempox.duration(1,'day').humanize() // "a day"
250
+ tempox.duration(1,'day').humanize(true) // "in a day"
251
+
252
+ d.years() / d.months() / d.days() / d.hours() / d.minutes() / d.seconds()
253
+ d.add(1, 'hour').subtract(30, 'minutes')
254
+ d.clone()
255
+ d.toISOString() // "P2D"
256
+
257
+ // Add duration to date
258
+ tempox().add(tempox.duration(2,'hours'))
259
+
260
+ tempox.isDuration(d) // true
261
+ ```
262
+
263
+ ### Locale (i18n)
264
+
265
+ ```js
266
+ // Set global locale
267
+ tempox.locale('hi'); // Hindi
268
+ tempox().format('MMMM D, YYYY'); // "जून 15, 2024"
269
+
270
+ // Per-instance locale
271
+ tempox().locale('es').format('MMMM'); // "junio"
272
+
273
+ // Built-in locales
274
+ tempox.locales(); // ['en','hi','es','fr','de','ar','ja']
275
+
276
+ // Define custom locale
277
+ tempox.defineLocale('mr', {
278
+ name: 'mr',
279
+ months: ['जानेवारी','फेब्रुवारी','मार्च',...],
280
+ // ...
281
+ });
282
+
283
+ // Get locale data
284
+ tempox.localeData('en').months
285
+ tempox().localeData()
286
+ ```
287
+
288
+ ### Static Methods
289
+
290
+ ```js
291
+ tempox.max(a, b, c) // returns latest Tempox
292
+ tempox.min(a, b, c) // returns earliest Tempox
293
+ tempox.invalid() // returns an invalid Tempox
294
+ tempox.normalizeUnits('y') // 'year'
295
+ tempox.version // '1.0.0'
296
+ tempox.fn // Tempox.prototype (for plugins)
297
+ ```
298
+
299
+ ---
300
+
301
+ ## React Native Usage
302
+
303
+ Works directly with React Native CLI (Hermes and JSC). No special configuration needed:
304
+
305
+ ```bash
306
+ npm install tempox
307
+ ```
308
+
309
+ ```js
310
+ // In your component
311
+ import tempox from 'tempox'; // ESM syntax works too with Metro
312
+ // or
313
+ const tempox = require('tempox');
314
+
315
+ const DateDisplay = () => {
316
+ const [display, setDisplay] = React.useState(tempox().format('LL'));
317
+ return <Text>{display}</Text>;
318
+ };
319
+ ```
320
+
321
+ ---
322
+
323
+ ## Why tempox over moment?
324
+
325
+ | Feature | moment | tempox |
326
+ |---------|--------|--------|
327
+ | Size (minified) | ~290 KB | ~25 KB |
328
+ | Size (gzipped) | ~72 KB | ~8 KB |
329
+ | Dependencies | 0 | 0 |
330
+ | Tree-shakeable | ❌ | ✅ |
331
+ | Immutable option | ❌ | ✅ `.clone()` |
332
+ | React Native safe | ⚠️ | ✅ |
333
+ | API compatible | ✅ | ✅ |
334
+
335
+ ---
336
+
337
+ ## License
338
+
339
+ MIT
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "datevolt",
3
+ "version": "1.0.0",
4
+ "description": "A complete, lightweight, zero-dependency date library with a moment.js-compatible API. Built for React Native CLI (Android & iOS), Node.js, and browsers.",
5
+ "main": "src/index.js",
6
+ "react-native": "src/index.js",
7
+ "files": [
8
+ "src/",
9
+ "README.md",
10
+ "LICENSE"
11
+ ],
12
+ "scripts": {
13
+ "test": "node test/test.js"
14
+ },
15
+ "keywords": [
16
+ "date",
17
+ "time",
18
+ "moment",
19
+ "moment-alternative",
20
+ "moment-replacement",
21
+ "react-native",
22
+ "android",
23
+ "ios",
24
+ "hermes",
25
+ "date-format",
26
+ "date-parse",
27
+ "datetime",
28
+ "timezone",
29
+ "duration",
30
+ "locale",
31
+ "calendar",
32
+ "lightweight",
33
+ "zero-dependency",
34
+ "javascript"
35
+ ],
36
+ "author": "shaikh-saqlain",
37
+ "license": "MIT",
38
+ "engines": {
39
+ "node": ">=12"
40
+ },
41
+ "react-native-metadata": {
42
+ "platforms": [
43
+ "android",
44
+ "ios"
45
+ ]
46
+ },
47
+ "dependencies": {},
48
+ "devDependencies": {},
49
+ "repository": {
50
+ "type": "git",
51
+ "url": "git+https://github.com/shaikh-saqlain/datevolt.git"
52
+ },
53
+ "bugs": {
54
+ "url": "https://github.com/shaikh-saqlain/datevolt/issues"
55
+ },
56
+ "homepage": "https://github.com/shaikh-saqlain/datevolt#readme"
57
+ }
@@ -0,0 +1,188 @@
1
+ 'use strict';
2
+
3
+ var localeModule = require('./locale');
4
+
5
+ var MS = {
6
+ ms: 1, millisecond: 1, milliseconds: 1,
7
+ s: 1000, second: 1000, seconds: 1000,
8
+ m: 60000, minute: 60000, minutes: 60000,
9
+ h: 3600000, hour: 3600000, hours: 3600000,
10
+ d: 86400000, day: 86400000, days: 86400000,
11
+ w: 604800000, week: 604800000, weeks: 604800000,
12
+ M: 2629800000, month: 2629800000, months: 2629800000, // 30.4375 days
13
+ y: 31557600000, year: 31557600000, years: 31557600000 // 365.25 days
14
+ };
15
+
16
+ // ISO 8601 duration string: P1Y2M3DT4H5M6S
17
+ var ISO_DURATION_REGEX = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;
18
+
19
+ function Duration(input, unit) {
20
+ this.__isDuration = true;
21
+ this._locale = localeModule.getGlobalLocale();
22
+
23
+ if (typeof input === 'string') {
24
+ var isoMatch = input.match(ISO_DURATION_REGEX);
25
+ if (isoMatch) {
26
+ var sign = isoMatch[1] === '-' ? -1 : 1;
27
+ this._years = sign * parseFloat(isoMatch[2]||0);
28
+ this._months = sign * parseFloat(isoMatch[3]||0);
29
+ this._weeks = sign * parseFloat(isoMatch[4]||0);
30
+ this._days = sign * parseFloat(isoMatch[5]||0);
31
+ this._hours = sign * parseFloat(isoMatch[6]||0);
32
+ this._minutes = sign * parseFloat(isoMatch[7]||0);
33
+ this._seconds = sign * parseFloat(isoMatch[8]||0);
34
+ this._ms = 0;
35
+ this._milliseconds = 0;
36
+ } else {
37
+ this._ms = 0;
38
+ this._years=this._months=this._weeks=this._days=this._hours=this._minutes=this._seconds=this._milliseconds=0;
39
+ }
40
+ } else if (typeof input === 'number') {
41
+ var resolvedUnit = unit || 'ms';
42
+ var multiplier = MS[resolvedUnit] || 1;
43
+ this._ms = input * multiplier;
44
+ this._years = 0; this._months = 0; this._weeks = 0; this._days = 0;
45
+ this._hours = 0; this._minutes = 0; this._seconds = 0; this._milliseconds = 0;
46
+ this._normalizeFromMs();
47
+ } else if (typeof input === 'object' && input !== null) {
48
+ this._years = input.years || input.year || input.y || 0;
49
+ this._months = input.months || input.month || input.M || 0;
50
+ this._weeks = input.weeks || input.week || input.w || 0;
51
+ this._days = input.days || input.day || input.d || 0;
52
+ this._hours = input.hours || input.hour || input.h || 0;
53
+ this._minutes = input.minutes || input.minute || input.m || 0;
54
+ this._seconds = input.seconds || input.second || input.s || 0;
55
+ this._milliseconds= input.milliseconds|| input.millisecond||input.ms||0;
56
+ this._ms = this._toMs();
57
+ } else {
58
+ this._ms = 0;
59
+ this._years=this._months=this._weeks=this._days=this._hours=this._minutes=this._seconds=this._milliseconds=0;
60
+ }
61
+ }
62
+
63
+ Duration.prototype._toMs = function() {
64
+ return this._years * MS.y + this._months * MS.M + this._weeks * MS.w +
65
+ this._days * MS.d + this._hours * MS.h + this._minutes * MS.m +
66
+ this._seconds * MS.s + this._milliseconds;
67
+ };
68
+
69
+ Duration.prototype._normalizeFromMs = function() {
70
+ var remaining = Math.abs(this._ms);
71
+ var sign = this._ms < 0 ? -1 : 1;
72
+ this._years = sign * Math.floor(remaining / MS.y); remaining %= MS.y;
73
+ this._months = sign * Math.floor(remaining / MS.M); remaining %= MS.M;
74
+ this._days = sign * Math.floor(remaining / MS.d); remaining %= MS.d;
75
+ this._hours = sign * Math.floor(remaining / MS.h); remaining %= MS.h;
76
+ this._minutes = sign * Math.floor(remaining / MS.m); remaining %= MS.m;
77
+ this._seconds = sign * Math.floor(remaining / MS.s); remaining %= MS.s;
78
+ this._milliseconds = sign * remaining;
79
+ this._weeks = 0;
80
+ };
81
+
82
+ // ── Getters ───────────────────────────────────────────────────────────────────
83
+ Duration.prototype.years = function() { return this._years; };
84
+ Duration.prototype.months = function() { return this._months; };
85
+ Duration.prototype.weeks = function() { return Math.floor(this._days/7); };
86
+ Duration.prototype.days = function() { return this._days % 7; };
87
+ Duration.prototype.hours = function() { return this._hours; };
88
+ Duration.prototype.minutes = function() { return this._minutes; };
89
+ Duration.prototype.seconds = function() { return this._seconds; };
90
+ Duration.prototype.milliseconds = function() { return this._milliseconds; };
91
+
92
+ // ── as() ─────────────────────────────────────────────────────────────────────
93
+ Duration.prototype.as = function(unit) {
94
+ var totalMs = this._toMs();
95
+ var multiplier = MS[unit] || 1;
96
+ return totalMs / multiplier;
97
+ };
98
+
99
+ Duration.prototype.asMilliseconds = function() { return this._toMs(); };
100
+ Duration.prototype.asSeconds = function() { return this._toMs()/1000; };
101
+ Duration.prototype.asMinutes = function() { return this._toMs()/60000; };
102
+ Duration.prototype.asHours = function() { return this._toMs()/3600000; };
103
+ Duration.prototype.asDays = function() { return this._toMs()/86400000; };
104
+ Duration.prototype.asWeeks = function() { return this._toMs()/604800000; };
105
+ Duration.prototype.asMonths = function() { return this._toMs()/2629800000; };
106
+ Duration.prototype.asYears = function() { return this._toMs()/31557600000; };
107
+
108
+ Duration.prototype.get = function(unit) {
109
+ return this.as(unit);
110
+ };
111
+
112
+ // ── Add / Subtract ────────────────────────────────────────────────────────────
113
+ Duration.prototype.add = function(input, unit) {
114
+ var other = input instanceof Duration ? input : new Duration(input, unit);
115
+ this._years += other._years;
116
+ this._months += other._months;
117
+ this._weeks += other._weeks;
118
+ this._days += other._days;
119
+ this._hours += other._hours;
120
+ this._minutes += other._minutes;
121
+ this._seconds += other._seconds;
122
+ this._milliseconds+= other._milliseconds;
123
+ this._ms = this._toMs();
124
+ return this;
125
+ };
126
+
127
+ Duration.prototype.subtract = function(input, unit) {
128
+ var other = input instanceof Duration ? input : new Duration(input, unit);
129
+ this._years -= other._years;
130
+ this._months -= other._months;
131
+ this._weeks -= other._weeks;
132
+ this._days -= other._days;
133
+ this._hours -= other._hours;
134
+ this._minutes -= other._minutes;
135
+ this._seconds -= other._seconds;
136
+ this._milliseconds-= other._milliseconds;
137
+ this._ms = this._toMs();
138
+ return this;
139
+ };
140
+
141
+ // ── Humanize ─────────────────────────────────────────────────────────────────
142
+ Duration.prototype.humanize = function(withSuffix) {
143
+ var ms = Math.abs(this._toMs());
144
+ var loc = localeModule.getLocale(this._locale);
145
+ var rt = loc.relativeTime;
146
+ var str;
147
+
148
+ var secs = ms/1000, mins = ms/60000, hrs = ms/3600000,
149
+ days = ms/86400000, weeks = ms/604800000,
150
+ months = ms/2629800000, years = ms/31557600000;
151
+
152
+ if (ms < 45000) str = rt.s;
153
+ else if (ms < 90000) str = rt.m;
154
+ else if (ms < 2700000) str = rt.mm.replace('%d', Math.round(mins));
155
+ else if (ms < 5400000) str = rt.h;
156
+ else if (ms < 79200000) str = rt.hh.replace('%d', Math.round(hrs));
157
+ else if (ms < 129600000)str = rt.d;
158
+ else if (ms < 2160000000)str = rt.dd.replace('%d', Math.round(days));
159
+ else if (ms < 3888000000)str = rt.M;
160
+ else if (ms < 31536000000)str = rt.MM.replace('%d', Math.round(months));
161
+ else if (ms < 47260800000)str = rt.y;
162
+ else str = rt.yy.replace('%d', Math.round(years));
163
+
164
+ if (withSuffix) {
165
+ if (this._toMs() >= 0) return rt.future.replace('%s', str);
166
+ return rt.past.replace('%s', str);
167
+ }
168
+ return str;
169
+ };
170
+
171
+ Duration.prototype.locale = function(loc) {
172
+ this._locale = loc;
173
+ return this;
174
+ };
175
+
176
+ // ── ISO string ────────────────────────────────────────────────────────────────
177
+ Duration.prototype.toISOString = function() {
178
+ var Y = this._years, M = this._months, W = this._weeks;
179
+ var D = this._days, H = this._hours, m = this._minutes, S = this._seconds;
180
+ return 'P' + (Y?Y+'Y':'') + (M?M+'M':'') + (W?W+'W':'') + (D?D+'D':'') +
181
+ ((H||m||S)?('T'+(H?H+'H':'')+(m?m+'M':'')+(S?S+'S':'')):'') || 'P0D';
182
+ };
183
+
184
+ Duration.prototype.toJSON = Duration.prototype.toISOString;
185
+ Duration.prototype.valueOf = function() { return this._toMs(); };
186
+ Duration.prototype.clone = function() { return new Duration(this._toMs()); };
187
+
188
+ module.exports = Duration;