00001
00007 var DateFormatter = function (opts) {
00008 this.opts = {}
00009 this.setOpts(opts)
00010 }
00011
00017 DateFormatter.DEFAULT_OPTIONS = {
00018 colons: true
00019 , hyphens: false
00020 , local: true
00021 , ms: false
00022 , offset: false
00023 }
00024
00030 DateFormatter.ISO8601 = new RegExp(
00031 '([0-9]{4})([-]?([0-9]{2}))([-]?([0-9]{2}))'
00032 + '(T([0-9]{2})(((:?([0-9]{2}))?((:?([0-9]{2}))?(\.([0-9]+))?))?)'
00033 + '(Z|([+-]([0-9]{2}(:?([0-9]{2}))?)))?)?'
00034 )
00035
00036
00052 DateFormatter.prototype.setOpts = function (opts) {
00053 if (!opts) opts = DateFormatter.DEFAULT_OPTIONS
00054
00055 var ctx = this
00056 Object.keys(DateFormatter.DEFAULT_OPTIONS).forEach(function (k) {
00057 ctx.opts[k] = opts.hasOwnProperty(k) ?
00058 opts[k] : DateFormatter.DEFAULT_OPTIONS[k]
00059 })
00060 }
00061
00069 DateFormatter.prototype.decodeIso8601 = function(time) {
00070 var dateParts = time.toString().match(DateFormatter.ISO8601)
00071 if (!dateParts) {
00072 throw new Error('Expected a ISO8601 datetime but got \'' + time + '\'')
00073 }
00074
00075 var date = [
00076 [dateParts[1], dateParts[3] || '01', dateParts[5] || '01'].join('-')
00077 , 'T'
00078 , [
00079 dateParts[7] || '00'
00080 , dateParts[11] || '00'
00081 , dateParts[14] || '00'
00082 ].join(':')
00083 , '.'
00084 , dateParts[16] || '000'
00085 ].join('')
00086
00087 date += (dateParts[17] !== undefined) ?
00088 dateParts[17] +
00089 ((dateParts[19] && dateParts[20] === undefined) ? '00' : '') :
00090 DateFormatter.formatCurrentOffset(new Date(date))
00091
00092 return new Date(date)
00093 }
00094
00101 DateFormatter.prototype.encodeIso8601 = function(date) {
00102 var parts = this.opts.local ?
00103 DateFormatter.getLocalDateParts(date) :
00104 DateFormatter.getUTCDateParts(date)
00105
00106 return [
00107 [parts[0],parts[1],parts[2]].join(this.opts.hyphens ? '-' : '')
00108 , 'T'
00109 , [parts[3],parts[4],parts[5]].join(this.opts.colons ? ':' : '')
00110 , (this.opts.ms) ? '.' + parts[6] : ''
00111 , (this.opts.local) ? ((this.opts.offset) ?
00112 DateFormatter.formatCurrentOffset(date) : '') : 'Z'
00113 ].join('')
00114 }
00115
00123 DateFormatter.getUTCDateParts = function (date) {
00124 return [
00125 date.getUTCFullYear()
00126 , DateFormatter.zeroPad(date.getUTCMonth()+1,2)
00127 , DateFormatter.zeroPad(date.getUTCDate(),2)
00128 , DateFormatter.zeroPad(date.getUTCHours(), 2)
00129 , DateFormatter.zeroPad(date.getUTCMinutes(), 2)
00130 , DateFormatter.zeroPad(date.getUTCSeconds(), 2)
00131 , DateFormatter.zeroPad(date.getUTCMilliseconds(), 3)]
00132 }
00133
00134
00142 DateFormatter.getLocalDateParts = function (date) {
00143 return [
00144 date.getFullYear()
00145 , DateFormatter.zeroPad(date.getMonth()+1,2)
00146 , DateFormatter.zeroPad(date.getDate(),2)
00147 , DateFormatter.zeroPad(date.getHours(), 2)
00148 , DateFormatter.zeroPad(date.getMinutes(), 2)
00149 , DateFormatter.zeroPad(date.getSeconds(), 2)
00150 , DateFormatter.zeroPad(date.getMilliseconds(), 3)]
00151 }
00152
00162 DateFormatter.zeroPad = function (digit, length) {
00163 var padded = '' + digit
00164 while (padded.length < length) {
00165 padded = '0' + padded
00166 }
00167
00168 return padded
00169 }
00170
00177 DateFormatter.formatCurrentOffset = function (d) {
00178 var offset = (d || new Date()).getTimezoneOffset()
00179 return (offset === 0) ? 'Z' : [
00180 (offset < 0) ? '+' : '-'
00181 , DateFormatter.zeroPad(Math.abs(Math.floor(offset/60)),2)
00182 , ':'
00183 , DateFormatter.zeroPad(Math.abs(offset%60),2)
00184 ].join('')
00185 }
00186
00187
00188 module.exports = new DateFormatter()