add support for passing in timezones

This commit is contained in:
Sami Samhuri 2013-10-14 18:43:00 -07:00
parent 6912b47d59
commit 1633e4007c
3 changed files with 78 additions and 27 deletions

View file

@ -46,6 +46,13 @@ And if you don't want to pass a localization object every time you can get a loc
console.log(strftime_IT('%B %d, %y %H:%M:%S')) // aprile 28, 2011 18:21:08 console.log(strftime_IT('%B %d, %y %H:%M:%S')) // aprile 28, 2011 18:21:08
Time zones can be passed in as an offset from GMT in minutes.
var strftimeTZ = require('strftime').strftimeTZ
console.log(strftimeTZ('%B %d, %y %H:%M:%S', new Date(1307472705067), -420)) // => June 07, 11 11:51:45
console.log(strftimeTZ('%F %T', new Date(1307472705067), 120)) // => 2011-06-07 11:51:45
Supported Specifiers Supported Specifiers
==================== ====================

View file

@ -11,7 +11,7 @@
;(function() { ;(function() {
//// Export the API //// Where to export the API
var namespace; var namespace;
// CommonJS / Node module // CommonJS / Node module
@ -25,12 +25,6 @@
namespace = (function(){ return this || (1,eval)('this') }()); namespace = (function(){ return this || (1,eval)('this') }());
} }
namespace.strftime = strftime;
namespace.strftimeUTC = strftime.strftimeUTC = strftimeUTC;
namespace.localizedStrftime = strftime.localizedStrftime = localizedStrftime;
////
function words(s) { return (s || '').split(' '); } function words(s) { return (s || '').split(' '); }
var DefaultLocale = var DefaultLocale =
@ -44,34 +38,62 @@
, pm: 'pm' , pm: 'pm'
}; };
namespace.strftime = strftime;
function strftime(fmt, d, locale) { function strftime(fmt, d, locale) {
return _strftime(fmt, d, locale, false); return _strftime(fmt, d, locale);
} }
// locale is optional
namespace.strftimeTZ = strftime.strftimeTZ = strftimeTZ;
function strftimeTZ(fmt, d, locale, timezone) {
if (typeof locale == 'number' && timezone == null) {
timezone = locale;
locale = undefined;
}
return _strftime(fmt, d, locale, { timezone: timezone });
}
namespace.strftimeUTC = strftime.strftimeUTC = strftimeUTC;
function strftimeUTC(fmt, d, locale) { function strftimeUTC(fmt, d, locale) {
return _strftime(fmt, d, locale, true); return _strftime(fmt, d, locale, { utc: true });
} }
namespace.localizedStrftime = strftime.localizedStrftime = localizedStrftime;
function localizedStrftime(locale) { function localizedStrftime(locale) {
return function(fmt, d) { return function(fmt, d, options) {
return strftime(fmt, d, locale); return strftime(fmt, d, locale, options);
}; };
} }
// locale is an object with the same structure as DefaultLocale // d, locale, and options are optional, but you can't leave
function _strftime(fmt, d, locale, _useUTC) { // 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 // d and locale are optional so check if d is really the locale
if (d && !quacksLikeDate(d)) { if (d && !quacksLikeDate(d)) {
locale = d; locale = d;
d = undefined; d = undefined;
} }
d = d || new Date(); d = d || new Date();
locale = locale || DefaultLocale; locale = locale || DefaultLocale;
locale.formats = locale.formats || {}; locale.formats = locale.formats || {};
var msDelta = 0;
if (_useUTC) { // Hang on to this Unix timestamp because we might mess with it directly below.
msDelta = (d.getTimezoneOffset() || 0) * 60000; var timestamp = d.getTime();
d = new Date(d.getTime() + msDelta);
if (options.utc || typeof options.timezone == 'number') {
d = dateToUTC(d);
}
if (typeof options.timezone == 'number') {
d = new Date(d.getTime() + (options.timezone * 60000));
} }
// Most of the specifiers supported by C's strftime, and some from Ruby. // Most of the specifiers supported by C's strftime, and some from Ruby.
@ -117,7 +139,7 @@
var day = Math.ceil((d.getTime() - y.getTime()) / (1000 * 60 * 60 * 24)); var day = Math.ceil((d.getTime() - y.getTime()) / (1000 * 60 * 60 * 24));
return pad(day, 3); return pad(day, 3);
case 'k': return pad(d.getHours(), padding == null ? ' ' : padding); case 'k': return pad(d.getHours(), padding == null ? ' ' : padding);
case 'L': return pad(Math.floor(d.getTime() % 1000), 3); case 'L': return pad(Math.floor(timestamp % 1000), 3);
case 'l': return pad(hours12(d), padding == null ? ' ' : padding); case 'l': return pad(hours12(d), padding == null ? ' ' : padding);
case 'M': return pad(d.getMinutes(), padding); case 'M': return pad(d.getMinutes(), padding);
case 'm': return pad(d.getMonth() + 1, padding); case 'm': return pad(d.getMonth() + 1, padding);
@ -128,7 +150,7 @@
case 'R': return _strftime(locale.formats.R || '%H:%M', d, locale); 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 'r': return _strftime(locale.formats.r || '%I:%M:%S %p', d, locale);
case 'S': return pad(d.getSeconds(), padding); case 'S': return pad(d.getSeconds(), padding);
case 's': return Math.floor((d.getTime() - msDelta) / 1000); case 's': return Math.floor(timestamp / 1000);
case 'T': return _strftime(locale.formats.T || '%H:%M:%S', d, locale); case 'T': return _strftime(locale.formats.T || '%H:%M:%S', d, locale);
case 't': return '\t'; case 't': return '\t';
case 'U': return pad(weekNumber(d, 'sunday'), padding); case 'U': return pad(weekNumber(d, 'sunday'), padding);
@ -143,7 +165,7 @@
var y = String(d.getFullYear()); var y = String(d.getFullYear());
return y.slice(y.length - 2); return y.slice(y.length - 2);
case 'Z': case 'Z':
if (_useUTC) { if (options.utc) {
return "GMT"; return "GMT";
} }
else { else {
@ -151,18 +173,23 @@
return tz && tz[1] || ''; return tz && tz[1] || '';
} }
case 'z': case 'z':
if (_useUTC) { if (options.utc) {
return "+0000"; return "+0000";
} }
else { else {
var off = d.getTimezoneOffset(); var off = typeof options.timezone == 'number' ? options.timezone : -d.getTimezoneOffset();
return (off < 0 ? '+' : '-') + pad(Math.abs(off / 60)) + pad(off % 60); return (off < 0 ? '-' : '+') + pad(Math.abs(off / 60)) + pad(off % 60);
} }
default: return c; default: return c;
} }
}); });
} }
function dateToUTC(d) {
var msDelta = (d.getTimezoneOffset() || 0) * 60000;
return new Date(d.getTime() + msDelta);
}
var RequiredDateMethods = ['getTime', 'getTimezoneOffset', 'getDay', 'getDate', 'getMonth', 'getFullYear', 'getYear', 'getHours', 'getMinutes', 'getSeconds']; var RequiredDateMethods = ['getTime', 'getTimezoneOffset', 'getDay', 'getDate', 'getMonth', 'getFullYear', 'getYear', 'getHours', 'getMinutes', 'getSeconds'];
function quacksLikeDate(x) { function quacksLikeDate(x) {
var i = 0 var i = 0

View file

@ -28,7 +28,7 @@ assert.format = function(format, expected, expectedUTC, time) {
+ ', expected ' + JSON.stringify(expected)) + ', expected ' + JSON.stringify(expected))
} }
if (expected) _assertFmt(expected) if (expected) _assertFmt(expected, 'strftime')
_assertFmt(expectedUTC || expected, 'strftimeUTC') _assertFmt(expectedUTC || expected, 'strftimeUTC')
} }
@ -138,7 +138,7 @@ assert.format_it = function(format, expected, expectedUTC) {
+ ', expected ' + JSON.stringify(expected)) + ', expected ' + JSON.stringify(expected))
} }
if (expected) _assertFmt(expected) if (expected) _assertFmt(expected, 'strftime')
_assertFmt(expectedUTC || expected, 'strftimeUTC') _assertFmt(expectedUTC || expected, 'strftimeUTC')
} }
@ -157,6 +157,23 @@ assert.format_it('%v', 'it$7-giu-2011')
ok('Localization') ok('Localization')
/// timezones
assert.formatTZ = function(format, expected, tz, time) {
time = time || Time;
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 08:51:45 PM +0200', 120)
assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', -420)
ok('Time zone offset')
/// helpers /// helpers
function words(s) { return (s || '').split(' '); } function words(s) { return (s || '').split(' '); }