Improved time formatting and conversion

Bunyan CLI was not handling timezone conversion properly when set to use
local time. This patch uses [Moment.js][] to fix those issues.

 * Timezone conversions work properly across DST conversions
 * The timezone, when shown, is correctly shown as `±hh:mm`
 * The timzeone is omitted on short output, since it isn't that short.
   Except when UTC is used, since that can be indicated by the single
   character `Z`

Fixes #245

 [Moment.js]: http://momentjs.com/
This commit is contained in:
David M. Lee 2015-10-15 22:17:53 -04:00 committed by Trent Mick
parent c1662212f8
commit 8df86bccf0
4 changed files with 70 additions and 14 deletions

View file

@ -18,7 +18,8 @@ ifeq ($(shell uname -s),Darwin)
endif endif
NODEOPT ?= $(HOME)/opt NODEOPT ?= $(HOME)/opt
# Run tests in a set timezone, so local time is predictable
export TZ=Pacific/Honolulu
#---- Files #---- Files

View file

@ -25,6 +25,7 @@ var child_process = require('child_process'),
exec = child_process.exec, exec = child_process.exec,
execFile = child_process.execFile; execFile = child_process.execFile;
var assert = require('assert'); var assert = require('assert');
var moment = require('moment');
var nodeSpawnSupportsStdio = ( var nodeSpawnSupportsStdio = (
Number(process.version.split('.')[0]) >= 0 || Number(process.version.split('.')[0]) >= 0 ||
@ -87,6 +88,16 @@ Object.keys(levelFromName).forEach(function (name) {
TIME_UTC = 1; // the default, bunyan's native format TIME_UTC = 1; // the default, bunyan's native format
TIME_LOCAL = 2; TIME_LOCAL = 2;
// Timestamp formats. Timezone is added at format time
UTC_FORMATS = {
long: 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]',
short: 'HH:mm:ss.SSS[Z]'
};
LOCAL_FORMATS = {
long: 'YYYY-MM-DD[T]HH:mm:ss.SSSZ',
short: 'HH:mm:ss.SSS'
};
var timezoneOffsetMs; // used for TIME_LOCAL display var timezoneOffsetMs; // used for TIME_LOCAL display
@ -752,25 +763,26 @@ function emitRecord(rec, line, opts, stylize) {
delete rec.v; delete rec.v;
var time = rec.time; var time = moment(rec.time);
// default to UTC
var zoneFormats;
switch (opts.timeFormat) { switch (opts.timeFormat) {
case TIME_UTC:
break;
case TIME_LOCAL: case TIME_LOCAL:
if (!timezoneOffsetMs) { zoneFormats = LOCAL_FORMATS;
timezoneOffsetMs break;
= (new Date(time)).getTimezoneOffset() * 60 * 1000; default:
} // default to UTC
time = new Date( zoneFormats = UTC_FORMATS;
(new Date(time)).getTime() - timezoneOffsetMs).toISOString() time.utc();
break; break;
} }
if (short && rec.time[10] === 'T') { if (short) {
// Presuming `time` is ISO8601 formatted, i.e. safe to drop date. time = time.format(zoneFormats.short);
time = stylize(time.substr(11), 'XXX');
} else { } else {
time = stylize('[' + time + ']', 'XXX'); // Is there any way to put square brackets in a moment format?
time = '[' + time.format(zoneFormats.long) + ']';
} }
time = stylize(time, 'XXX');
delete rec.time; delete rec.time;
var nameStr = rec.name; var nameStr = rec.name;

View file

@ -32,5 +32,8 @@
"scripts": { "scripts": {
"test": "make test" "test": "make test"
},
"dependencies": {
"moment": "^2.10.6"
} }
} }

View file

@ -86,6 +86,46 @@ test('cat simple.log', function (t) {
} }
); );
}); });
test('simple.log local long', function (t) {
exec(_('%s -o long -L %s/corpus/simple.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout,
'[2012-02-08T12:56:52.856-10:00] INFO: myservice/123 on example.com: '
+ 'My message\n');
t.end();
});
});
test('simple.log utc long', function (t) {
exec(_('%s -o long %s/corpus/simple.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout,
'[2012-02-08T22:56:52.856Z] INFO: myservice/123 on example.com: '
+ 'My message\n');
t.end();
});
});
test('simple.log local short', function (t) {
exec(_('%s -o short -L %s/corpus/simple.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout,
'12:56:52.856 INFO myservice: '
+ 'My message\n');
t.end();
});
});
test('simple.log utc short', function (t) {
exec(_('%s -o short %s/corpus/simple.log', BUNYAN, __dirname),
function (err, stdout, stderr) {
t.ifError(err)
t.equal(stdout,
'22:56:52.856Z INFO myservice: '
+ 'My message\n');
t.end();
});
});
test('simple.log with color', function (t) { test('simple.log with color', function (t) {
exec(_('%s --color %s/corpus/simple.log', BUNYAN, __dirname), exec(_('%s --color %s/corpus/simple.log', BUNYAN, __dirname),
function (err, stdout, stderr) { function (err, stdout, stderr) {