Skip to content

Instantly share code, notes, and snippets.

@sstephenson
Created August 10, 2011 20:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sstephenson/1138209 to your computer and use it in GitHub Desktop.
Save sstephenson/1138209 to your computer and use it in GitHub Desktop.
ISO8601 (JSON) timestamp support for Date.parse
# Older browsers do not support ISO8601 (JSON) timestamps in Date.parse
if isNaN Date.parse "2011-01-01T12:00:00-05:00"
parse = Date.parse
iso8601 = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|[-+]?[\d:]+)$/
Date.parse = (dateString) ->
dateString = dateString.toString()
if matches = dateString.match iso8601
[_, year, month, day, hour, minute, second, zone] = matches
offset = zone.replace(":", "") if zone isnt "Z"
dateString = "#{year}/#{month}/#{day} #{hour}:#{minute}:#{second} GMT#{[offset]}"
parse dateString
Copy link

ghost commented Aug 11, 2011

And the antithesis...

if typeof Date::toISOString isnt 'function'

  Date::toISOString = ->
    throw new RangeError if not isFinite @

    result = [@getUTCFullYear(), @getUTCMonth() + 1, @getUTCDate(), @getUTCHours(),
      @getUTCMinutes(), @getUTCSeconds()]

    # Months, dates, hours, minutes, and seconds should have two digits.
    (result[index] = '0' + element) for element, index in result when element < 10

    # Milliseconds should have three digits.
    "#{result.slice(0, 3).join('-')}T#{result.slice(3).join(':')}." +
      "#{('000' + @getUTCMilliseconds()).slice(-3)}Z"

  Date::toJSON = ->
    if isFinite @ then @toISOString() else null

Edit: Actually, I think your RegExp should be /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d{3})?(Z|[-+]?[\d:]+)$/, since all native implementations now return milliseconds as part of the ISO 8601 string. ECMAScript 5 doesn't mandate this; 5.1 does.

Copy link

ghost commented Aug 11, 2011

Parsing the full range of valid date time string values as defined by ES 5.1 section 15.9.1.15 requires this monstrosity: /^(\d{4})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.\d{3})?)?(Z|(?:[-+]\d{2}:\d{2}))?)?)?)?$/. (I'm not particularly adept at RegExps, so there's likely a better way to write that).

It preserves the seven capturing groups that you're currently using to parse the provided date time string, but, if you'd like to use it, you'll need to slightly modify offset and dateString:

offset = zone.replace(":", "") if zone? and zone isnt "Z"
"#{year}/#{month || 1}/#{day || 1} #{hour || 1}:#{minute || 1}:#{second || 1} GMT#{[offset]}"

Edit: Slightly improved the RegExp...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment