Created
September 24, 2019 15:45
-
-
Save DaneWeber/efb476bd8972aec3a37a338b8a3ecd88 to your computer and use it in GitHub Desktop.
ISO8601 date & time with offset for Javascript
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
Date.prototype.toJSON = function () { | |
const tzOffset = 0 - this.getTimezoneOffset(); // Javascript is backwards from ISO8601 | |
const sign = tzOffset >= 0 ? '+' : '-'; | |
const timezoneOffsetInHours = Math.abs(Math.floor(tzOffset / 60)); | |
const leadingHourZero = timezoneOffsetInHours < 10 ? '0' : ''; | |
const timezoneOffsetMinuteRemainder = Math.abs(Math.floor(tzOffset % 60)); | |
const leadingMinuteZero = timezoneOffsetMinuteRemainder < 10 ? '0' : ''; | |
const offset = sign + leadingHourZero + timezoneOffsetInHours + ':' + leadingMinuteZero + timezoneOffsetMinuteRemainder; | |
const fakeDate = new Date(Date.UTC(this.getFullYear(), this.getMonth(), | |
this.getDate(), this.getHours(), this.getMinutes(), this.getSeconds())); | |
const iso = fakeDate.toISOString().substring(0,19); | |
return iso + offset; | |
}; |
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
import "./dateToJSON"; | |
// This spec file should be exercised in various timezones. Set the timezone in the container with | |
// docker exec -it -e TZ=Pacific/Chatham cmd | |
// Or interactively with commands like the following: | |
// echo "Pacific/Niue" > /etc/timezone | |
// dpkg-reconfigure tzdata | |
// date | |
describe('Date Prototype', () => { | |
describe('toJSON', () => { | |
const localNow = new Date(); | |
const localNowToJSON = localNow.toJSON(); | |
it('Date().toJSON() overrides the usual JSON.stringify() behavior (which is used by Axios for posting to API endpoints)', () => { | |
const expectedResult = '"' + localNowToJSON + '"'; | |
const result = JSON.stringify(localNow); | |
expect(result).toEqual(expectedResult); | |
}); | |
it('new Date().toJSON() produces a string', () => { | |
// act | |
const result = new Date().toJSON(); | |
// assert | |
expect(result).toEqual(expect.any(String)); | |
}); | |
it('produces an ISO8601 timestamp with offset', () => { | |
// arrange | |
const now = new Date(); | |
// 2000-01-24T02:34:56-10:00 | |
const iso8601pattern = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}/; | |
// act | |
const result = now.toJSON(); | |
// assert | |
expect(result).toMatch(iso8601pattern); | |
}); | |
it('matches the local year', () => { | |
// arrange | |
const expectedResult = localNow.getFullYear(); | |
// act | |
const result = parseInt(localNowToJSON.substring(0,4), 10); | |
// assert | |
expect(result).toEqual(expectedResult); | |
}); | |
it('matches the local month', () => { | |
// arrange | |
const expectedResult = localNow.getMonth() + 1; | |
// act | |
const result = parseInt(localNowToJSON.substring(5,7), 10); | |
// assert | |
expect(result).toEqual(expectedResult); | |
}); | |
it('matches the local date', () => { | |
// arrange | |
const expectedResult = localNow.getDate(); | |
// act | |
const result = parseInt(localNowToJSON.substring(8,10), 10); | |
// assert | |
expect(result).toEqual(expectedResult); | |
}); | |
it('matches the local hour', () => { | |
// arrange | |
const expectedResult = localNow.getHours(); | |
// act | |
const result = parseInt(localNowToJSON.substring(11,13), 10); | |
// assert | |
expect(result).toEqual(expectedResult); | |
}); | |
it('matches the local minutes', () => { | |
// arrange | |
const expectedResult = localNow.getMinutes(); | |
// act | |
const result = parseInt(localNowToJSON.substring(14,16), 10); | |
// assert | |
expect(result).toEqual(expectedResult); | |
}); | |
it('matches the local seconds', () => { | |
// arrange | |
const expectedResult = localNow.getSeconds(); | |
// act | |
const result = parseInt(localNowToJSON.substring(17,19), 10); | |
// assert | |
expect(result).toEqual(expectedResult); | |
}); | |
it('includes the correct local UTC offset sign', () => { | |
// arrange | |
const expectedResult = 0 - localNow.getTimezoneOffset() >= 0 ? '+' : '-'; | |
// act | |
const result = localNowToJSON.substring(19,20); | |
// assert | |
expect(result).toEqual(expectedResult); | |
}); | |
it('includes the local UTC offset hours', () => { | |
// arrange | |
const expectedResult = Math.floor(Math.abs(localNow.getTimezoneOffset() / 60)); | |
// act | |
const result = parseInt(localNowToJSON.substring(20,22), 10); | |
// assert | |
expect(result).toEqual(expectedResult); | |
}); | |
it('includes the local UTC offset minutes', () => { | |
// arrange | |
const expectedResult = Math.abs(localNow.getTimezoneOffset() % 60); | |
// act | |
const result = parseInt(localNowToJSON.substring(23,25), 10); | |
// assert | |
expect(result).toEqual(expectedResult); | |
}); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment