date-format 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +48 -24
- package/package.json +1 -1
- package/test/date_format-test.js +4 -7
- package/test/parse-test.js +105 -62
package/lib/index.js
CHANGED
@@ -30,10 +30,6 @@ function offset(timezoneOffset) {
|
|
30
30
|
return timezoneOffset < 0 ? "+" + h + m : "-" + h + m;
|
31
31
|
}
|
32
32
|
|
33
|
-
function datePart(date, displayUTC, part) {
|
34
|
-
return displayUTC ? date["getUTC" + part]() : date["get" + part]();
|
35
|
-
}
|
36
|
-
|
37
33
|
function asString(format, date) {
|
38
34
|
if (typeof format !== "string") {
|
39
35
|
date = format;
|
@@ -43,20 +39,19 @@ function asString(format, date) {
|
|
43
39
|
date = module.exports.now();
|
44
40
|
}
|
45
41
|
|
46
|
-
|
42
|
+
// Issue # 14 - Per ISO8601 standard, the time string should be local time
|
43
|
+
// with timezone info.
|
44
|
+
// See https://en.wikipedia.org/wiki/ISO_8601 section "Time offsets from UTC"
|
47
45
|
|
48
|
-
var vDay = addZero(
|
49
|
-
var vMonth = addZero(
|
50
|
-
var vYearLong = addZero(
|
46
|
+
var vDay = addZero(date.getDate());
|
47
|
+
var vMonth = addZero(date.getMonth() + 1);
|
48
|
+
var vYearLong = addZero(date.getFullYear());
|
51
49
|
var vYearShort = addZero(vYearLong.substring(2, 4));
|
52
50
|
var vYear = format.indexOf("yyyy") > -1 ? vYearLong : vYearShort;
|
53
|
-
var vHour = addZero(
|
54
|
-
var vMinute = addZero(
|
55
|
-
var vSecond = addZero(
|
56
|
-
var vMillisecond = padWithZeros(
|
57
|
-
datePart(date, displayUTC, "Milliseconds"),
|
58
|
-
3
|
59
|
-
);
|
51
|
+
var vHour = addZero(date.getHours());
|
52
|
+
var vMinute = addZero(date.getMinutes());
|
53
|
+
var vSecond = addZero(date.getSeconds());
|
54
|
+
var vMillisecond = padWithZeros(date.getMilliseconds(), 3);
|
60
55
|
var vTimeZone = offset(date.getTimezoneOffset());
|
61
56
|
var formatted = format
|
62
57
|
.replace(/dd/g, vDay)
|
@@ -70,55 +65,63 @@ function asString(format, date) {
|
|
70
65
|
return formatted;
|
71
66
|
}
|
72
67
|
|
68
|
+
function setDatePart(date, part, value, local) {
|
69
|
+
date['set' + (local ? '' : 'UTC') + part](value);
|
70
|
+
}
|
71
|
+
|
73
72
|
function extractDateParts(pattern, str, missingValuesDate) {
|
73
|
+
// Javascript Date object doesn't support custom timezone. Sets all felds as
|
74
|
+
// GMT based to begin with. If the timezone offset is provided, then adjust
|
75
|
+
// it using provided timezone, otherwise, adjust it with the system timezone.
|
76
|
+
var local = pattern.indexOf('O') < 0;
|
74
77
|
var matchers = [
|
75
78
|
{
|
76
79
|
pattern: /y{1,4}/,
|
77
80
|
regexp: "\\d{1,4}",
|
78
81
|
fn: function(date, value) {
|
79
|
-
date
|
82
|
+
setDatePart(date, 'FullYear', value, local);
|
80
83
|
}
|
81
84
|
},
|
82
85
|
{
|
83
86
|
pattern: /MM/,
|
84
87
|
regexp: "\\d{1,2}",
|
85
88
|
fn: function(date, value) {
|
86
|
-
date
|
89
|
+
setDatePart(date, 'Month', (value - 1), local);
|
87
90
|
}
|
88
91
|
},
|
89
92
|
{
|
90
93
|
pattern: /dd/,
|
91
94
|
regexp: "\\d{1,2}",
|
92
95
|
fn: function(date, value) {
|
93
|
-
date
|
96
|
+
setDatePart(date, 'Date', value, local);
|
94
97
|
}
|
95
98
|
},
|
96
99
|
{
|
97
100
|
pattern: /hh/,
|
98
101
|
regexp: "\\d{1,2}",
|
99
102
|
fn: function(date, value) {
|
100
|
-
date
|
103
|
+
setDatePart(date, 'Hours', value, local);
|
101
104
|
}
|
102
105
|
},
|
103
106
|
{
|
104
107
|
pattern: /mm/,
|
105
108
|
regexp: "\\d\\d",
|
106
109
|
fn: function(date, value) {
|
107
|
-
date
|
110
|
+
setDatePart(date, 'Minutes', value, local);
|
108
111
|
}
|
109
112
|
},
|
110
113
|
{
|
111
114
|
pattern: /ss/,
|
112
115
|
regexp: "\\d\\d",
|
113
116
|
fn: function(date, value) {
|
114
|
-
date
|
117
|
+
setDatePart(date, 'Seconds', value, local);
|
115
118
|
}
|
116
119
|
},
|
117
120
|
{
|
118
121
|
pattern: /SSS/,
|
119
122
|
regexp: "\\d\\d\\d",
|
120
123
|
fn: function(date, value) {
|
121
|
-
date
|
124
|
+
setDatePart(date, 'Milliseconds', value, local);
|
122
125
|
}
|
123
126
|
},
|
124
127
|
{
|
@@ -129,8 +132,28 @@ function extractDateParts(pattern, str, missingValuesDate) {
|
|
129
132
|
value = 0;
|
130
133
|
}
|
131
134
|
var offset = Math.abs(value);
|
132
|
-
var
|
133
|
-
|
135
|
+
var timezoneOffset = (value > 0 ? -1 : 1 ) * ((offset % 100) + Math.floor(offset / 100) * 60);
|
136
|
+
// Per ISO8601 standard: UTC = local time - offset
|
137
|
+
//
|
138
|
+
// For example, 2000-01-01T01:00:00-0700
|
139
|
+
// local time: 2000-01-01T01:00:00
|
140
|
+
// ==> UTC : 2000-01-01T08:00:00 ( 01 - (-7) = 8 )
|
141
|
+
//
|
142
|
+
// To make it even more confusing, the date.getTimezoneOffset() is
|
143
|
+
// opposite sign of offset string in the ISO8601 standard. So if offset
|
144
|
+
// is '-0700' the getTimezoneOffset() would be (+)420. The line above
|
145
|
+
// calculates timezoneOffset to matche Javascript's behavior.
|
146
|
+
//
|
147
|
+
// The date/time of the input is actually the local time, so the date
|
148
|
+
// object that was constructed is actually local time even thought the
|
149
|
+
// UTC setters are used. This means the date object's internal UTC
|
150
|
+
// representation was wrong. It needs to be fixed by substracting the
|
151
|
+
// offset (or adding the offset minutes as they are opposite sign).
|
152
|
+
//
|
153
|
+
// Note: the time zone has to be processed after all other fileds are
|
154
|
+
// set. The result would be incorrect if the offset was calculated
|
155
|
+
// first then overriden by the other filed setters.
|
156
|
+
date.setUTCMinutes(date.getUTCMinutes() + timezoneOffset);
|
134
157
|
}
|
135
158
|
}
|
136
159
|
];
|
@@ -162,6 +185,7 @@ function extractDateParts(pattern, str, missingValuesDate) {
|
|
162
185
|
dateFns.forEach(function(f, i) {
|
163
186
|
f.fn(date, matches[i + 1]);
|
164
187
|
});
|
188
|
+
|
165
189
|
return date;
|
166
190
|
}
|
167
191
|
|
package/package.json
CHANGED
package/test/date_format-test.js
CHANGED
@@ -29,23 +29,21 @@ describe('date_format', function() {
|
|
29
29
|
|
30
30
|
it('should provide a ISO8601 with timezone offset format', function() {
|
31
31
|
var tzDate = createFixedDate();
|
32
|
-
tzDate.setMinutes(tzDate.getMinutes() - tzDate.getTimezoneOffset() - 660);
|
33
32
|
tzDate.getTimezoneOffset = function () {
|
34
33
|
return -660;
|
35
34
|
};
|
36
35
|
|
37
|
-
// when tz offset is in the pattern, the date should be in
|
36
|
+
// when tz offset is in the pattern, the date should be in local time
|
38
37
|
dateFormat.asString(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, tzDate)
|
39
|
-
.should.eql('2010-01-
|
38
|
+
.should.eql('2010-01-11T14:31:30.005+1100');
|
40
39
|
|
41
40
|
tzDate = createFixedDate();
|
42
|
-
tzDate.setMinutes((tzDate.getMinutes() - tzDate.getTimezoneOffset()) + 120);
|
43
41
|
tzDate.getTimezoneOffset = function () {
|
44
42
|
return 120;
|
45
43
|
};
|
46
44
|
|
47
45
|
dateFormat.asString(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, tzDate)
|
48
|
-
.should.eql('2010-01-
|
46
|
+
.should.eql('2010-01-11T14:31:30.005-0200');
|
49
47
|
});
|
50
48
|
|
51
49
|
it('should provide a just-the-time format', function() {
|
@@ -54,11 +52,10 @@ describe('date_format', function() {
|
|
54
52
|
|
55
53
|
it('should provide a custom format', function() {
|
56
54
|
var customDate = createFixedDate();
|
57
|
-
customDate.setMinutes((customDate.getMinutes() - customDate.getTimezoneOffset()) + 120);
|
58
55
|
customDate.getTimezoneOffset = function () {
|
59
56
|
return 120;
|
60
57
|
};
|
61
58
|
|
62
|
-
dateFormat.asString('O.SSS.ss.mm.hh.dd.MM.yy', customDate).should.eql('-0200.005.30.31.
|
59
|
+
dateFormat.asString('O.SSS.ss.mm.hh.dd.MM.yy', customDate).should.eql('-0200.005.30.31.14.11.01.10');
|
63
60
|
});
|
64
61
|
});
|
package/test/parse-test.js
CHANGED
@@ -33,21 +33,19 @@ describe("dateFormat.parse", function() {
|
|
33
33
|
|
34
34
|
it("should return the correct date if the string matches", function() {
|
35
35
|
var testDate = new Date();
|
36
|
-
testDate.
|
37
|
-
testDate.
|
38
|
-
testDate.
|
39
|
-
testDate.
|
40
|
-
testDate.
|
41
|
-
testDate.
|
42
|
-
testDate.
|
43
|
-
testDate.getTimezoneOffset = function() {
|
44
|
-
return 600;
|
45
|
-
};
|
36
|
+
testDate.setUTCFullYear(2018);
|
37
|
+
testDate.setUTCMonth(8);
|
38
|
+
testDate.setUTCDate(13);
|
39
|
+
testDate.setUTCHours(18);
|
40
|
+
testDate.setUTCMinutes(10);
|
41
|
+
testDate.setUTCSeconds(12);
|
42
|
+
testDate.setUTCMilliseconds(392);
|
46
43
|
|
47
44
|
dateFormat
|
48
|
-
.parse(pattern, "2018-09-
|
45
|
+
.parse(pattern, "2018-09-14 04:10:12.392+1000")
|
49
46
|
.getTime()
|
50
|
-
.should.eql(testDate.getTime())
|
47
|
+
.should.eql(testDate.getTime())
|
48
|
+
;
|
51
49
|
});
|
52
50
|
|
53
51
|
it("should throw if the string does not match", function() {
|
@@ -65,7 +63,10 @@ describe("dateFormat.parse", function() {
|
|
65
63
|
return testDate;
|
66
64
|
};
|
67
65
|
|
68
|
-
|
66
|
+
/**
|
67
|
+
* If there's no timezone in the format, then we verify against the local date
|
68
|
+
*/
|
69
|
+
function verifyLocalDate(actual, expected) {
|
69
70
|
actual.getFullYear().should.eql(expected.year || testDate.getFullYear());
|
70
71
|
actual.getMonth().should.eql(expected.month || testDate.getMonth());
|
71
72
|
actual.getDate().should.eql(expected.day || testDate.getDate());
|
@@ -77,19 +78,34 @@ describe("dateFormat.parse", function() {
|
|
77
78
|
.should.eql(expected.milliseconds || testDate.getMilliseconds());
|
78
79
|
}
|
79
80
|
|
81
|
+
/**
|
82
|
+
* If a timezone is specified, let's verify against the UTC time it is supposed to be
|
83
|
+
*/
|
84
|
+
function verifyDate(actual, expected) {
|
85
|
+
actual.getUTCFullYear().should.eql(expected.year || testDate.getUTCFullYear());
|
86
|
+
actual.getUTCMonth().should.eql(expected.month || testDate.getUTCMonth());
|
87
|
+
actual.getUTCDate().should.eql(expected.day || testDate.getUTCDate());
|
88
|
+
actual.getUTCHours().should.eql(expected.hours || testDate.getUTCHours());
|
89
|
+
actual.getUTCMinutes().should.eql(expected.minutes || testDate.getUTCMinutes());
|
90
|
+
actual.getUTCSeconds().should.eql(expected.seconds || testDate.getUTCSeconds());
|
91
|
+
actual
|
92
|
+
.getMilliseconds()
|
93
|
+
.should.eql(expected.milliseconds || testDate.getMilliseconds());
|
94
|
+
}
|
95
|
+
|
80
96
|
it("should return a date with missing values defaulting to current time", function() {
|
81
97
|
var date = dateFormat.parse("yyyy-MM", "2015-09");
|
82
|
-
|
98
|
+
verifyLocalDate(date, { year: 2015, month: 8 });
|
83
99
|
});
|
84
100
|
|
85
101
|
it("should use a passed in date for missing values", function() {
|
86
|
-
var missingValueDate = new Date(2010, 1,
|
102
|
+
var missingValueDate = new Date(2010, 1, 8, 22, 30, 12, 100);
|
87
103
|
var date = dateFormat.parse("yyyy-MM", "2015-09", missingValueDate);
|
88
|
-
|
104
|
+
verifyLocalDate(date, {
|
89
105
|
year: 2015,
|
90
106
|
month: 8,
|
91
|
-
day:
|
92
|
-
hours:
|
107
|
+
day: 8,
|
108
|
+
hours: 22,
|
93
109
|
minutes: 30,
|
94
110
|
seconds: 12,
|
95
111
|
milliseconds: 100
|
@@ -98,80 +114,107 @@ describe("dateFormat.parse", function() {
|
|
98
114
|
|
99
115
|
it("should handle variations on the same pattern", function() {
|
100
116
|
var date = dateFormat.parse("MM-yyyy", "09-2015");
|
101
|
-
|
117
|
+
verifyLocalDate(date, { year: 2015, month: 8 });
|
102
118
|
|
103
119
|
date = dateFormat.parse("yyyy MM", "2015 09");
|
104
|
-
|
120
|
+
verifyLocalDate(date, { year: 2015, month: 8 });
|
105
121
|
|
106
122
|
date = dateFormat.parse("MM, yyyy.", "09, 2015.");
|
107
|
-
|
123
|
+
verifyLocalDate(date, { year: 2015, month: 8 });
|
108
124
|
});
|
109
125
|
|
110
|
-
|
111
|
-
|
112
|
-
|
126
|
+
describe("should match all the date parts", function() {
|
127
|
+
it("works with dd", function() {
|
128
|
+
var date = dateFormat.parse("dd", "21");
|
129
|
+
verifyLocalDate(date, { day: 21 });
|
130
|
+
});
|
113
131
|
|
114
|
-
|
115
|
-
|
132
|
+
it("works with hh", function() {
|
133
|
+
var date = dateFormat.parse("hh", "12");
|
134
|
+
verifyLocalDate(date, { hours: 12 });
|
135
|
+
});
|
116
136
|
|
117
|
-
|
118
|
-
|
137
|
+
it("works with mm", function() {
|
138
|
+
var date = dateFormat.parse("mm", "34");
|
139
|
+
verifyLocalDate(date, { minutes: 34 });
|
140
|
+
});
|
119
141
|
|
120
|
-
|
121
|
-
|
142
|
+
it("works with ss", function() {
|
143
|
+
var date = dateFormat.parse("ss", "59");
|
144
|
+
verifyLocalDate(date, { seconds: 59 });
|
145
|
+
});
|
122
146
|
|
123
|
-
|
124
|
-
|
147
|
+
it("works with ss.SSS", function() {
|
148
|
+
var date = dateFormat.parse("ss.SSS", "23.452");
|
149
|
+
verifyLocalDate(date, { seconds: 23, milliseconds: 452 });
|
150
|
+
});
|
125
151
|
|
126
|
-
|
127
|
-
|
152
|
+
it("works with hh:mm O (+1000)", function() {
|
153
|
+
var date = dateFormat.parse("hh:mm O", "05:23 +1000");
|
154
|
+
verifyDate(date, { hours: 19, minutes: 23 });
|
155
|
+
});
|
128
156
|
|
129
|
-
|
130
|
-
|
157
|
+
it("works with hh:mm O (-200)", function() {
|
158
|
+
var date = dateFormat.parse("hh:mm O", "05:23 -200");
|
159
|
+
verifyDate(date, { hours: 7, minutes: 23 });
|
160
|
+
});
|
131
161
|
|
132
|
-
|
133
|
-
|
162
|
+
it("works with hh:mm O (+0930)", function() {
|
163
|
+
var date = dateFormat.parse("hh:mm O", "05:23 +0930");
|
164
|
+
verifyDate(date, { hours: 19, minutes: 53 });
|
165
|
+
});
|
134
166
|
});
|
135
167
|
});
|
136
168
|
|
137
169
|
describe("with a date formatted by this library", function() {
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
170
|
+
describe("should format and then parse back to the same date", function() {
|
171
|
+
function testDateInitWithUTC() {
|
172
|
+
var td = new Date();
|
173
|
+
td.setUTCFullYear(2018);
|
174
|
+
td.setUTCMonth(8);
|
175
|
+
td.setUTCDate(13);
|
176
|
+
td.setUTCHours(18);
|
177
|
+
td.setUTCMinutes(10);
|
178
|
+
td.setUTCSeconds(12);
|
179
|
+
td.setUTCMilliseconds(392);
|
180
|
+
return td;
|
181
|
+
}
|
182
|
+
|
183
|
+
it("works with ISO8601_WITH_TZ_OFFSET_FORMAT", function() {
|
184
|
+
// For this test case to work, the date object must be initialized with
|
185
|
+
// UTC timezone
|
186
|
+
var td = testDateInitWithUTC();
|
187
|
+
var d = dateFormat(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, td);
|
188
|
+
dateFormat.parse(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, d)
|
189
|
+
.should.eql(td);
|
190
|
+
});
|
154
191
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
)
|
160
|
-
|
192
|
+
it("works with ISO8601_FORMAT", function() {
|
193
|
+
var td = new Date();
|
194
|
+
var d = dateFormat(dateFormat.ISO8601_FORMAT, td);
|
195
|
+
var actual = dateFormat.parse(dateFormat.ISO8601_FORMAT, d);
|
196
|
+
actual.should.eql(td);
|
197
|
+
});
|
161
198
|
|
162
|
-
|
199
|
+
it("works with DATETIME_FORMAT", function() {
|
200
|
+
var testDate = new Date();
|
201
|
+
dateFormat
|
163
202
|
.parse(
|
164
203
|
dateFormat.DATETIME_FORMAT,
|
165
204
|
dateFormat(dateFormat.DATETIME_FORMAT, testDate)
|
166
205
|
)
|
167
206
|
.should.eql(testDate);
|
207
|
+
});
|
168
208
|
|
169
|
-
|
209
|
+
it("works with ABSOLUTETIME_FORMAT", function() {
|
210
|
+
var testDate = new Date();
|
211
|
+
dateFormat
|
170
212
|
.parse(
|
171
213
|
dateFormat.ABSOLUTETIME_FORMAT,
|
172
214
|
dateFormat(dateFormat.ABSOLUTETIME_FORMAT, testDate)
|
173
215
|
)
|
174
216
|
.should.eql(testDate);
|
217
|
+
});
|
175
218
|
});
|
176
219
|
});
|
177
220
|
});
|