Skip to content

Commit

Permalink
parseJSON - minimal implementation for parsing JSON dates from an API
Browse files Browse the repository at this point in the history
  • Loading branch information
marnusw committed Oct 19, 2019
1 parent f98bfe0 commit 13bca26
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 0 deletions.
16 changes: 16 additions & 0 deletions src/parseJSON/benchmark.js
@@ -0,0 +1,16 @@
// @flow
/* eslint-env mocha */
/* global suite, benchmark */

import parseJSON from '.'
import moment from 'moment'

suite('toDate', function() {
benchmark('date-fns', function() {
return parseJSON('2014-10-25T13:46:20+00:00')
})

benchmark('Moment.js', function() {
return moment('2014-10-25T13:46:20+00:00')
})
})
52 changes: 52 additions & 0 deletions src/parseJSON/index.js
@@ -0,0 +1,52 @@
import toDate from '../toDate/index.js'

/**
* @name parseJSON
* @category Common Helpers
* @summary Parse a JSON date string
*
* @description
* Converts a complete ISO date string in UTC time, the typical format for transmitting
* a date in JSON, to a JavaScript `Date` instance.
*
* This is a minimal implementation for converting dates retrieved from a JSON API to
* a `Date` instance which can be used with other functions in the `date-fns` library.
* The following formats are supported:
*
* - `2000-03-15T05:20:10.123Z`: The output of `.toISOString()` and `JSON.stringify(new Date())`
* - `2000-03-15T05:20:10Z`: Without milliseconds
* - `2000-03-15T05:20:10+00:00`: With a zero offset, the default JSON encoded format in some other languages
* - `2000-03-15T05:20:10+0000`: With a zero offset without a colon
*
* For convenience and ease of use these other input types are also supported
* via [toDate]{@link https://date-fns.org/docs/toDate}:
*
* - A `Date` instance will be cloned
* - A `number` will be treated as a timestamp
*
* Any other input type or invalid date strings will return an `Invalid Date`.
*
* @param {String|Number|Date} argument A fully formed ISO1806 date string to convert
* @returns {Date} the parsed date in the local time zone
*/
export default function index(argument) {
if (typeof argument === 'string') {
var parts = argument.match(
/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{3}))?(?:Z|\+00:?00)/
)
if (parts) {
return new Date(
Date.UTC(
+parts[1],
parts[2] - 1,
+parts[3],
+parts[4],
+parts[5],
+parts[6],
+(parts[7] || 0)
)
)
}
}
return toDate(argument)
}
51 changes: 51 additions & 0 deletions src/parseJSON/test.js
@@ -0,0 +1,51 @@
import assert from 'power-assert'
import parseJSON from '.'

describe('parseJSON', function() {
it('parses a fully formed ISO date with Z', () => {
const date = '2000-03-15T05:20:10.123Z'
const parsedDate = parseJSON(date)
assert.equal(parsedDate.toISOString(), date)
})

it('parses a fully formed ISO date with Z without ms', () => {
const date = '2000-03-15T05:20:10Z'
const expectedDate = '2000-03-15T05:20:10.000Z'
const parsedDate = parseJSON(date)
assert.equal(parsedDate.toISOString(), expectedDate)
})

it('parses a fully formed ISO date with zero offset', () => {
const zeroOffset = '2000-03-15T05:20:10+00:00'
const expectedDate = '2000-03-15T05:20:10.000Z'
const parsedDate = parseJSON(zeroOffset)
assert.equal(parsedDate.toISOString(), expectedDate)
})

it('parses a fully formed ISO date with zero offset without colon', () => {
const zeroOffset = '2000-03-15T05:20:10+0000'
const expectedDate = '2000-03-15T05:20:10.000Z'
const parsedDate = parseJSON(zeroOffset)
assert.equal(parsedDate.toISOString(), expectedDate)
})

it('clones a date object', () => {
const date = new Date(2000, 2, 15, 5, 20, 10, 20)
const parsedDate = parseJSON(date)
assert.deepEqual(parsedDate, date)
assert.notEqual(parsedDate, date)
})

it('assumes a number is a timestamp', () => {
const date = new Date(2000, 2, 15, 5, 20, 10, 20)
const timestamp = date.getTime()
const parsedDate = parseJSON(timestamp)
assert.deepEqual(parsedDate, date)
})

it('returns an invalid date for anything else', () => {
assert.equal(parseJSON('').toString(), 'Invalid Date')
assert.equal(parseJSON('invalid').toString(), 'Invalid Date')
assert.equal(parseJSON('2020-10-10').toString(), 'Invalid Date')
})
})

0 comments on commit 13bca26

Please sign in to comment.