-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(dateTime)!: correctly works with timezones, utc offsets and DST (#36
- Loading branch information
Showing
27 changed files
with
1,905 additions
and
151 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
build |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
export * from './dateTime'; | ||
export * from './format'; | ||
export * from './timeZone'; | ||
export * from './utils'; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
import {dateTime} from '../dateTime'; | ||
|
||
test('add short reverse args', () => { | ||
let a = dateTime().year(2011).month(9).date(12).hour(6).minute(7).second(8).millisecond(500); | ||
|
||
expect((a = a.add({ms: 50})).millisecond()).toBe(550); | ||
expect((a = a.add({s: 1})).second()).toBe(9); | ||
expect((a = a.add({m: 1})).minute()).toBe(8); | ||
expect((a = a.add({h: 1})).hour()).toBe(7); | ||
expect((a = a.add({d: 1})).date()).toBe(13); | ||
expect((a = a.add({w: 1})).date()).toBe(20); | ||
expect((a = a.add({M: 1})).month()).toBe(10); | ||
expect((a = a.add({y: 1})).year()).toBe(2012); | ||
expect((a = a.add({Q: 1})).month()).toBe(1); | ||
|
||
const b = dateTime({input: [2010, 0, 31]}).add({M: 1}); | ||
expect(b.month()).toBe(1); | ||
expect(b.date()).toBe(28); | ||
|
||
const c = dateTime({input: [2010, 1, 28]}).subtract({M: 1}); | ||
expect(c.month()).toBe(0); | ||
expect(c.date()).toBe(28); | ||
|
||
const d = dateTime({input: [2010, 1, 28]}).subtract({Q: 1}); | ||
expect(d.month()).toBe(10); | ||
expect(d.date()).toBe(28); | ||
expect(d.year()).toBe(2009); | ||
}); | ||
|
||
test('add long reverse args', () => { | ||
let a = dateTime().year(2011).month(9).date(12).hour(6).minute(7).second(8).millisecond(500); | ||
|
||
expect((a = a.add({milliseconds: 50})).millisecond()).toBe(550); | ||
expect((a = a.add({seconds: 1})).second()).toBe(9); | ||
expect((a = a.add({minutes: 1})).minute()).toBe(8); | ||
expect((a = a.add({hours: 1})).hour()).toBe(7); | ||
expect((a = a.add({days: 1})).date()).toBe(13); | ||
expect((a = a.add({weeks: 1})).date()).toBe(20); | ||
expect((a = a.add({months: 1})).month()).toBe(10); | ||
expect((a = a.add({years: 1})).year()).toBe(2012); | ||
expect((a = a.add({quarters: 1})).month()).toBe(1); | ||
}); | ||
|
||
test('add long singular reverse args', () => { | ||
let a = dateTime().year(2011).month(9).date(12).hour(6).minute(7).second(8).millisecond(500); | ||
|
||
expect((a = a.add({millisecond: 50})).millisecond()).toBe(550); | ||
expect((a = a.add({second: 1})).second()).toBe(9); | ||
expect((a = a.add({minute: 1})).minute()).toBe(8); | ||
expect((a = a.add({hour: 1})).hour()).toBe(7); | ||
expect((a = a.add({day: 1})).date()).toBe(13); | ||
expect((a = a.add({week: 1})).date()).toBe(20); | ||
expect((a = a.add({month: 1})).month()).toBe(10); | ||
expect((a = a.add({year: 1})).year()).toBe(2012); | ||
expect((a = a.add({quarter: 1})).month()).toBe(1); | ||
}); | ||
|
||
test('add string long', () => { | ||
let a = dateTime().year(2011).month(9).date(12).hour(6).minute(7).second(8).millisecond(500); | ||
|
||
expect((a = a.add(50, 'milliseconds')).millisecond()).toBe(550); | ||
expect((a = a.add(1, 'seconds')).second()).toBe(9); | ||
expect((a = a.add(1, 'minutes')).minute()).toBe(8); | ||
expect((a = a.add(1, 'hours')).hour()).toBe(7); | ||
expect((a = a.add(1, 'days')).date()).toBe(13); | ||
expect((a = a.add(1, 'weeks')).date()).toBe(20); | ||
expect((a = a.add(1, 'months')).month()).toBe(10); | ||
expect((a = a.add(1, 'years')).year()).toBe(2012); | ||
expect((a = a.add(1, 'quarters')).month()).toBe(1); | ||
}); | ||
|
||
test('add string long singular', () => { | ||
let a = dateTime().year(2011).month(9).date(12).hour(6).minute(7).second(8).millisecond(500); | ||
|
||
expect((a = a.add(50, 'millisecond')).millisecond()).toBe(550); | ||
expect((a = a.add(1, 'second')).second()).toBe(9); | ||
expect((a = a.add(1, 'minute')).minute()).toBe(8); | ||
expect((a = a.add(1, 'hour')).hour()).toBe(7); | ||
expect((a = a.add(1, 'day')).date()).toBe(13); | ||
expect((a = a.add(1, 'week')).date()).toBe(20); | ||
expect((a = a.add(1, 'month')).month()).toBe(10); | ||
expect((a = a.add(1, 'year')).year()).toBe(2012); | ||
expect((a = a.add(1, 'quarter')).month()).toBe(1); | ||
}); | ||
|
||
test('add string short', () => { | ||
let a = dateTime().year(2011).month(9).date(12).hour(6).minute(7).second(8).millisecond(500); | ||
|
||
expect((a = a.add(50, 'ms')).millisecond()).toBe(550); | ||
expect((a = a.add(1, 's')).second()).toBe(9); | ||
expect((a = a.add(1, 'm')).minute()).toBe(8); | ||
expect((a = a.add(1, 'h')).hour()).toBe(7); | ||
expect((a = a.add(1, 'd')).date()).toBe(13); | ||
expect((a = a.add(1, 'w')).date()).toBe(20); | ||
expect((a = a.add(1, 'M')).month()).toBe(10); | ||
expect((a = a.add(1, 'y')).year()).toBe(2012); | ||
expect((a = a.add(1, 'Q')).month()).toBe(1); | ||
}); | ||
|
||
test('add strings string short', () => { | ||
let a = dateTime().year(2011).month(9).date(12).hour(6).minute(7).second(8).millisecond(500); | ||
|
||
expect((a = a.add('50', 'ms')).millisecond()).toBe(550); | ||
expect((a = a.add('1', 's')).second()).toBe(9); | ||
expect((a = a.add('1', 'm')).minute()).toBe(8); | ||
expect((a = a.add('1', 'h')).hour()).toBe(7); | ||
expect((a = a.add('1', 'd')).date()).toBe(13); | ||
expect((a = a.add('1', 'w')).date()).toBe(20); | ||
expect((a = a.add('1', 'M')).month()).toBe(10); | ||
expect((a = a.add('1', 'y')).year()).toBe(2012); | ||
expect((a = a.add('1', 'Q')).month()).toBe(1); | ||
}); | ||
|
||
test('add no string with milliseconds default', () => { | ||
const a = dateTime().year(2011).month(9).date(12).hour(6).minute(7).second(8).millisecond(500); | ||
|
||
expect(a.add(50).millisecond()).toBe(550); | ||
}); | ||
|
||
test('subtract strings string short', () => { | ||
let a = dateTime().year(2011).month(9).date(12).hour(6).minute(7).second(8).millisecond(500); | ||
|
||
expect((a = a.subtract('50', 'ms')).millisecond()).toBe(450); | ||
expect((a = a.subtract('1', 's')).second()).toBe(7); | ||
expect((a = a.subtract('1', 'm')).minute()).toBe(6); | ||
expect((a = a.subtract('1', 'h')).hour()).toBe(5); | ||
expect((a = a.subtract('1', 'd')).date()).toBe(11); | ||
expect((a = a.subtract('1', 'w')).date()).toBe(4); | ||
expect((a = a.subtract('1', 'M')).month()).toBe(8); | ||
expect((a = a.subtract('1', 'y')).year()).toBe(2010); | ||
expect((a = a.subtract('1', 'Q')).month()).toBe(5); | ||
}); | ||
|
||
test('add across DST', () => { | ||
const a = dateTime({input: '2023-11-05T05:00:00Z', timeZone: 'America/New_York'}); | ||
|
||
expect(a.hour()).toBe(1); | ||
expect(a.utcOffset()).toBe(-4 * 60); | ||
|
||
const b = a.add(24, 'hours'); | ||
expect(b.hour()).toBe(0); // adding hours should respect DST difference | ||
expect(b.utcOffset()).toBe(-5 * 60); | ||
|
||
// adding days over DST difference should result in the same hour | ||
const c = a.add(1, 'day'); | ||
expect(c.hour()).toBe(1); | ||
expect(c.utcOffset()).toBe(-5 * 60); | ||
|
||
// adding months over DST difference should result in the same hour | ||
const d = a.add(1, 'month'); | ||
expect(d.hour()).toBe(1); | ||
expect(d.utcOffset()).toBe(-5 * 60); | ||
|
||
// adding quarters over DST difference should result in the same hour | ||
const e = a.add(1, 'quarter'); | ||
expect(e.hour()).toBe(1); | ||
expect(e.utcOffset()).toBe(-5 * 60); | ||
}); | ||
|
||
test('add decimal values of days and months', () => { | ||
expect( | ||
dateTime({input: [2016, 3, 3]}) | ||
.add(1.5, 'days') | ||
.date(), | ||
).toBe(5); | ||
expect( | ||
dateTime({input: [2016, 3, 3]}) | ||
.add(-1.5, 'days') | ||
.date(), | ||
).toBe(1); | ||
expect( | ||
dateTime({input: [2016, 3, 1]}) | ||
.add(-1.5, 'days') | ||
.date(), | ||
).toBe(30); | ||
expect( | ||
dateTime({input: [2016, 3, 3]}) | ||
.add(1.5, 'months') | ||
.month(), | ||
).toBe(5); | ||
expect( | ||
dateTime({input: [2016, 3, 3]}) | ||
.add(-1.5, 'months') | ||
.month(), | ||
).toBe(1); | ||
expect( | ||
dateTime({input: [2016, 0, 3]}) | ||
.add(-1.5, 'months') | ||
.month(), | ||
).toBe(10); | ||
expect( | ||
dateTime({input: [2016, 3, 3]}) | ||
.subtract(1.5, 'days') | ||
.date(), | ||
).toBe(1); | ||
expect( | ||
dateTime({input: [2016, 3, 2]}) | ||
.subtract(1.5, 'days') | ||
.date(), | ||
).toBe(31); | ||
expect( | ||
dateTime({input: [2016, 1, 1]}) | ||
.subtract(1.1, 'days') | ||
.date(), | ||
).toBe(31); | ||
expect( | ||
dateTime({input: [2016, 3, 3]}) | ||
.subtract(-1.5, 'days') | ||
.date(), | ||
).toBe(5); | ||
expect( | ||
dateTime({input: [2016, 3, 30]}) | ||
.subtract(-1.5, 'days') | ||
.date(), | ||
).toBe(2); | ||
expect( | ||
dateTime({input: [2016, 3, 3]}) | ||
.subtract(1.5, 'months') | ||
.month(), | ||
).toBe(1); | ||
expect( | ||
dateTime({input: [2016, 3, 3]}) | ||
.subtract(-1.5, 'months') | ||
.month(), | ||
).toBe(5); | ||
expect( | ||
dateTime({input: [2016, 11, 31]}) | ||
.subtract(-1.5, 'months') | ||
.month(), | ||
).toBe(1); | ||
expect( | ||
dateTime({input: [2016, 0, 1]}) | ||
.add(1.5, 'years') | ||
.format('YYYY-MM-DD'), | ||
).toBe('2017-07-01'); | ||
expect( | ||
dateTime({input: [2016, 0, 1]}) | ||
.add(1.6, 'years') | ||
.format('YYYY-MM-DD'), | ||
).toBe('2017-08-01'); | ||
expect( | ||
dateTime({input: [2016, 0, 1]}) | ||
.add(1.1, 'quarters') | ||
.format('YYYY-MM-DD'), | ||
).toBe('2016-04-01'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import {dateTime} from '../dateTime'; | ||
|
||
test('setter / getter', () => { | ||
const m = dateTime({input: [2010]}); | ||
|
||
expect(m.utcOffset(0).utcOffset()).toBe(0); | ||
|
||
expect(m.utcOffset(1).utcOffset()).toBe(60); | ||
expect(m.utcOffset(60).utcOffset()).toBe(60); | ||
expect(m.utcOffset('+01:00').utcOffset()).toBe(60); | ||
expect(m.utcOffset('+0100').utcOffset()).toBe(60); | ||
|
||
expect(m.utcOffset(-1).utcOffset()).toBe(-60); | ||
expect(m.utcOffset(-60).utcOffset()).toBe(-60); | ||
expect(m.utcOffset('-01:00').utcOffset()).toBe(-60); | ||
expect(m.utcOffset('-0100').utcOffset()).toBe(-60); | ||
|
||
expect(m.utcOffset(1.5).utcOffset()).toBe(90); | ||
expect(m.utcOffset(90).utcOffset()).toBe(90); | ||
expect(m.utcOffset('+01:30').utcOffset()).toBe(90); | ||
expect(m.utcOffset('+0130').utcOffset()).toBe(90); | ||
|
||
expect(m.utcOffset(-1.5).utcOffset()).toBe(-90); | ||
expect(m.utcOffset(-90).utcOffset()).toBe(-90); | ||
expect(m.utcOffset('-01:30').utcOffset()).toBe(-90); | ||
expect(m.utcOffset('-0130').utcOffset()).toBe(-90); | ||
|
||
expect(m.utcOffset('+00:10').utcOffset()).toBe(10); | ||
expect(m.utcOffset('-00:10').utcOffset()).toBe(-10); | ||
expect(m.utcOffset('+0010').utcOffset()).toBe(10); | ||
expect(m.utcOffset('-0010').utcOffset()).toBe(-10); | ||
}); | ||
|
||
test('utcOffset shorthand hours -> minutes', () => { | ||
let i; | ||
for (i = -15; i <= 15; ++i) { | ||
expect(dateTime().utcOffset(i).utcOffset()).toBe(i * 60); | ||
} | ||
|
||
expect(dateTime().utcOffset(-16).utcOffset()).toBe(-16); | ||
expect(dateTime().utcOffset(16).utcOffset()).toBe(16); | ||
}); | ||
|
||
test('change hours when changing the utc offset', () => { | ||
const m = dateTime({input: [2000, 0, 1, 6]}).utc(true); | ||
expect(m.hour()).toBe(6); | ||
|
||
// sanity check | ||
expect(m.utcOffset(0).hour()).toBe(6); | ||
|
||
expect(m.utcOffset(-60).hour()).toBe(5); | ||
|
||
expect(m.utcOffset(60).hour()).toBe(7); | ||
}); | ||
|
||
test('change minutes when changing the utc offset', () => { | ||
const m = dateTime({input: Date.UTC(2000, 0, 1, 6, 31)}); | ||
|
||
expect(m.utcOffset(0).format('HH:mm')).toBe('06:31'); | ||
|
||
expect(m.utcOffset(-30).format('HH:mm')).toBe('06:01'); | ||
|
||
expect(m.utcOffset(30).format('HH:mm')).toBe('07:01'); | ||
|
||
expect(m.utcOffset(-1380).format('HH:mm')).toBe('07:31'); | ||
}); |
Oops, something went wrong.