diff --git a/strftime.js b/strftime.js index 4b50c80..c331e35 100644 --- a/strftime.js +++ b/strftime.js @@ -9,358 +9,358 @@ // http://sjs.mit-license.org // -;(function() { +; +(function () { +// Where to export the API +var namespace; +var toString = Object.prototype.toString; - //// Where to export the API - var namespace; - - // CommonJS / Node module - if (typeof module !== 'undefined') { +try { + // CommonJS / Node module namespace = module.exports = strftime; - } - - // Browsers and other environments - else { +} catch (error) { + // Browsers and other environments // Get the global object. Works in ES3, ES5, and ES5 strict mode. - namespace = (function(){ return this || (1,eval)('this') }()); - } + namespace = new Function('return this')(); +} - function words(s) { return (s || '').split(' '); } +var defaultLocale = { + days: 'Sunday Monday Tuesday Wednesday Thursday Friday Saturday'.split(' '), + shortDays: 'Sun Mon Tue Wed Thu Fri Sat'.split(' '), + months: 'January February March April May June July August September October November December'.split(' '), + shortMonths: 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' '), + AM: 'AM', + PM: 'PM', + am: 'am', + pm: 'pm' +}; - var DefaultLocale = - { days: words('Sunday Monday Tuesday Wednesday Thursday Friday Saturday') - , shortDays: words('Sun Mon Tue Wed Thu Fri Sat') - , months: words('January February March April May June July August September October November December') - , shortMonths: words('Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec') - , AM: 'AM' - , PM: 'PM' - , am: 'am' - , pm: 'pm' - }; +var defaultFormats = { + D: '%m/%d/%y', + F: '%Y-%m-%d', + R: '%H:%M', + r: '%I:%M:%S %p', + T: '%H:%M:%S', + v: '%e-%b-%Y' +}; - namespace.strftime = strftime; - function strftime(fmt, d, locale) { - return _strftime(fmt, d, locale); - } +// d, locale, and options are optional, but you can't leave +// holes in the argument list. If you pass options you have to pass +// in all the preceding args as well. +// +// options: +// - locale [object] an object with the same structure as defaultLocale +// - timezone [number] timezone offset in minutes from GMT +function _strftime(f, date, locale, options) { + var o = options || {}; + var l = locale; + var d = date; + var ts; - // locale is optional - namespace.strftimeTZ = strftime.strftimeTZ = strftimeTZ; - function strftimeTZ(fmt, d, locale, timezone) { - if ((typeof locale == 'number' || typeof locale == 'string') && timezone == null) { - timezone = locale; - locale = undefined; + if (d && toString.call(d) !== '[object Date]') { + l = d; + d = null; } - return _strftime(fmt, d, locale, { timezone: timezone }); - } - namespace.strftimeUTC = strftime.strftimeUTC = strftimeUTC; - function strftimeUTC(fmt, d, locale) { - return _strftime(fmt, d, locale, { utc: true }); - } - - namespace.localizedStrftime = strftime.localizedStrftime = localizedStrftime; - function localizedStrftime(locale) { - return function(fmt, d, options) { - return strftime(fmt, d, locale, options); - }; - } - - // d, locale, and options are optional, but you can't leave - // holes in the argument list. If you pass options you have to pass - // in all the preceding args as well. - // - // options: - // - locale [object] an object with the same structure as DefaultLocale - // - timezone [number] timezone offset in minutes from GMT - function _strftime(fmt, d, locale, options) { - options = options || {}; - - // d and locale are optional so check if d is really the locale - if (d && !quacksLikeDate(d)) { - locale = d; - d = undefined; - } + l = l || defaultLocale; + l.formats = l.formats || {}; d = d || new Date(); + ts = d.getTime(); + d = fixTZ(d, o); - locale = locale || DefaultLocale; - locale.formats = locale.formats || {}; + return match(f, d, l, ts, o); +} - // Hang on to this Unix timestamp because we might mess with it directly below. - var timestamp = d.getTime(); +var mask = { + 'A': function (padding, date, locale) { + return locale.days[date.getDay()]; + }, + 'a': function (padding, date, locale) { + return locale.shortDays[date.getDay()]; + }, + 'B': function (padding, date, locale) { + return locale.months[date.getMonth()]; + }, + 'b': function (padding, date, locale) { + return locale.shortMonths[date.getMonth()]; + }, + 'C': function (padding, date) { + return pad(Math.floor(date.getFullYear() / 100), padding); + }, + 'D': function (padding, date, locale) { + return _strftime(locale.formats.D || '%m/%d/%y', date, locale); + }, + 'd': function (padding, date) { + return pad(date.getDate(), padding); + }, + 'e': function (padding, date) { + return date.getDate(); + }, + 'F': function (padding, date, locale) { + return _strftime(locale.formats.F || '%Y-%m-%d', date, locale); + }, + 'H': function (padding, date) { + return pad(date.getHours(), padding); + }, + 'h': function (padding, date, locale) { + return locale.shortMonths[date.getMonth()]; + }, + 'I': function (padding, date) { + return pad(hours12(date), padding); + }, + 'j': function (padding, date) { + var y = new Date(date.getFullYear(), 0, 1); + var day = Math.ceil((date.getTime() - y.getTime()) / (1000 * 60 * 60 * 24)); + return pad(day, null, 3); + }, + 'k': function (padding, date) { + return pad(date.getHours(), padding == null ? ' ' : padding); + }, + 'L': function (padding, date, locale, timestamp) { + return pad(Math.floor(timestamp % 1000), null, 3); + }, + 'l': function (padding, date) { + return pad(hours12(date), padding == null ? ' ' : padding); + }, + 'M': function (padding, date) { + return pad(date.getMinutes(), padding); + }, + 'm': function (padding, date) { + return pad(date.getMonth() + 1, padding); + }, + 'n': function () { + return '\n'; + }, + 'o': function (padding, date) { + var _date = date.getDate(); + return String(_date) + ordinal(_date); + }, + 'P': function (padding, date, locale) { + return date.getHours() < 12 ? locale.am : locale.pm; + }, + 'p': function (padding, date, locale) { + return date.getHours() < 12 ? locale.AM : locale.PM; + }, + 'R': function (padding, date, locale) { + return _strftime(locale.formats.R || '%H:%M', date, locale); + }, + 'r': function (padding, date, locale) { + return _strftime(locale.formats.r || '%I:%M:%S %p', date, locale); + }, + 'S': function (padding, date) { + return pad(date.getSeconds(), padding); + }, + 's': function (padding, date, locale, timestamp) { + return Math.floor(timestamp / 1000); + }, + 'T': function (padding, date, locale) { + return _strftime(locale.formats.T || '%H:%M:%S', date, locale); + }, + 't': function () { + return '\t'; + }, + 'U': function (padding, date) { + return pad(weekNumber(date, 'sunday'), padding); + }, + 'u': function (padding, date) { + var day = date.getDay(); + return day === 0 ? 7 : day; + }, + 'v': function (padding, date, locale) { + return _strftime(locale.formats.v || '%e-%b-%Y', date, locale); + }, + 'W': function (padding, date) { + return pad(weekNumber(date, 'monday'), padding); + }, + 'w': function (padding, date) { + return date.getDay(); + }, + 'Y': function (padding, date) { + return date.getFullYear(); + }, + 'y': function (padding, date) { + return String(date.getFullYear()).slice(-2); + }, + 'Z': function (padding, date, locale, timestamp, options) { + if (options.utc) { + return 'GMT'; + } else { + var tzString = date.toString().match(/\((\w+)\)/); + return tzString && tzString[1] || ''; + } + }, + 'z': function (padding, date, locale, timestamp, options) { + if (options.utc) { + return '+0000'; + } else { + var off = typeof options.timezone === 'number' ? options.timezone : -date.getTimezoneOffset(); + return (off < 0 ? '-' : '+') + pad(Math.abs(off / 60)) + pad(off % 60); + } + } +}; - var tz = options.timezone; +// Most of the specifiers supported by C's strftime, and some from Ruby. +// Some other syntax extensions from Ruby are supported: %-, %_, and %0 +// to pad with nothing, space, or zero (respectively). +function match(f, d, l, ts, o) { + var m, i = 0, r = '', c; + var re = /%([-_0]?)(.)/g; + + while (m = re.exec(f)) { + c = m[2]; + r += f.substring(i, m.index) + (mask[c] ? mask[c](fixPadding(m[1], m[0]), d, l, ts, o) : c); + i = re.lastIndex; + } + + return r + f.substring(i); +} + +function fixPadding(p, c) { + if (p) { + switch (p) { + case '-': + return ''; + case '_': + return ' '; + case '0': + return p; + default: + return c; + } + } else { + return null; + } +} + +function dateToUTC(d) { + return new Date(d.getTime() + (d.getTimezoneOffset() || 0) * 60000); +} + +// Default padding is '0' and default length is 2, both are optional. +function pad(n, padding, length) { + var _n = String(n); + var _p = padding == null ? '0' : padding; + var _l = length || 2; + + // padding may be an empty string, don't loop forever if it is + if (_p) { + while (_n.length < _l) { + _n = _p + _n; + } + } + + return _n; +} + +function hours12(d) { + var hour = d.getHours(); + + if (hour === 0) { + hour = 12; + } else if (hour > 12) { + hour -= 12; + } + + return hour; +} + +// Get the ordinal suffix for a number: st, nd, rd, or th +function ordinal(n) { + var i = n % 10; + var ii = n % 100; + + if ((ii >= 11 && ii <= 13) || i === 0 || i >= 4) { + return 'th'; + } + + switch (i) { + case 1: + return 'st'; + case 2: + return 'nd'; + case 3: + return 'rd'; + } +} + +// firstWeekday: 'sunday' or 'monday', default is 'sunday' +// Pilfered & ported from Ruby's strftime implementation. +function weekNumber(d, firstWeekday) { + var firstDayOfYear = new Date(d.getFullYear(), 0, 1); + // This works by shifting the weekday back by one day if we + // are treating Monday as the first day of the week. + var wDay = d.getDay(); + var yDay = (d - firstDayOfYear) / 86400000; + + if (firstWeekday === 'monday') { + if (wDay === 0) { + // Sunday + wDay = 6; + } else { + wDay--; + } + } + + return Math.floor((yDay + 7 - wDay) / 7); +} + +function strftime(fmt, d, locale) { + return _strftime(fmt, d, locale); +} + +// ISO 8601 format timezone string, [-+]HHMM +// Convert to the number of minutes and it'll be applied to the date below. +function fixTZ(date, opt) { + var d = date; + var tz = opt.timezone; var tzType = typeof tz; - if (options.utc || tzType == 'number' || tzType == 'string') { - d = dateToUTC(d); + if (opt.utc || tzType == 'number' || tzType == 'string') { + d = dateToUTC(d); } if (tz) { - // ISO 8601 format timezone string, [-+]HHMM - // - // Convert to the number of minutes and it'll be applied to the date below. - if (tzType == 'string') { - var sign = tz[0] == '-' ? -1 : 1; - var hours = parseInt(tz.slice(1, 3), 10); - var mins = parseInt(tz.slice(3, 5), 10); - tz = sign * (60 * hours) + mins; - } + if (tzType == 'string') { + var s = tz[0] === '-' ? -1 : 1; + var h = parseInt(tz.slice(1, 3), 10); + var m = parseInt(tz.slice(3, 5), 10); + + tz = s * (60 * h) + m; + } - if (tzType) { d = new Date(d.getTime() + (tz * 60000)); - } + opt.timezone = tz; } - // Most of the specifiers supported by C's strftime, and some from Ruby. - // Some other syntax extensions from Ruby are supported: %-, %_, and %0 - // to pad with nothing, space, or zero (respectively). - return fmt.replace(/%([-_0]?.)/g, function(_, c) { - var mod, padding; + return d; +} - if (c.length == 2) { - mod = c[0]; - // omit padding - if (mod == '-') { - padding = ''; - } - // pad with space - else if (mod == '_') { - padding = ' '; - } - // pad with zero - else if (mod == '0') { - padding = '0'; - } - else { - // unrecognized, return the format - return _; - } - c = c[1]; - } +namespace.strftime = strftime; - switch (c) { +namespace.strftimeTZ = strftime.strftimeTZ = function strfTimeTZ(fmt, d, locale, timeZone) { + var _locale = locale; + var _timeZone = timeZone; - // Examples for new Date(0) in GMT + if ((typeof locale === 'number' || typeof locale === 'string') && timeZone == null) { + _timeZone = locale; + _locale = undefined; + } - // 'Thursday' - case 'A': return locale.days[d.getDay()]; - - // 'Thu' - case 'a': return locale.shortDays[d.getDay()]; - - // 'January' - case 'B': return locale.months[d.getMonth()]; - - // 'Jan' - case 'b': return locale.shortMonths[d.getMonth()]; - - // '19' - case 'C': return pad(Math.floor(d.getFullYear() / 100), padding); - - // '01/01/70' - case 'D': return _strftime(locale.formats.D || '%m/%d/%y', d, locale); - - // '01' - case 'd': return pad(d.getDate(), padding); - - // '01' - case 'e': return d.getDate(); - - // '1970-01-01' - case 'F': return _strftime(locale.formats.F || '%Y-%m-%d', d, locale); - - // '00' - case 'H': return pad(d.getHours(), padding); - - // 'Jan' - case 'h': return locale.shortMonths[d.getMonth()]; - - // '12' - case 'I': return pad(hours12(d), padding); - - // '000' - case 'j': - var y = new Date(d.getFullYear(), 0, 1); - var day = Math.ceil((d.getTime() - y.getTime()) / (1000 * 60 * 60 * 24)); - return pad(day, 3); - - // ' 0' - case 'k': return pad(d.getHours(), padding == null ? ' ' : padding); - - // '000' - case 'L': return pad(Math.floor(timestamp % 1000), 3); - - // '12' - case 'l': return pad(hours12(d), padding == null ? ' ' : padding); - - // '00' - case 'M': return pad(d.getMinutes(), padding); - - // '01' - case 'm': return pad(d.getMonth() + 1, padding); - - // '\n' - case 'n': return '\n'; - - // '1st' - case 'o': return String(d.getDate()) + ordinal(d.getDate()); - - // 'am' - case 'P': return d.getHours() < 12 ? locale.am : locale.pm; - - // 'AM' - case 'p': return d.getHours() < 12 ? locale.AM : locale.PM; - - // '00:00' - case 'R': return _strftime(locale.formats.R || '%H:%M', d, locale); - - // '12:00:00 AM' - case 'r': return _strftime(locale.formats.r || '%I:%M:%S %p', d, locale); - - // '00' - case 'S': return pad(d.getSeconds(), padding); - - // '0' - case 's': return Math.floor(timestamp / 1000); - - // '00:00:00' - case 'T': return _strftime(locale.formats.T || '%H:%M:%S', d, locale); - - // '\t' - case 't': return '\t'; - - // '00' - case 'U': return pad(weekNumber(d, 'sunday'), padding); - - // '4' - case 'u': - var day = d.getDay(); - return day == 0 ? 7 : day; // 1 - 7, Monday is first day of the week - - // '1-Jan-1970' - case 'v': return _strftime(locale.formats.v || '%e-%b-%Y', d, locale); - - // '00' - case 'W': return pad(weekNumber(d, 'monday'), padding); - - // '4' - case 'w': return d.getDay(); // 0 - 6, Sunday is first day of the week - - // '1970' - case 'Y': return d.getFullYear(); - - // '70' - case 'y': - var y = String(d.getFullYear()); - return y.slice(y.length - 2); - - // 'GMT' - case 'Z': - if (options.utc) { - return "GMT"; - } - else { - var tzString = d.toString().match(/\((\w+)\)/); - return tzString && tzString[1] || ''; - } - - // '+0000' - case 'z': - if (options.utc) { - return "+0000"; - } - else { - var off = typeof tz == 'number' ? tz : -d.getTimezoneOffset(); - return (off < 0 ? '-' : '+') + pad(Math.abs(off / 60)) + pad(off % 60); - } - - default: return c; - } + return _strftime(fmt, d, _locale, { + timezone: _timeZone }); - } +}; - function dateToUTC(d) { - var msDelta = (d.getTimezoneOffset() || 0) * 60000; - return new Date(d.getTime() + msDelta); - } +namespace.strftimeUTC = strftime.strftimeUTC = function strftimeUTC(fmt, d, locale) { + return _strftime(fmt, d, locale, { + utc: true + }); +}; - var RequiredDateMethods = ['getTime', 'getTimezoneOffset', 'getDay', 'getDate', 'getMonth', 'getFullYear', 'getYear', 'getHours', 'getMinutes', 'getSeconds']; - function quacksLikeDate(x) { - var i = 0 - , n = RequiredDateMethods.length - ; - for (i = 0; i < n; ++i) { - if (typeof x[RequiredDateMethods[i]] != 'function') { - return false; - } - } - return true; - } - - // Default padding is '0' and default length is 2, both are optional. - function pad(n, padding, length) { - // pad(n, ) - if (typeof padding === 'number') { - length = padding; - padding = '0'; - } - - // Defaults handle pad(n) and pad(n, ) - if (padding == null) { - padding = '0'; - } - length = length || 2; - - var s = String(n); - // padding may be an empty string, don't loop forever if it is - if (padding) { - while (s.length < length) s = padding + s; - } - return s; - } - - function hours12(d) { - var hour = d.getHours(); - if (hour == 0) hour = 12; - else if (hour > 12) hour -= 12; - return hour; - } - - // Get the ordinal suffix for a number: st, nd, rd, or th - function ordinal(n) { - var i = n % 10 - , ii = n % 100 - ; - if ((ii >= 11 && ii <= 13) || i === 0 || i >= 4) { - return 'th'; - } - switch (i) { - case 1: return 'st'; - case 2: return 'nd'; - case 3: return 'rd'; - } - } - - // firstWeekday: 'sunday' or 'monday', default is 'sunday' - // - // Pilfered & ported from Ruby's strftime implementation. - function weekNumber(d, firstWeekday) { - firstWeekday = firstWeekday || 'sunday'; - - // This works by shifting the weekday back by one day if we - // are treating Monday as the first day of the week. - var wday = d.getDay(); - if (firstWeekday == 'monday') { - if (wday == 0) // Sunday - wday = 6; - else - wday--; - } - var firstDayOfYear = new Date(d.getFullYear(), 0, 1) - , yday = (d - firstDayOfYear) / 86400000 - , weekNum = (yday + 7 - wday) / 7 - ; - return Math.floor(weekNum); - } +namespace.localizedStrftime = strftime.localizedStrftime = function localizedStrftime(locale) { + return function (fmt, d, options) { + return _strftime(fmt, d, locale, options); + }; +}; }()); diff --git a/test/test.js b/test/test.js index 195187f..7f509ac 100755 --- a/test/test.js +++ b/test/test.js @@ -12,43 +12,43 @@ var assert = require('assert') , lib = require(libFilename) // Tue, 07 Jun 2011 18:51:45 GMT - , Time = new Date(1307472705067) + , Time = new Date(1307472705067); assert.fn = function(value, msg) { assert.equal('function', typeof value, msg) -} +}; assert.format = function(format, expected, expectedUTC, time) { - time = time || Time + time = time || Time; function _assertFmt(expected, name) { - name = name || 'strftime' - var actual = lib[name](format, time) + name = name || 'strftime'; + var actual = lib[name](format, time); assert.equal(expected, actual, name + '("' + format + '", ' + time + ') is ' + JSON.stringify(actual) + ', expected ' + JSON.stringify(expected)) } - if (expected) _assertFmt(expected, 'strftime') + if (expected) _assertFmt(expected, 'strftime'); _assertFmt(expectedUTC || expected, 'strftimeUTC') -} +}; /// check exports -assert.fn(lib.strftime) -assert.fn(lib.strftimeUTC) -assert.fn(lib.localizedStrftime) -ok('Exports') +assert.fn(lib.strftime); +assert.fn(lib.strftimeUTC); +assert.fn(lib.localizedStrftime); +ok('Exports'); /// time zones if (process.env.TZ == 'America/Vancouver') { - testTimezone('P[DS]T') - assert.format('%C', '01', '01', new Date(100, 0, 1)) - assert.format('%j', '097', '098', new Date(1365390736236)) + testTimezone('P[DS]T'); + assert.format('%C', '01', '01', new Date(100, 0, 1)); + assert.format('%j', '097', '098', new Date(1365390736236)); ok('Time zones (' + process.env.TZ + ')') } else if (process.env.TZ == 'CET') { - testTimezone('CES?T') - assert.format('%C', '01', '00', new Date(100, 0, 1)) - assert.format('%j', '098', '098', new Date(1365390736236)) + testTimezone('CES?T'); + assert.format('%C', '01', '00', new Date(100, 0, 1)); + assert.format('%j', '098', '098', new Date(1365390736236)); ok('Time zones (' + process.env.TZ + ')') } else { @@ -56,56 +56,56 @@ else { } /// check all formats in GMT, most coverage -assert.format('%A', 'Tuesday') -assert.format('%a', 'Tue') -assert.format('%B', 'June') -assert.format('%b', 'Jun') -assert.format('%C', '20') -assert.format('%D', '06/07/11') -assert.format('%d', '07') -assert.format('%-d', '7') -assert.format('%_d', ' 7') -assert.format('%0d', '07') -assert.format('%e', '7') -assert.format('%F', '2011-06-07') -assert.format('%H', null, '18') -assert.format('%h', 'Jun') -assert.format('%I', null, '06') -assert.format('%-I', null, '6') -assert.format('%_I', null, ' 6') -assert.format('%0I', null, '06') -assert.format('%j', null, '158') -assert.format('%k', null, '18') -assert.format('%L', '067') -assert.format('%l', null, ' 6') -assert.format('%-l', null, '6') -assert.format('%_l', null, ' 6') -assert.format('%0l', null, '06') -assert.format('%M', null, '51') -assert.format('%m', '06') -assert.format('%n', '\n') -assert.format('%o', '7th') -assert.format('%P', null, 'pm') -assert.format('%p', null, 'PM') -assert.format('%R', null, '18:51') -assert.format('%r', null, '06:51:45 PM') -assert.format('%S', '45') -assert.format('%s', '1307472705') -assert.format('%T', null, '18:51:45') -assert.format('%t', '\t') -assert.format('%U', '23') -assert.format('%U', '24', null, new Date(+Time + 5 * 86400000)) -assert.format('%u', '2') -assert.format('%v', '7-Jun-2011') -assert.format('%W', '23') -assert.format('%W', '23', null, new Date(+Time + 5 * 86400000)) -assert.format('%w', '2') -assert.format('%Y', '2011') -assert.format('%y', '11') -assert.format('%Z', null, 'GMT') -assert.format('%z', null, '+0000') -assert.format('%%', '%') // any other char -ok('GMT') +assert.format('%A', 'Tuesday'); +assert.format('%a', 'Tue'); +assert.format('%B', 'June'); +assert.format('%b', 'Jun'); +assert.format('%C', '20'); +assert.format('%D', '06/07/11'); +assert.format('%d', '07'); +assert.format('%-d', '7'); +assert.format('%_d', ' 7'); +assert.format('%0d', '07'); +assert.format('%e', '7'); +assert.format('%F', '2011-06-07'); +assert.format('%H', null, '18'); +assert.format('%h', 'Jun'); +assert.format('%I', null, '06'); +assert.format('%-I', null, '6'); +assert.format('%_I', null, ' 6'); +assert.format('%0I', null, '06'); +assert.format('%j', null, '158'); +assert.format('%k', null, '18'); +assert.format('%L', '067'); +assert.format('%l', null, ' 6'); +assert.format('%-l', null, '6'); +assert.format('%_l', null, ' 6'); +assert.format('%0l', null, '06'); +assert.format('%M', null, '51'); +assert.format('%m', '06'); +assert.format('%n', '\n'); +assert.format('%o', '7th'); +assert.format('%P', null, 'pm'); +assert.format('%p', null, 'PM'); +assert.format('%R', null, '18:51'); +assert.format('%r', null, '06:51:45 PM'); +assert.format('%S', '45'); +assert.format('%s', '1307472705'); +assert.format('%T', null, '18:51:45'); +assert.format('%t', '\t'); +assert.format('%U', '23'); +assert.format('%U', '24', null, new Date(+Time + 5 * 86400000)); +assert.format('%u', '2'); +assert.format('%v', '7-Jun-2011'); +assert.format('%W', '23'); +assert.format('%W', '23', null, new Date(+Time + 5 * 86400000)); +assert.format('%w', '2'); +assert.format('%Y', '2011'); +assert.format('%y', '11'); +assert.format('%Z', null, 'GMT'); +assert.format('%z', null, '+0000'); +assert.format('%%', '%'); // any other char +ok('GMT'); /// locales @@ -127,54 +127,54 @@ var it_IT = , T: 'it$%H:%M:%S' , v: 'it$%e-%b-%Y' } -} +}; assert.format_it = function(format, expected, expectedUTC) { function _assertFmt(expected, name) { - name = name || 'strftime' - var actual = lib[name](format, Time, it_IT) + name = name || 'strftime'; + var actual = lib[name](format, Time, it_IT); assert.equal(expected, actual, name + '("' + format + '", Time) is ' + JSON.stringify(actual) + ', expected ' + JSON.stringify(expected)) } - if (expected) _assertFmt(expected, 'strftime') + if (expected) _assertFmt(expected, 'strftime'); _assertFmt(expectedUTC || expected, 'strftimeUTC') -} +}; -assert.format_it('%A', 'martedi') -assert.format_it('%a', 'mar') -assert.format_it('%B', 'giugno') -assert.format_it('%b', 'giu') -assert.format_it('%D', 'it$06/07/11') -assert.format_it('%F', 'it$2011-06-07') -assert.format_it('%p', null, 'it$PM') -assert.format_it('%P', null, 'it$pm') -assert.format_it('%R', null, 'it$18:51') -assert.format_it('%r', null, 'it$06:51:45 it$PM') -assert.format_it('%T', null, 'it$18:51:45') -assert.format_it('%v', 'it$7-giu-2011') -ok('Localization') +assert.format_it('%A', 'martedi'); +assert.format_it('%a', 'mar'); +assert.format_it('%B', 'giugno'); +assert.format_it('%b', 'giu'); +assert.format_it('%D', 'it$06/07/11'); +assert.format_it('%F', 'it$2011-06-07'); +assert.format_it('%p', null, 'it$PM'); +assert.format_it('%P', null, 'it$pm'); +assert.format_it('%R', null, 'it$18:51'); +assert.format_it('%r', null, 'it$06:51:45 it$PM'); +assert.format_it('%T', null, 'it$18:51:45'); +assert.format_it('%v', 'it$7-giu-2011'); +ok('Localization'); /// timezones assert.formatTZ = function(format, expected, tz, time) { time = time || Time; - var actual = lib.strftimeTZ(format, time, tz) + var actual = lib.strftimeTZ(format, time, tz); assert.equal( expected, actual, ('strftime("' + format + '", ' + time + ') is ' + JSON.stringify(actual) + ', expected ' + JSON.stringify(expected)) ) -} +}; -assert.formatTZ('%F %r %z', '2011-06-07 06:51:45 PM +0000', 0) -assert.formatTZ('%F %r %z', '2011-06-07 06:51:45 PM +0000', '+0000') -assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', 120) -assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', '+0200') -assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', -420) -assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', '-0700') -ok('Time zone offset') +assert.formatTZ('%F %r %z', '2011-06-07 06:51:45 PM +0000', 0); +assert.formatTZ('%F %r %z', '2011-06-07 06:51:45 PM +0000', '+0000'); +assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', 120); +assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', '+0200'); +assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', -420); +assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', '-0700'); +ok('Time zone offset'); /// helpers @@ -187,8 +187,8 @@ function ok(s) { console.log('[ \033[32mOK\033[0m ] ' + s) } // Don't pass GMT! Every date includes it and it will fail. // Be careful if you pass a regex, it has to quack like the default one. function testTimezone(regex) { - regex = typeof regex === 'string' ? RegExp('\\((' + regex + ')\\)$') : regex - var match = Time.toString().match(regex) + regex = typeof regex === 'string' ? new RegExp('\\((' + regex + ')\\)$') : regex; + var match = Time.toString().match(regex); if (match) { var off = Time.getTimezoneOffset() , hourOff = off / 60 @@ -207,18 +207,18 @@ function testTimezone(regex) { , ampm = hour12 == hour24 ? 'AM' : 'PM' , R = hour24 + ':' + mins , r = padZero12 + hour12 + ':' + mins + ':45 ' + ampm - , T = R + ':45' - assert.format('%H', padZero24 + hour24, '18') - assert.format('%I', padZero12 + hour12, '06') - assert.format('%k', padSpace24 + hour24, '18') - assert.format('%l', padSpace12 + hour12, ' 6') - assert.format('%M', mins) - assert.format('%P', ampm.toLowerCase(), 'pm') - assert.format('%p', ampm, 'PM') - assert.format('%R', R, '18:51') - assert.format('%r', r, '06:51:45 PM') - assert.format('%T', T, '18:51:45') - assert.format('%Z', tz, 'GMT') + , T = R + ':45'; + assert.format('%H', padZero24 + hour24, '18'); + assert.format('%I', padZero12 + hour12, '06'); + assert.format('%k', padSpace24 + hour24, '18'); + assert.format('%l', padSpace12 + hour12, ' 6'); + assert.format('%M', mins); + assert.format('%P', ampm.toLowerCase(), 'pm'); + assert.format('%p', ampm, 'PM'); + assert.format('%R', R, '18:51'); + assert.format('%r', r, '06:51:45 PM'); + assert.format('%T', T, '18:51:45'); + assert.format('%Z', tz, 'GMT'); assert.format('%z', sign + '0' + Math.abs(hourDiff) + '00', '+0000') } }