date-format 2.1.0 → 4.0.3

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/README.md CHANGED
@@ -15,18 +15,28 @@ Formatting dates as strings
15
15
 
16
16
  ```javascript
17
17
  var format = require('date-format');
18
- format.asString(); //defaults to ISO8601 format and current date.
19
- format.asString(new Date()); //defaults to ISO8601 format
20
- format.asString('hh:mm:ss.SSS', new Date()); //just the time
18
+ format.asString(); // defaults to ISO8601 format and current date
19
+ format.asString(new Date()); // defaults to ISO8601 format
20
+ format.asString('hh:mm:ss.SSS', new Date()); // just the time
21
+ format.asString(format.ISO8601_WITH_TZ_OFFSET_FORMAT, new Date()); // in ISO8601 with timezone
21
22
  ```
22
23
 
23
24
  or
24
25
 
25
26
  ```javascript
26
27
  var format = require('date-format');
27
- format(); //defaults to ISO8601 format and current date.
28
- format(new Date());
29
- format('hh:mm:ss.SSS', new Date());
28
+ format(); // defaults to ISO8601 format and current date
29
+ format(new Date()); // defaults to ISO8601 format
30
+ format('hh:mm:ss.SSS', new Date()); // just the time
31
+ format(format.ISO8601_WITH_TZ_OFFSET_FORMAT, new Date()); // in ISO8601 with timezone
32
+ ```
33
+
34
+ **output:**
35
+ ```javascript
36
+ 2017-03-14T14:10:20.391
37
+ 2017-03-14T14:10:20.391
38
+ 14:10:20.391
39
+ 2017-03-14T14:10:20.391+11:00
30
40
  ```
31
41
 
32
42
  Format string can be anything, but the following letters will be replaced (and leading zeroes added if necessary):
