diff --git a/lib/index.js b/lib/index.js index d448d8d..fc1f3ba 100644 --- a/lib/index.js +++ b/lib/index.js @@ -70,45 +70,68 @@ d = new Date(d.getTime() + msDelta); } - // Most of the specifiers supported by C's strftime, and one from Ruby (%L) - return fmt.replace(/%(.)/g, function(_, c) { + // 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; + 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]; + } switch (c) { case 'A': return locale.days[d.getDay()]; case 'a': return locale.shortDays[d.getDay()]; case 'B': return locale.months[d.getMonth()]; case 'b': return locale.shortMonths[d.getMonth()]; - case 'C': return pad(Math.floor(d.getFullYear() / 100)); + case 'C': return pad(Math.floor(d.getFullYear() / 100), padding); case 'D': return _strftime(locale.formats.D || '%m/%d/%y', d, locale); - case 'd': return pad(d.getDate()); + case 'd': return pad(d.getDate(), padding); case 'e': return d.getDate(); case 'F': return _strftime(locale.formats.F || '%Y-%m-%d', d, locale); - case 'H': return pad(d.getHours()); + case 'H': return pad(d.getHours(), padding); case 'h': return locale.shortMonths[d.getMonth()]; - case 'I': return pad(hours12(d)); + case 'I': return pad(hours12(d), padding); case 'j': var y=new Date(d.getFullYear(), 0, 1); var day = Math.ceil((d.getTime() - y.getTime()) / (1000*60*60*24)); return day; - case 'k': return pad(d.getHours(), ' '); + case 'k': return pad(d.getHours(), padding == null ? ' ' : padding); case 'L': return pad(Math.floor(d.getTime() % 1000), 3); - case 'l': return pad(hours12(d), ' '); - case 'M': return pad(d.getMinutes()); - case 'm': return pad(d.getMonth() + 1); + case 'l': return pad(hours12(d), padding == null ? ' ' : padding); + case 'M': return pad(d.getMinutes(), padding); + case 'm': return pad(d.getMonth() + 1, padding); case 'n': return '\n'; case 'P': return d.getHours() < 12 ? locale.am : locale.pm; case 'p': return d.getHours() < 12 ? locale.AM : locale.PM; case 'R': return _strftime(locale.formats.R || '%H:%M', d, locale); case 'r': return _strftime(locale.formats.r || '%I:%M:%S %p', d, locale); - case 'S': return pad(d.getSeconds()); + case 'S': return pad(d.getSeconds(), padding); case 's': return Math.floor((d.getTime() - msDelta) / 1000); case 'T': return _strftime(locale.formats.T || '%H:%M:%S', d, locale); case 't': return '\t'; - case 'U': return pad(weekNumber(d, 'sunday')); + case 'U': return pad(weekNumber(d, 'sunday'), padding); case 'u': var day = d.getDay(); return day == 0 ? 7 : day; // 1 - 7, Monday is first day of the week case 'v': return _strftime(locale.formats.v || '%e-%b-%Y', d, locale); - case 'W': return pad(weekNumber(d, 'monday')); + case 'W': return pad(weekNumber(d, 'monday'), padding); case 'w': return d.getDay(); // 0 - 6, Sunday is first day of the week case 'Y': return d.getFullYear(); case 'y': @@ -157,11 +180,16 @@ } // Defaults handle pad(n) and pad(n, ) - padding = padding || '0'; + if (padding == null) { + padding = '0'; + } length = length || 2; var s = String(n); - while (s.length < length) s = padding + s; + // padding may be an empty string, don't loop forever if it is + if (padding) { + while (s.length < length) s = padding + s; + } return s; } diff --git a/test/test.js b/test/test.js index 2f6478f..b2602cc 100755 --- a/test/test.js +++ b/test/test.js @@ -60,15 +60,24 @@ 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')