@@ -38,11 +48,11 @@ Format string can be anything, but the following letters will be replaced (and l
38
48
  * mm - `date.getMinutes()`
39
49
  * ss - `date.getSeconds()`
40
50
  * SSS - `date.getMilliseconds()`
41
- * O - timezone offset in +hm format (note that time will be in UTC if displaying offset)
51
+ * O - timezone offset in ±hh:mm format (note that time will still be local if displaying offset)
42
52
 
43
53
  Built-in formats:
44
54
  * `format.ISO8601_FORMAT` - `2017-03-14T14:10:20.391` (local time used)
45
- * `format.ISO8601_WITH_TZ_OFFSET_FORMAT` - `2017-03-14T03:10:20.391+1100` (UTC + TZ used)
55
+ * `format.ISO8601_WITH_TZ_OFFSET_FORMAT` - `2017-03-14T14:10:20.391+11:00` (local + TZ used)
46
56
  * `format.DATETIME_FORMAT` - `14 03 2017 14:10:20.391` (local time used)
47
57
  * `format.ABSOLUTETIME_FORMAT` - `14:10:20.391` (local time used)
48
58
 
@@ -54,5 +64,8 @@ The date format library has limited ability to parse strings into dates. It can
54
64
  var format = require('date-format');
55
65
  // pass in the format of the string as first argument
56
66
  format.parse(format.ISO8601_FORMAT, '2017-03-14T14:10:20.391');
67
+ format.parse(format.ISO8601_WITH_TZ_OFFSET_FORMAT, '2017-03-14T14:10:20.391+1100');
68
+ format.parse(format.ISO8601_WITH_TZ_OFFSET_FORMAT, '2017-03-14T14:10:20.391+11:00');
69
+ format.parse(format.ISO8601_WITH_TZ_OFFSET_FORMAT, '2017-03-14T03:10:20.391Z');
57
70
  // returns Date
58
71
  ```
package/lib/index.js CHANGED
@@ -21,17 +21,9 @@ function offset(timezoneOffset) {
21
21
  var os = Math.abs(timezoneOffset);
22
22
  var h = String(Math.floor(os / 60));
23
23
  var m = String(os % 60);
24
- if (h.length === 1) {
25
- h = "0" + h;
26
- }
27
- if (m.length === 1) {
28
- m = "0" + m;
29
- }
30
- return timezoneOffset < 0 ? "+" + h + m : "-" + h + m;
31
- }
32
-
33
- function datePart(date, displayUTC, part) {
34
- return displayUTC ? date["getUTC" + part]() : date["get" + part]();
24
+ h = ("0" + h).slice(-2);
25
+ m = ("0" + m).slice(-2);
26
+ return timezoneOffset === 0 ? "Z" : (timezoneOffset < 0 ? "+" : "-") + h + ":" + m;
35
27
  }
36
28
 
37
29
  function asString(format, date) {
@@ -43,20 +35,19 @@ function asString(format, date) {
43
35
  date = module.exports.now();
44
36
  }
45
37
 
46
- var displayUTC = format.indexOf("O") > -1;
38
+ // Issue # 14 - Per ISO8601 standard, the time string should be local time
39
+ // with timezone info.
40
+ // See https://en.wikipedia.org/wiki/ISO_8601 section "Time offsets from UTC"
47
41
 
48
- var vDay = addZero(datePart(date, displayUTC, "Date"));
49
- var vMonth = addZero(datePart(date, displayUTC, "Month") + 1);
50
- var vYearLong = addZero(datePart(date, displayUTC, "FullYear"));
42
+ var vDay = addZero(date.getDate());
43
+ var vMonth = addZero(date.getMonth() + 1);
44
+ var vYearLong = addZero(date.getFullYear());
51
45
  var vYearShort = addZero(vYearLong.substring(2, 4));
52
46
  var vYear = format.indexOf("yyyy") > -1 ? vYearLong : vYearShort;
53
- var vHour = addZero(datePart(date, displayUTC, "Hours"));
54
- var vMinute = addZero(datePart(date, displayUTC, "Minutes"));
55
- var vSecond = addZero(datePart(date, displayUTC, "Seconds"));
56
- var vMillisecond = padWithZeros(
57
- datePart(date, displayUTC, "Milliseconds"),
58
- 3
59
- );
47
+ var vHour = addZero(date.getHours());
48
+ var vMinute = addZero(date.getMinutes());
49
+ var vSecond = addZero(date.getSeconds());
50
+ var vMillisecond = padWithZeros(date.getMilliseconds(), 3);
60
51
  var vTimeZone = offset(date.getTimezoneOffset());
61
52
  var formatted = format
62
53
  .replace(/dd/g, vDay)
@@ -70,67 +61,98 @@ function asString(format, date) {
70
61
  return formatted;
71
62
  }
72
63
 
64
+ function setDatePart(date, part, value, local) {
65
+ date['set' + (local ? '' : 'UTC') + part](value);
66
+ }
67
+
73
68
  function extractDateParts(pattern, str, missingValuesDate) {
69
+ // Javascript Date object doesn't support custom timezone. Sets all felds as
70
+ // GMT based to begin with. If the timezone offset is provided, then adjust
71
+ // it using provided timezone, otherwise, adjust it with the system timezone.
72
+ var local = pattern.indexOf('O') < 0;
74
73
  var matchers = [
75
74
  {
76
75
  pattern: /y{1,4}/,
77
76
  regexp: "\\d{1,4}",
78
77
  fn: function(date, value) {
79
- date.setFullYear(value);
78
+ setDatePart(date, 'FullYear', value, local);
80
79
  }
81
80
  },
82
81
  {
83
82
  pattern: /MM/,
84
83
  regexp: "\\d{1,2}",
85
84
  fn: function(date, value) {
86
- date.setMonth(value - 1);
85
+ setDatePart(date, 'Month', (value - 1), local);
87
86
  }
88
87
  },
89
88
  {
90
89
  pattern: /dd/,
91
90
  regexp: "\\d{1,2}",
92
91
  fn: function(date, value) {
93
- date.setDate(value);
92
+ setDatePart(date, 'Date', value, local);
94
93
  }
95
94
  },
96
95
  {
97
96
  pattern: /hh/,
98
97
  regexp: "\\d{1,2}",
99
98
  fn: function(date, value) {
100
- date.setHours(value);
99
+ setDatePart(date, 'Hours', value, local);
101
100
  }
102
101
  },
103
102
  {
104
103
  pattern: /mm/,
105
104
  regexp: "\\d\\d",
106
105
  fn: function(date, value) {
107
- date.setMinutes(value);
106
+ setDatePart(date, 'Minutes', value, local);
108
107
  }
109
108
  },
110
109
  {
111
110
  pattern: /ss/,
112
111
  regexp: "\\d\\d",
113
112
  fn: function(date, value) {
114
- date.setSeconds(value);
113
+ setDatePart(date, 'Seconds', value, local);
115
114
  }
116
115
  },
117
116
  {
118
117
  pattern: /SSS/,
119
118
  regexp: "\\d\\d\\d",
120
119
  fn: function(date, value) {
121
- date.setMilliseconds(value);
120
+ setDatePart(date, 'Milliseconds', value, local);
122
121
  }
123
122
  },
124
123
  {
125
124
  pattern: /O/,
126
- regexp: "[+-]\\d{3,4}|Z",
125
+ regexp: "[+-]\\d{1,2}:?\\d{2}?|Z",
127
126
  fn: function(date, value) {
128
127
  if (value === "Z") {
129
128
  value = 0;
130
129
  }
130
+ else {
131
+ value = value.replace(":", "");
132
+ }
131
133
  var offset = Math.abs(value);
132
- var minutes = (offset % 100) + Math.floor(offset / 100) * 60;
133
- date.setMinutes(date.getMinutes() + (value > 0 ? minutes : -minutes));
134
+ var timezoneOffset = (value > 0 ? -1 : 1 ) * ((offset % 100) + Math.floor(offset / 100) * 60);
135
+ // Per ISO8601 standard: UTC = local time - offset
136
+ //
137
+ // For example, 2000-01-01T01:00:00-0700
138
+ // local time: 2000-01-01T01:00:00
139
+ // ==> UTC : 2000-01-01T08:00:00 ( 01 - (-7) = 8 )
140
+ //
141
+ // To make it even more confusing, the date.getTimezoneOffset() is
142
+ // opposite sign of offset string in the ISO8601 standard. So if offset
143
+ // is '-0700' the getTimezoneOffset() would be (+)420. The line above
144
+ // calculates timezoneOffset to matche Javascript's behavior.
145
+ //
146
+ // The date/time of the input is actually the local time, so the date
147
+ // object that was constructed is actually local time even thought the
148
+ // UTC setters are used. This means the date object's internal UTC
149
+ // representation was wrong. It needs to be fixed by substracting the
150
+ // offset (or adding the offset minutes as they are opposite sign).
151
+ //
152
+ // Note: the time zone has to be processed after all other fileds are
153
+ // set. The result would be incorrect if the offset was calculated
154
+ // first then overriden by the other filed setters.
155
+ date.setUTCMinutes(date.getUTCMinutes() + timezoneOffset);
134
156
  }
135
157
  }
136
158
  ];
@@ -162,6 +184,7 @@ function extractDateParts(pattern, str, missingValuesDate) {
162
184
  dateFns.forEach(function(f, i) {
163
185
  f.fn(date, matches[i + 1]);
164
186
  });
187
+
165
188
  return date;
166
189
  }
167
190
 
@@ -181,6 +204,7 @@ function parse(pattern, str, missingValuesDate) {
181
204
  /**
182
205
  * Used for testing - replace this function with a fixed date.
183
206
  */
207
+ // istanbul ignore next
184
208
  function now() {
185
209
  return new Date();
186
210
  }
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "date-format",
3
- "version": "2.1.0",
3
+ "version": "4.0.3",
4
4
  "description": "Formatting Date objects as strings since 2013",
5
5
  "main": "lib/index.js",
6
+ "files": [
7
+ "lib"
8
+ ],
6
9
  "repository": {
7
10
  "type": "git",
8
11
  "url": "https://github.com/nomiddlename/date-format.git"
@@ -13,7 +16,7 @@
13
16
  "scripts": {
14
17
  "lint": "eslint lib/* test/*",
15
18
  "pretest": "eslint lib/* test/*",
16
- "test": "mocha"
19
+ "test": "nyc --check-coverage mocha"
17
20
  },
18
21
  "keywords": [
19
22
  "date",
@@ -25,9 +28,18 @@
25
28
  "readmeFilename": "README.md",
26
29
  "gitHead": "bf59015ab6c9e86454b179374f29debbdb403522",
27
30
  "devDependencies": {
28
- "eslint": "^5.16.0",
29
- "eslint-plugin-mocha": "^5.3.0",
30
- "mocha": "^5.2.0",
31
+ "eslint": "^8.7.0",
32
+ "eslint-plugin-mocha": "^10.0.3",
33
+ "mocha": "^9.1.4",
34
+ "nyc": "^15.1.0",
31
35
  "should": "^13.2.3"
36
+ },
37
+ "nyc": {
38
+ "include": [
39
+ "lib/**"
40
+ ],
41
+ "branches": 100,
42
+ "lines": 100,
43
+ "functions": 100
32
44
  }
33
45
  }
package/.eslintrc DELETED
@@ -1,12 +0,0 @@
1
- {
2
- "extends": [
3
- "eslint:recommended"
4
- ],
5
- "env": {
6
- "node": true,
7
- "mocha": true
8
- },
9
- "plugins": [
10
- "mocha"
11
- ]
12
- }
package/.travis.yml DELETED
@@ -1,6 +0,0 @@
1
- language: node_js
2
- sudo: false
3
- node_js:
4
- - "10"
5
- - "8"
6
- - "6"
@@ -1,64 +0,0 @@
1
- 'use strict';
2
-
3
- require('should');
4
-
5
- var dateFormat = require('../lib');
6
-
7
- function createFixedDate() {
8
- return new Date(2010, 0, 11, 14, 31, 30, 5);
9
- }
10
-
11
- describe('date_format', function() {
12
- var date = createFixedDate();
13
-
14
- it('should default to now when a date is not provided', function() {
15
- dateFormat.asString(dateFormat.DATETIME_FORMAT).should.not.be.empty();
16
- });
17
-
18
- it('should be usable directly without calling asString', function() {
19
- dateFormat(dateFormat.DATETIME_FORMAT, date).should.eql('11 01 2010 14:31:30.005');
20
- });
21
-
22
- it('should format a date as string using a pattern', function() {
23
- dateFormat.asString(dateFormat.DATETIME_FORMAT, date).should.eql('11 01 2010 14:31:30.005');
24
- });
25
-
26
- it('should default to the ISO8601 format', function() {
27
- dateFormat.asString(date).should.eql('2010-01-11T14:31:30.005');
28
- });
29
-
30
- it('should provide a ISO8601 with timezone offset format', function() {
31
- var tzDate = createFixedDate();
32
- tzDate.setMinutes(tzDate.getMinutes() - tzDate.getTimezoneOffset() - 660);
33
- tzDate.getTimezoneOffset = function () {
34
- return -660;
35
- };
36
-
37
- // when tz offset is in the pattern, the date should be in UTC
38
- dateFormat.asString(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, tzDate)
39
- .should.eql('2010-01-11T03:31:30.005+1100');
40
-
41
- tzDate = createFixedDate();
42
- tzDate.setMinutes((tzDate.getMinutes() - tzDate.getTimezoneOffset()) + 120);
43
- tzDate.getTimezoneOffset = function () {
44
- return 120;
45
- };
46
-
47
- dateFormat.asString(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, tzDate)
48
- .should.eql('2010-01-11T16:31:30.005-0200');
49
- });
50
-
51
- it('should provide a just-the-time format', function() {
52
- dateFormat.asString(dateFormat.ABSOLUTETIME_FORMAT, date).should.eql('14:31:30.005');
53
- });
54
-
55
- it('should provide a custom format', function() {
56
- var customDate = createFixedDate();
57
- customDate.setMinutes((customDate.getMinutes() - customDate.getTimezoneOffset()) + 120);
58
- customDate.getTimezoneOffset = function () {
59
- return 120;
60
- };
61
-
62
- dateFormat.asString('O.SSS.ss.mm.hh.dd.MM.yy', customDate).should.eql('-0200.005.30.31.16.11.01.10');
63
- });
64
- });
@@ -1,177 +0,0 @@
1
- "use strict";
2
-
3
- require("should");
4
- var dateFormat = require("../lib");
5
-
6
- describe("dateFormat.parse", function() {
7
- it("should require a pattern", function() {
8
- (function() {
9
- dateFormat.parse();
10
- }.should.throw(/pattern must be supplied/));
11
- (function() {
12
- dateFormat.parse(null);
13
- }.should.throw(/pattern must be supplied/));
14
- (function() {
15
- dateFormat.parse("");
16
- }.should.throw(/pattern must be supplied/));
17
- });
18
-
19
- describe("with a pattern that has no replacements", function() {
20
- it("should return a new date when the string matches", function() {
21
- dateFormat.parse("cheese", "cheese").should.be.a.Date();
22
- });
23
-
24
- it("should throw if the string does not match", function() {
25
- (function() {
26
- dateFormat.parse("cheese", "biscuits");
27
- }.should.throw(/String 'biscuits' could not be parsed as 'cheese'/));
28
- });
29
- });
30
-
31
- describe("with a full pattern", function() {
32
- var pattern = "yyyy-MM-dd hh:mm:ss.SSSO";
33
-
34
- it("should return the correct date if the string matches", function() {
35
- var testDate = new Date();
36
- testDate.setFullYear(2018);
37
- testDate.setMonth(8);
38
- testDate.setDate(13);
39
- testDate.setHours(18);
40
- testDate.setMinutes(10);
41
- testDate.setSeconds(12);
42
- testDate.setMilliseconds(392);
43
- testDate.getTimezoneOffset = function() {
44
- return 600;
45
- };
46
-
47
- dateFormat
48
- .parse(pattern, "2018-09-13 08:10:12.392+1000")
49
- .getTime()
50
- .should.eql(testDate.getTime());
51
- });
52
-
53
- it("should throw if the string does not match", function() {
54
- (function() {
55
- dateFormat.parse(pattern, "biscuits");
56
- }.should.throw(
57
- /String 'biscuits' could not be parsed as 'yyyy-MM-dd hh:mm:ss.SSSO'/
58
- ));
59
- });
60
- });
61
-
62
- describe("with a partial pattern", function() {
63
- var testDate = new Date();
64
- dateFormat.now = function() {
65
- return testDate;
66
- };
67
-
68
- function verifyDate(actual, expected) {
69
- actual.getFullYear().should.eql(expected.year || testDate.getFullYear());
70
- actual.getMonth().should.eql(expected.month || testDate.getMonth());
71
- actual.getDate().should.eql(expected.day || testDate.getDate());
72
- actual.getHours().should.eql(expected.hours || testDate.getHours());
73
- actual.getMinutes().should.eql(expected.minutes || testDate.getMinutes());
74
- actual.getSeconds().should.eql(expected.seconds || testDate.getSeconds());
75
- actual
76
- .getMilliseconds()
77
- .should.eql(expected.milliseconds || testDate.getMilliseconds());
78
- }
79
-
80
- it("should return a date with missing values defaulting to current time", function() {
81
- var date = dateFormat.parse("yyyy-MM", "2015-09");
82
- verifyDate(date, { year: 2015, month: 8 });
83
- });
84
-
85
- it("should use a passed in date for missing values", function() {
86
- var missingValueDate = new Date(2010, 1, 11, 10, 30, 12, 100);
87
- var date = dateFormat.parse("yyyy-MM", "2015-09", missingValueDate);
88
- verifyDate(date, {
89
- year: 2015,
90
- month: 8,
91
- day: 11,
92
- hours: 10,
93
- minutes: 30,
94
- seconds: 12,
95
- milliseconds: 100
96
- });
97
- });
98
-
99
- it("should handle variations on the same pattern", function() {
100
- var date = dateFormat.parse("MM-yyyy", "09-2015");
101
- verifyDate(date, { year: 2015, month: 8 });
102
-
103
- date = dateFormat.parse("yyyy MM", "2015 09");
104
- verifyDate(date, { year: 2015, month: 8 });
105
-
106
- date = dateFormat.parse("MM, yyyy.", "09, 2015.");
107
- verifyDate(date, { year: 2015, month: 8 });
108
- });
109
-
110
- it("should match all the date parts", function() {
111
- var date = dateFormat.parse("dd", "21");
112
- verifyDate(date, { day: 21 });
113
-
114
- date = dateFormat.parse("hh", "12");
115
- verifyDate(date, { hours: 12 });
116
-
117
- date = dateFormat.parse("mm", "34");
118
- verifyDate(date, { minutes: 34 });
119
-
120
- date = dateFormat.parse("ss", "59");
121
- verifyDate(date, { seconds: 59 });
122
-
123
- date = dateFormat.parse("ss.SSS", "23.452");
124
- verifyDate(date, { seconds: 23, milliseconds: 452 });
125
-
126
- date = dateFormat.parse("hh:mm O", "05:23 +1000");
127
- verifyDate(date, { hours: 15, minutes: 23 });
128
-
129
- date = dateFormat.parse("hh:mm O", "05:23 -200");
130
- verifyDate(date, { hours: 3, minutes: 23 });
131
-
132
- date = dateFormat.parse("hh:mm O", "05:23 +0930");
133
- verifyDate(date, { hours: 14, minutes: 53 });
134
- });
135
- });
136
-
137
- describe("with a date formatted by this library", function() {
138
- var testDate = new Date();
139
- testDate.setUTCFullYear(2018);
140
- testDate.setUTCMonth(8);
141
- testDate.setUTCDate(13);
142
- testDate.setUTCHours(18);
143
- testDate.setUTCMinutes(10);
144
- testDate.setUTCSeconds(12);
145
- testDate.setUTCMilliseconds(392);
146
-
147
- it("should format and then parse back to the same date", function() {
148
- dateFormat
149
- .parse(
150
- dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT,
151
- dateFormat(dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT, testDate)
152
- )
153
- .should.eql(testDate);
154
-
155
- dateFormat
156
- .parse(
157
- dateFormat.ISO8601_FORMAT,
158
- dateFormat(dateFormat.ISO8601_FORMAT, testDate)
159
- )
160
- .should.eql(testDate);
161
-
162
- dateFormat
163
- .parse(
164
- dateFormat.DATETIME_FORMAT,
165
- dateFormat(dateFormat.DATETIME_FORMAT, testDate)
166
- )
167
- .should.eql(testDate);
168
-
169
- dateFormat
170
- .parse(
171
- dateFormat.ABSOLUTETIME_FORMAT,
172
- dateFormat(dateFormat.ABSOLUTETIME_FORMAT, testDate)
173
- )
174
- .should.eql(testDate);
175
- });
176
- });
177
- });