diff --git a/.eslintrc b/.eslintrc
index 532a594..a56d2c6 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -10,6 +10,11 @@
"jest": true
},
"rules": {
- "valid-jsdoc": 0
+ "valid-jsdoc": 0,
+ "import/consistent-type-specifier-style": ["error", "prefer-top-level"],
+ "@typescript-eslint/consistent-type-imports": [
+ "error",
+ {"prefer": "type-imports", "fixStyle": "separate-type-imports"}
+ ]
}
}
diff --git a/src/constants/format.ts b/src/constants/format.ts
index dd9db12..17c9092 100644
--- a/src/constants/format.ts
+++ b/src/constants/format.ts
@@ -10,3 +10,15 @@ export const englishFormats = {
LLL: 'MMMM D, YYYY h:mm A',
LLLL: 'dddd, MMMM D, YYYY h:mm A',
} as const satisfies LongDateFormat;
+
+export const HTML5_INPUT_FORMATS = {
+ DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm', //
+ DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss', //
+ DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS', //
+ DATE: 'YYYY-MM-DD', //
+ TIME: 'HH:mm', //
+ TIME_SECONDS: 'HH:mm:ss', //
+ TIME_MS: 'HH:mm:ss.SSS', //
+ WEEK: 'GGGG-[W]WW', //
+ MONTH: 'YYYY-MM', //
+} as const;
diff --git a/src/dateTime/__tests__/format.ts b/src/dateTime/__tests__/format.ts
new file mode 100644
index 0000000..a7fd91e
--- /dev/null
+++ b/src/dateTime/__tests__/format.ts
@@ -0,0 +1,344 @@
+import {HTML5_INPUT_FORMATS} from '../../constants';
+import {settings} from '../../settings';
+import {dateTime, dateTimeUtc} from '../dateTime';
+
+afterEach(() => {
+ settings.updateLocale({weekStart: 1, yearStart: 1});
+});
+
+test('format using constants', () => {
+ const m = dateTime({input: '2016-01-02T23:40:40.678'});
+ expect(m.format(HTML5_INPUT_FORMATS.DATETIME_LOCAL)).toBe('2016-01-02T23:40'); // 'datetime local format constant'
+ expect(m.format(HTML5_INPUT_FORMATS.DATETIME_LOCAL_SECONDS)).toBe('2016-01-02T23:40:40'); // 'datetime local format constant'
+
+ expect(m.format(HTML5_INPUT_FORMATS.DATETIME_LOCAL_MS)).toBe('2016-01-02T23:40:40.678'); // 'datetime local format constant with seconds and millis'
+ expect(m.format(HTML5_INPUT_FORMATS.DATE)).toBe('2016-01-02'); // 'date format constant'
+ expect(m.format(HTML5_INPUT_FORMATS.TIME)).toBe('23:40'); // 'time format constant')
+ expect(m.format(HTML5_INPUT_FORMATS.TIME_SECONDS)).toBe('23:40:40'); // 'time format constant with seconds'
+ expect(m.format(HTML5_INPUT_FORMATS.TIME_MS)).toBe('23:40:40.678'); //'time format constant with seconds and millis'
+ expect(m.format(HTML5_INPUT_FORMATS.WEEK)).toBe('2015-W53'); // 'week format constant'
+ expect(m.format(HTML5_INPUT_FORMATS.MONTH)).toBe('2016-01'); // 'month format constant'
+});
+
+test('format YY', () => {
+ const b = dateTime({input: new Date(2009, 1, 14, 15, 25, 50, 125)});
+ expect(b.format('YY')).toBe('09'); // 'YY ---> 09'
+});
+
+test('format escape brackets', () => {
+ const b = dateTime({input: new Date(2009, 1, 14, 15, 25, 50, 125)});
+ expect(b.format('[day]')).toBe('day'); // 'Single bracket'
+ expect(b.format('[day] YY [YY]')).toBe('day 09 YY'); // 'Double bracket'
+ expect(b.format('[YY')).toBe('[09'); // 'Un-ended bracket'
+ expect(b.format('[[YY]]')).toBe('[YY]'); // 'Double nested brackets'
+ expect(b.format('[[]')).toBe('['); // 'Escape open bracket'
+ expect(b.format('[Last]')).toBe('Last'); // 'localized tokens'
+ expect(b.format('[L] L')).toBe('L 02/14/2009'); // 'localized tokens with escaped localized tokens'
+ expect(b.format('[L LL LLL LLLL aLa]')).toBe('L LL LLL LLLL aLa'); // 'localized tokens with escaped localized tokens',
+ expect(b.format('[LLL] LLL')).toBe('LLL February 14, 2009 3:25 PM'); // 'localized tokens with escaped localized tokens (recursion)',
+ expect(b.format('YYYY[\n]DD[\n]')).toBe('2009\n14\n'); // 'Newlines'
+});
+
+test('handle negative years', () => {
+ expect(dateTimeUtc().year(-1).format('YY')).toBe('-01'); // 'YY with negative year'
+ expect(dateTimeUtc().year(-1).format('YYYY')).toBe('-0001'); // 'YYYY with negative year'
+ expect(dateTimeUtc().year(-12).format('YY')).toBe('-12'); // 'YY with negative year'
+ expect(dateTimeUtc().year(-12).format('YYYY')).toBe('-0012'); // 'YYYY with negative year'
+ expect(dateTimeUtc().year(-123).format('YY')).toBe('-23'); // 'YY with negative year'
+ expect(dateTimeUtc().year(-123).format('YYYY')).toBe('-0123'); // 'YYYY with negative year'
+ expect(dateTimeUtc().year(-1234).format('YY')).toBe('-34'); // 'YY with negative year'
+ expect(dateTimeUtc().year(-1234).format('YYYY')).toBe('-1234'); // 'YYYY with negative year'
+ expect(dateTimeUtc().year(-12345).format('YY')).toBe('-45'); // 'YY with negative year'
+ expect(dateTimeUtc().year(-12345).format('YYYY')).toBe('-12345'); // 'YYYY with negative year'
+});
+
+test('format milliseconds', () => {
+ let b = dateTime({input: new Date(2009, 1, 14, 15, 25, 50, 123)});
+ expect(b.format('S')).toBe('1'); // 'Deciseconds'
+ expect(b.format('SS')).toBe('12'); // 'Centiseconds'
+ expect(b.format('SSS')).toBe('123'); // 'Milliseconds'
+ b = b.millisecond(789);
+ expect(b.format('S')).toBe('7'); // 'Deciseconds'
+ expect(b.format('SS')).toBe('78'); // 'Centiseconds'
+ expect(b.format('SSS')).toBe('789'); // 'Milliseconds'
+});
+
+test('format timezone', () => {
+ const b = dateTime({input: new Date(2010, 1, 14, 15, 25, 50, 125)});
+ expect(b.format('Z')).toMatch(/^[+-]\d\d:\d\d$/); // 'should be something like '+07:30'
+ expect(b.format('ZZ')).toMatch(/^[+-]\d{4}$/); // 'should be something like '+0700'
+});
+
+test('unix timestamp', () => {
+ const m = dateTime({input: 1234567890123});
+ expect(m.format('X')).toBe('1234567890'); // 'unix timestamp without milliseconds'
+ expect(m.format('X.S')).toBe('1234567890.1'); // 'unix timestamp with deciseconds'
+ expect(m.format('X.SS')).toBe('1234567890.12'); // 'unix timestamp with centiseconds'
+ expect(m.format('X.SSS')).toBe('1234567890.123'); // 'unix timestamp with milliseconds'
+});
+
+test('unix offset milliseconds', () => {
+ const m = dateTime({input: 1234567890123});
+ expect(m.format('x')).toBe('1234567890123'); // 'unix offset in milliseconds'
+});
+
+test('utcOffset sanity checks', () => {
+ expect(dateTime({timeZone: 'Europe/Amsterdam'}).utcOffset() % 15).toBe(0); // 'utc offset should be a multiple of 15 (was ' + dateTimeParse().utcOffset() + ')'
+
+ expect(dateTime().utcOffset()).toBe(-new Date().getTimezoneOffset() || 0); // 'utcOffset should return the opposite of getTimezoneOffset'
+});
+
+test('default format', () => {
+ const isoRegex = /\d{4}.\d\d.\d\dT\d\d.\d\d.\d\d[+-]\d\d:\d\d/;
+ expect(isoRegex.exec(dateTime({timeZone: 'Europe/Amsterdam'}).format())).toBeTruthy();
+});
+
+test('default UTC format', () => {
+ const isoRegex = /\d{4}.\d\d.\d\dT\d\d.\d\d.\d\dZ/;
+ expect(isoRegex.exec(dateTimeUtc().format())).toBeTruthy();
+});
+
+test('toJSON', () => {
+ const date = dateTime({input: '2012-10-09T21:30:40.678+0100'});
+
+ expect(date.toJSON()).toBe('2012-10-09T20:30:40.678Z'); // 'should output ISO8601 on dateTimeParse.fn.toJSON'
+
+ expect(JSON.stringify({date})).toBe('{"date":"2012-10-09T20:30:40.678Z"}'); // 'should output ISO8601 on JSON.stringify'
+});
+
+test('toISOString', () => {
+ let date = dateTimeUtc({input: '2012-10-09T20:30:40.678'});
+
+ expect(date.toISOString()).toBe('2012-10-09T20:30:40.678Z'); // 'should output ISO8601 on dateTimeParse.fn.toISOString'
+
+ // big years
+ date = dateTimeUtc({input: [20123, 9, 9, 20, 30, 40, 678]});
+ expect(date.toISOString()).toBe('+020123-10-09T20:30:40.678Z'); // 'ISO8601 format on big positive year'
+ // negative years
+ date = dateTimeUtc({input: [-1, 9, 9, 20, 30, 40, 678]});
+ expect(date.toISOString()).toBe('-000001-10-09T20:30:40.678Z'); // 'ISO8601 format on negative year'
+ // big negative years
+ date = dateTimeUtc({input: [-20123, 9, 9, 20, 30, 40, 678]});
+ expect(date.toISOString()).toBe('-020123-10-09T20:30:40.678Z'); // 'ISO8601 format on big negative year'
+
+ //invalid dates
+ date = dateTimeUtc({input: '2017-12-32k'});
+ expect(() => date.toISOString()).toThrow(); // 'An invalid date to iso string is null'
+});
+
+test('toISOString without UTC conversion', () => {
+ let date = dateTimeUtc({input: '2016-12-31T19:53:45.678'}).utcOffset('+05:30');
+
+ expect(date.toISOString(true)).toBe('2017-01-01T01:23:45.678+05:30'); // 'should output ISO8601 on dateTimeParse.fn.toISOString'
+
+ // big years
+ date = dateTime({input: '+020122-12-31T19:53:45.678Z'}).utcOffset('+05:30');
+ expect(date.toISOString(true)).toBe('+020123-01-01T01:23:45.678+05:30'); // 'ISO8601 format on big positive year'
+ // negative years
+ date = dateTime({input: '-000002-12-31T19:53:45.678Z'}).utcOffset('+05:30');
+ expect(date.toISOString(true)).toBe('-000001-01-01T01:23:45.678+05:30'); //'ISO8601 format on negative year'
+ // big negative years
+ date = dateTime({input: '-020124-12-31T19:53:45.678Z'}).utcOffset('+05:30');
+ expect(date.toISOString(true)).toBe('-020123-01-01T01:23:45.678+05:30'); // 'ISO8601 format on big negative year'
+
+ //invalid dates
+ date = dateTimeUtc({input: '2017-12-32k'}).utcOffset('+05:30');
+ expect(() => date.toISOString(true)).toThrow(); // 'An invalid date to iso string is null'
+});
+
+test('long years', () => {
+ expect(dateTimeUtc().year(2).format('YYYYYY')).toBe('+000002'); // 'small year with YYYYYY'
+ expect(dateTimeUtc().year(2012).format('YYYYYY')).toBe('+002012'); // 'regular year with YYYYYY'
+ expect(dateTimeUtc().year(20123).format('YYYYYY')).toBe('+020123'); // 'big year with YYYYYY'
+
+ expect(dateTimeUtc().year(-1).format('YYYYYY')).toBe('-000001'); // 'small negative year with YYYYYY'
+ expect(dateTimeUtc().year(-2012).format('YYYYYY')).toBe('-002012'); // 'negative year with YYYYYY'
+ expect(dateTimeUtc().year(-20123).format('YYYYYY')).toBe('-020123'); // 'big negative year with YYYYYY'
+});
+
+test('toISOString() when 0 year', () => {
+ const date = dateTime({input: '0000-01-01T21:00:00.000Z'});
+ expect(date.toISOString()).toBe('0000-01-01T21:00:00.000Z');
+ expect(date.toDate().toISOString()).toBe('0000-01-01T21:00:00.000Z');
+});
+
+test.each<[string, string]>([
+ ['2005-01-02', '2004-53'],
+ ['2005-12-31', '2005-52'],
+ ['2007-01-01', '2007-01'],
+ ['2007-12-30', '2007-52'],
+ ['2007-12-31', '2008-01'],
+ ['2008-01-01', '2008-01'],
+ ['2008-12-28', '2008-52'],
+ ['2008-12-29', '2009-01'],
+ ['2008-12-30', '2009-01'],
+ ['2008-12-31', '2009-01'],
+ ['2009-01-01', '2009-01'],
+ ['2009-12-31', '2009-53'],
+ ['2010-01-01', '2009-53'],
+ ['2010-01-02', '2009-53'],
+ ['2010-01-03', '2009-53'],
+ ['0404-12-31', '0404-53'],
+ ['0405-12-31', '0405-52'],
+])('iso week formats, (%j)', (input, expected) => {
+ // https://en.wikipedia.org/wiki/ISO_week_date
+ const isoWeek = expected.split('-')[1];
+ const date = dateTime({input, format: 'YYYY-MM-DD'});
+ expect(date.format('WW')).toBe(isoWeek);
+ expect(date.format('W')).toBe(isoWeek.replace(/^0+/, ''));
+});
+
+test.each<[string, string]>([
+ ['2005-01-02', '2004-53'],
+ ['2005-12-31', '2005-52'],
+ ['2007-01-01', '2007-01'],
+ ['2007-12-30', '2007-52'],
+ ['2007-12-31', '2008-01'],
+ ['2008-01-01', '2008-01'],
+ ['2008-12-28', '2008-52'],
+ ['2008-12-29', '2009-01'],
+ ['2008-12-30', '2009-01'],
+ ['2008-12-31', '2009-01'],
+ ['2009-01-01', '2009-01'],
+ ['2009-12-31', '2009-53'],
+ ['2010-01-01', '2009-53'],
+ ['2010-01-02', '2009-53'],
+ ['2010-01-03', '2009-53'],
+ ['0404-12-31', '0404-53'],
+ ['0405-12-31', '0405-52'],
+])('iso week year formats, (%j)', (input, expected) => {
+ // https://en.wikipedia.org/wiki/ISO_week_date
+ const isoWeekYear = expected.split('-')[0];
+ const date = dateTime({input, format: 'YYYY-MM-DD'});
+ expect(date.format('GGGGG')).toBe('0' + isoWeekYear);
+ expect(date.format('GGGG')).toBe(isoWeekYear);
+ expect(date.format('GG')).toBe(isoWeekYear.slice(2, 4));
+});
+
+test.each<[string, string]>([
+ ['2005-01-02', '2004-53'],
+ ['2005-12-31', '2005-52'],
+ ['2007-01-01', '2007-01'],
+ ['2007-12-30', '2007-52'],
+ ['2007-12-31', '2008-01'],
+ ['2008-01-01', '2008-01'],
+ ['2008-12-28', '2008-52'],
+ ['2008-12-29', '2009-01'],
+ ['2008-12-30', '2009-01'],
+ ['2008-12-31', '2009-01'],
+ ['2009-01-01', '2009-01'],
+ ['2009-12-31', '2009-53'],
+ ['2010-01-01', '2009-53'],
+ ['2010-01-02', '2009-53'],
+ ['2010-01-03', '2009-53'],
+ ['0404-12-31', '0404-53'],
+ ['0405-12-31', '0405-52'],
+])('week year formats, (%j)', (input, expected) => {
+ settings.updateLocale({yearStart: 4});
+ const weekYear = expected.split('-')[0];
+ const date = dateTime({input, format: 'YYYY-MM-DD'});
+ expect(date.format('ggggg')).toBe('0' + weekYear);
+ expect(date.format('gggg')).toBe(weekYear);
+ expect(date.format('gg')).toBe(weekYear.slice(2, 4));
+});
+
+test('iso weekday formats', () => {
+ expect(dateTime({input: [1985, 1, 4]}).format('E')).toBe('1'); // 'Feb 4 1985 is Monday -- 1st day'
+ expect(dateTime({input: [2029, 8, 18]}).format('E')).toBe('2'); // 'Sep 18 2029 is Tuesday -- 2nd day'
+ expect(dateTime({input: [2013, 3, 24]}).format('E')).toBe('3'); // 'Apr 24 2013 is Wednesday -- 3rd day'
+ expect(dateTime({input: [2015, 2, 5]}).format('E')).toBe('4'); // 'Mar 5 2015 is Thursday -- 4th day'
+ expect(dateTime({input: [1970, 0, 2]}).format('E')).toBe('5'); // 'Jan 2 1970 is Friday -- 5th day'
+ expect(dateTime({input: [2001, 4, 12]}).format('E')).toBe('6'); // 'May 12 2001 is Saturday -- 6th day'
+ expect(dateTime({input: [2000, 0, 2]}).format('E')).toBe('7'); // 'Jan 2 2000 is Sunday -- 7th day'
+});
+
+test('weekday formats', () => {
+ settings.updateLocale({weekStart: 3});
+ expect(dateTime({input: [1985, 1, 6]}).format('e')).toBe('0'); // 'Feb 6 1985 is Wednesday -- 0th day'
+ expect(dateTime({input: [2029, 8, 20]}).format('e')).toBe('1'); // 'Sep 20 2029 is Thursday -- 1st day'
+ expect(dateTime({input: [2013, 3, 26]}).format('e')).toBe('2'); // 'Apr 26 2013 is Friday -- 2nd day'
+ expect(dateTime({input: [2015, 2, 7]}).format('e')).toBe('3'); // 'Mar 7 2015 is Saturday -- 3nd day'
+ expect(dateTime({input: [1970, 0, 4]}).format('e')).toBe('4'); // 'Jan 4 1970 is Sunday -- 4th day'
+ expect(dateTime({input: [2001, 4, 14]}).format('e')).toBe('5'); // 'May 14 2001 is Monday -- 5th day'
+ expect(dateTime({input: [2000, 0, 4]}).format('e')).toBe('6'); // 'Jan 4 2000 is Tuesday -- 6th day'
+});
+
+test('invalid', () => {
+ const invalid = dateTime({input: NaN});
+ expect(invalid.format()).toBe('Invalid Date');
+ expect(invalid.format('YYYY-MM-DD')).toBe('Invalid Date');
+});
+
+test('quarter formats', () => {
+ expect(dateTime({input: [1985, 1, 4]}).format('Q')).toBe('1'); //'Feb 4 1985 is Q1'
+ expect(dateTime({input: [2029, 8, 18]}).format('Q')).toBe('3'); //'Sep 18 2029 is Q3'
+ expect(dateTime({input: [2013, 3, 24]}).format('Q')).toBe('2'); //'Apr 24 2013 is Q2'
+ expect(dateTime({input: [2015, 2, 5]}).format('Q')).toBe('1'); //'Mar 5 2015 is Q1'
+ expect(dateTime({input: [1970, 0, 2]}).format('Q')).toBe('1'); //'Jan 2 1970 is Q1'
+ expect(dateTime({input: [2001, 11, 12]}).format('Q')).toBe('4'); // 'Dec 12 2001 is Q4'
+ expect(dateTime({input: [2000, 0, 2]}).format('[Q]Q-YYYY')).toBe('Q1-2000'); // 'Jan 2 2000 is Q1'
+});
+
+test('quarter ordinal formats', () => {
+ expect(dateTime({input: [1985, 1, 4]}).format('Qo')).toBe('1st'); // 'Feb 4 1985 is 1st quarter'
+ expect(dateTime({input: [2029, 8, 18]}).format('Qo')).toBe('3rd'); // 'Sep 18 2029 is 3rd quarter'
+ expect(dateTime({input: [2013, 3, 24]}).format('Qo')).toBe('2nd'); // 'Apr 24 2013 is 2nd quarter'
+ expect(dateTime({input: [2015, 2, 5]}).format('Qo')).toBe('1st'); // 'Mar 5 2015 is 1st quarter'
+ expect(dateTime({input: [1970, 0, 2]}).format('Qo')).toBe('1st'); // 'Jan 2 1970 is 1st quarter'
+ expect(dateTime({input: [2001, 11, 12]}).format('Qo')).toBe('4th'); // 'Dec 12 2001 is 4th quarter'
+ expect(dateTime({input: [2000, 0, 2]}).format('Qo [quarter] YYYY')).toBe('1st quarter 2000'); // 'Jan 2 2000 is 1st quarter'
+});
+
+test('milliseconds', () => {
+ const m = dateTime({input: '123', format: 'SSS'});
+
+ expect(m.format('S')).toBe('1');
+ expect(m.format('SS')).toBe('12');
+ expect(m.format('SSS')).toBe('123');
+ expect(m.format('SSSS')).toBe('1230');
+ expect(m.format('SSSSS')).toBe('12300');
+ expect(m.format('SSSSSS')).toBe('123000');
+ expect(m.format('SSSSSSS')).toBe('1230000');
+ expect(m.format('SSSSSSSS')).toBe('12300000');
+ expect(m.format('SSSSSSSSS')).toBe('123000000');
+});
+
+test('hmm and hmmss', () => {
+ expect(dateTime({input: '12:34:56', format: 'HH:mm:ss'}).format('hmm')).toBe('1234');
+ expect(dateTime({input: '01:34:56', format: 'HH:mm:ss'}).format('hmm')).toBe('134');
+ expect(dateTime({input: '13:34:56', format: 'HH:mm:ss'}).format('hmm')).toBe('134');
+
+ expect(dateTime({input: '12:34:56', format: 'HH:mm:ss'}).format('hmmss')).toBe('123456');
+ expect(dateTime({input: '01:34:56', format: 'HH:mm:ss'}).format('hmmss')).toBe('13456');
+ expect(dateTime({input: '13:34:56', format: 'HH:mm:ss'}).format('hmmss')).toBe('13456');
+});
+
+test('Hmm and Hmmss', () => {
+ expect(dateTime({input: '12:34:56', format: 'HH:mm:ss'}).format('Hmm')).toBe('1234');
+ expect(dateTime({input: '01:34:56', format: 'HH:mm:ss'}).format('Hmm')).toBe('134');
+ expect(dateTime({input: '13:34:56', format: 'HH:mm:ss'}).format('Hmm')).toBe('1334');
+
+ expect(dateTime({input: '12:34:56', format: 'HH:mm:ss'}).format('Hmmss')).toBe('123456');
+ expect(dateTime({input: '01:34:56', format: 'HH:mm:ss'}).format('Hmmss')).toBe('13456');
+ expect(dateTime({input: '08:34:56', format: 'HH:mm:ss'}).format('Hmmss')).toBe('83456');
+ expect(dateTime({input: '18:34:56', format: 'HH:mm:ss'}).format('Hmmss')).toBe('183456');
+});
+
+test('k and kk', () => {
+ expect(dateTime({input: '01:23:45', format: 'HH:mm:ss'}).format('k')).toBe('1');
+ expect(dateTime({input: '12:34:56', format: 'HH:mm:ss'}).format('k')).toBe('12');
+ expect(dateTime({input: '01:23:45', format: 'HH:mm:ss'}).format('kk')).toBe('01');
+ expect(dateTime({input: '12:34:56', format: 'HH:mm:ss'}).format('kk')).toBe('12');
+ expect(dateTime({input: '00:34:56', format: 'HH:mm:ss'}).format('kk')).toBe('24');
+ expect(dateTime({input: '00:00:00', format: 'HH:mm:ss'}).format('kk')).toBe('24');
+});
+
+test('Y token', () => {
+ expect(dateTime({input: '2010-01-01', format: 'YYYY-MM-DD'}).format('Y')).toBe('2010'); // 'format 2010 with Y'
+ expect(dateTime({input: [-123]}).format('Y')).toBe('-0123'); // 'format -123 with Y'
+ expect(dateTime({input: [12345]}).format('Y')).toBe('+12345'); // 'format 12345 with Y'
+ expect(dateTime({input: [0]}).format('Y')).toBe('0000'); // 'format 0 with Y'
+ expect(dateTime({input: [1]}).format('Y')).toBe('0001'); // 'format 1 with Y'
+ expect(dateTime({input: [9999]}).format('Y')).toBe('9999'); // 'format 9999 with Y'
+ expect(dateTime({input: [10000]}).format('Y')).toBe('+10000'); // 'format 10000 with Y'
+});
diff --git a/src/dateTime/__tests__/weekYear.ts b/src/dateTime/__tests__/weekYear.ts
new file mode 100644
index 0000000..09cd37d
--- /dev/null
+++ b/src/dateTime/__tests__/weekYear.ts
@@ -0,0 +1,263 @@
+import {settings} from '../../settings';
+import {dateTime, dateTimeUtc} from '../dateTime';
+
+afterEach(() => {
+ settings.updateLocale({weekStart: 1, yearStart: 1});
+});
+
+test('iso week year', () => {
+ // Some examples taken from https://en.wikipedia.org/wiki/ISO_week
+ expect(dateTime({input: [2005, 0, 1]}).isoWeekYear()).toBe(2004);
+ expect(dateTime({input: [2005, 0, 2]}).isoWeekYear()).toBe(2004);
+ expect(dateTime({input: [2005, 0, 3]}).isoWeekYear()).toBe(2005);
+ expect(dateTime({input: [2005, 11, 31]}).isoWeekYear()).toBe(2005);
+ expect(dateTime({input: [2006, 0, 1]}).isoWeekYear()).toBe(2005);
+ expect(dateTime({input: [2006, 0, 2]}).isoWeekYear()).toBe(2006);
+ expect(dateTime({input: [2007, 0, 1]}).isoWeekYear()).toBe(2007);
+ expect(dateTime({input: [2007, 11, 30]}).isoWeekYear()).toBe(2007);
+ expect(dateTime({input: [2007, 11, 31]}).isoWeekYear()).toBe(2008);
+ expect(dateTime({input: [2008, 0, 1]}).isoWeekYear()).toBe(2008);
+ expect(dateTime({input: [2008, 11, 28]}).isoWeekYear()).toBe(2008);
+ expect(dateTime({input: [2008, 11, 29]}).isoWeekYear()).toBe(2009);
+ expect(dateTime({input: [2008, 11, 30]}).isoWeekYear()).toBe(2009);
+ expect(dateTime({input: [2008, 11, 31]}).isoWeekYear()).toBe(2009);
+ expect(dateTime({input: [2009, 0, 1]}).isoWeekYear()).toBe(2009);
+ expect(dateTime({input: [2010, 0, 1]}).isoWeekYear()).toBe(2009);
+ expect(dateTime({input: [2010, 0, 2]}).isoWeekYear()).toBe(2009);
+ expect(dateTime({input: [2010, 0, 3]}).isoWeekYear()).toBe(2009);
+ expect(dateTime({input: [2010, 0, 4]}).isoWeekYear()).toBe(2010);
+});
+
+test('week year', () => {
+ // Some examples taken from https://en.wikipedia.org/wiki/ISO_week
+ settings.updateLocale({weekStart: 1, yearStart: 4}); // like iso
+ expect(dateTime({input: [2005, 0, 1]}).weekYear()).toBe(2004);
+ expect(dateTime({input: [2005, 0, 2]}).weekYear()).toBe(2004);
+ expect(dateTime({input: [2005, 0, 3]}).weekYear()).toBe(2005);
+ expect(dateTime({input: [2005, 11, 31]}).weekYear()).toBe(2005);
+ expect(dateTime({input: [2006, 0, 1]}).weekYear()).toBe(2005);
+ expect(dateTime({input: [2006, 0, 2]}).weekYear()).toBe(2006);
+ expect(dateTime({input: [2007, 0, 1]}).weekYear()).toBe(2007);
+ expect(dateTime({input: [2007, 11, 30]}).weekYear()).toBe(2007);
+ expect(dateTime({input: [2007, 11, 31]}).weekYear()).toBe(2008);
+ expect(dateTime({input: [2008, 0, 1]}).weekYear()).toBe(2008);
+ expect(dateTime({input: [2008, 11, 28]}).weekYear()).toBe(2008);
+ expect(dateTime({input: [2008, 11, 29]}).weekYear()).toBe(2009);
+ expect(dateTime({input: [2008, 11, 30]}).weekYear()).toBe(2009);
+ expect(dateTime({input: [2008, 11, 31]}).weekYear()).toBe(2009);
+ expect(dateTime({input: [2009, 0, 1]}).weekYear()).toBe(2009);
+ expect(dateTime({input: [2010, 0, 1]}).weekYear()).toBe(2009);
+ expect(dateTime({input: [2010, 0, 2]}).weekYear()).toBe(2009);
+ expect(dateTime({input: [2010, 0, 3]}).weekYear()).toBe(2009);
+ expect(dateTime({input: [2010, 0, 4]}).weekYear()).toBe(2010);
+
+ settings.updateLocale({weekStart: 1, yearStart: 1});
+ expect(dateTime({input: [2004, 11, 26]}).weekYear()).toBe(2004);
+ expect(dateTime({input: [2004, 11, 27]}).weekYear()).toBe(2005);
+ expect(dateTime({input: [2005, 11, 25]}).weekYear()).toBe(2005);
+ expect(dateTime({input: [2005, 11, 26]}).weekYear()).toBe(2006);
+ expect(dateTime({input: [2006, 11, 31]}).weekYear()).toBe(2006);
+ expect(dateTime({input: [2007, 0, 1]}).weekYear()).toBe(2007);
+ expect(dateTime({input: [2007, 11, 30]}).weekYear()).toBe(2007);
+ expect(dateTime({input: [2007, 11, 31]}).weekYear()).toBe(2008);
+ expect(dateTime({input: [2008, 11, 28]}).weekYear()).toBe(2008);
+ expect(dateTime({input: [2008, 11, 29]}).weekYear()).toBe(2009);
+ expect(dateTime({input: [2009, 11, 27]}).weekYear()).toBe(2009);
+ expect(dateTime({input: [2009, 11, 28]}).weekYear()).toBe(2010);
+});
+
+test('week numbers 2012/2013', () => {
+ settings.updateLocale({weekStart: 6, yearStart: 1});
+ expect(dateTime({input: '2012-12-28', format: 'YYYY-MM-DD'}).week()).toBe(52);
+ expect(dateTime({input: '2012-12-29', format: 'YYYY-MM-DD'}).week()).toBe(1);
+ expect(dateTime({input: '2013-01-01', format: 'YYYY-MM-DD'}).week()).toBe(1);
+ expect(dateTime({input: '2013-01-08', format: 'YYYY-MM-DD'}).week()).toBe(2);
+ expect(dateTime({input: '2013-01-11', format: 'YYYY-MM-DD'}).week()).toBe(2);
+ expect(dateTime({input: '2013-01-12', format: 'YYYY-MM-DD'}).week()).toBe(3);
+ expect(dateTime({input: '2012-01-01', format: 'YYYY-MM-DD'}).weeksInYear()).toBe(52);
+});
+
+test('weeks numbers dow:1 doy:4', () => {
+ settings.updateLocale({weekStart: 1, yearStart: 4});
+ expect(dateTime({input: [2012, 0, 1]}).week()).toBe(52); // 'Jan 1 2012 should be week 52'
+ expect(dateTime({input: [2012, 0, 2]}).week()).toBe(1); // 'Jan 2 2012 should be week 1'
+ expect(dateTime({input: [2012, 0, 8]}).week()).toBe(1); // 'Jan 8 2012 should be week 1'
+ expect(dateTime({input: [2012, 0, 9]}).week()).toBe(2); // 'Jan 9 2012 should be week 2'
+ expect(dateTime({input: [2012, 0, 15]}).week()).toBe(2); // 'Jan 15 2012 should be week 2'
+ expect(dateTime({input: [2007, 0, 1]}).week()).toBe(1); // 'Jan 1 2007 should be week 1'
+ expect(dateTime({input: [2007, 0, 7]}).week()).toBe(1); // 'Jan 7 2007 should be week 1'
+ expect(dateTime({input: [2007, 0, 8]}).week()).toBe(2); // 'Jan 8 2007 should be week 2'
+ expect(dateTime({input: [2007, 0, 14]}).week()).toBe(2); // 'Jan 14 2007 should be week 2'
+ expect(dateTime({input: [2007, 0, 15]}).week()).toBe(3); // 'Jan 15 2007 should be week 3'
+ expect(dateTime({input: [2007, 11, 31]}).week()).toBe(1); // 'Dec 31 2007 should be week 1'
+ expect(dateTime({input: [2008, 0, 1]}).week()).toBe(1); // 'Jan 1 2008 should be week 1'
+ expect(dateTime({input: [2008, 0, 6]}).week()).toBe(1); // 'Jan 6 2008 should be week 1'
+ expect(dateTime({input: [2008, 0, 7]}).week()).toBe(2); // 'Jan 7 2008 should be week 2'
+ expect(dateTime({input: [2008, 0, 13]}).week()).toBe(2); // 'Jan 13 2008 should be week 2'
+ expect(dateTime({input: [2008, 0, 14]}).week()).toBe(3); // 'Jan 14 2008 should be week 3'
+ expect(dateTime({input: [2002, 11, 30]}).week()).toBe(1); // 'Dec 30 2002 should be week 1'
+ expect(dateTime({input: [2003, 0, 1]}).week()).toBe(1); // 'Jan 1 2003 should be week 1'
+ expect(dateTime({input: [2003, 0, 5]}).week()).toBe(1); // 'Jan 5 2003 should be week 1'
+ expect(dateTime({input: [2003, 0, 6]}).week()).toBe(2); // 'Jan 6 2003 should be week 2'
+ expect(dateTime({input: [2003, 0, 12]}).week()).toBe(2); // 'Jan 12 2003 should be week 2'
+ expect(dateTime({input: [2003, 0, 13]}).week()).toBe(3); // 'Jan 13 2003 should be week 3'
+ expect(dateTime({input: [2008, 11, 29]}).week()).toBe(1); // 'Dec 29 2008 should be week 1'
+ expect(dateTime({input: [2009, 0, 1]}).week()).toBe(1); // 'Jan 1 2009 should be week 1'
+ expect(dateTime({input: [2009, 0, 4]}).week()).toBe(1); // 'Jan 4 2009 should be week 1'
+ expect(dateTime({input: [2009, 0, 5]}).week()).toBe(2); // 'Jan 5 2009 should be week 2'
+ expect(dateTime({input: [2009, 0, 11]}).week()).toBe(2); // 'Jan 11 2009 should be week 2'
+ expect(dateTime({input: [2009, 0, 13]}).week()).toBe(3); // 'Jan 12 2009 should be week 3'
+ expect(dateTime({input: [2009, 11, 28]}).week()).toBe(53); // 'Dec 28 2009 should be week 53'
+ expect(dateTime({input: [2010, 0, 1]}).week()).toBe(53); // 'Jan 1 2010 should be week 53'
+ expect(dateTime({input: [2010, 0, 3]}).week()).toBe(53); // 'Jan 3 2010 should be week 53'
+ expect(dateTime({input: [2010, 0, 4]}).week()).toBe(1); // 'Jan 4 2010 should be week 1'
+ expect(dateTime({input: [2010, 0, 10]}).week()).toBe(1); // 'Jan 10 2010 should be week 1'
+ expect(dateTime({input: [2010, 0, 11]}).week()).toBe(2); // 'Jan 11 2010 should be week 2'
+ expect(dateTime({input: [2010, 11, 27]}).week()).toBe(52); // 'Dec 27 2010 should be week 52'
+ expect(dateTime({input: [2011, 0, 1]}).week()).toBe(52); // 'Jan 1 2011 should be week 52'
+ expect(dateTime({input: [2011, 0, 2]}).week()).toBe(52); // 'Jan 2 2011 should be week 52'
+ expect(dateTime({input: [2011, 0, 3]}).week()).toBe(1); // 'Jan 3 2011 should be week 1'
+ expect(dateTime({input: [2011, 0, 9]}).week()).toBe(1); // 'Jan 9 2011 should be week 1'
+ expect(dateTime({input: [2011, 0, 10]}).week()).toBe(2); // 'Jan 10 2011 should be week 2'
+});
+
+test('weeks numbers dow:6 doy:12', () => {
+ settings.updateLocale({weekStart: 6, yearStart: 1});
+ expect(dateTime({input: [2011, 11, 31]}).week()).toBe(1); // 'Dec 31 2011 should be week 1'
+ expect(dateTime({input: [2012, 0, 6]}).week()).toBe(1); // 'Jan 6 2012 should be week 1'
+ expect(dateTime({input: [2012, 0, 7]}).week()).toBe(2); // 'Jan 7 2012 should be week 2'
+ expect(dateTime({input: [2012, 0, 13]}).week()).toBe(2); // 'Jan 13 2012 should be week 2'
+ expect(dateTime({input: [2012, 0, 14]}).week()).toBe(3); // 'Jan 14 2012 should be week 3'
+ expect(dateTime({input: [2006, 11, 30]}).week()).toBe(1); // 'Dec 30 2006 should be week 1'
+ expect(dateTime({input: [2007, 0, 5]}).week()).toBe(1); // 'Jan 5 2007 should be week 1'
+ expect(dateTime({input: [2007, 0, 6]}).week()).toBe(2); // 'Jan 6 2007 should be week 2'
+ expect(dateTime({input: [2007, 0, 12]}).week()).toBe(2); // 'Jan 12 2007 should be week 2'
+ expect(dateTime({input: [2007, 0, 13]}).week()).toBe(3); // 'Jan 13 2007 should be week 3'
+ expect(dateTime({input: [2007, 11, 29]}).week()).toBe(1); // 'Dec 29 2007 should be week 1'
+ expect(dateTime({input: [2008, 0, 1]}).week()).toBe(1); // 'Jan 1 2008 should be week 1'
+ expect(dateTime({input: [2008, 0, 4]}).week()).toBe(1); // 'Jan 4 2008 should be week 1'
+ expect(dateTime({input: [2008, 0, 5]}).week()).toBe(2); // 'Jan 5 2008 should be week 2'
+ expect(dateTime({input: [2008, 0, 11]}).week()).toBe(2); // 'Jan 11 2008 should be week 2'
+ expect(dateTime({input: [2008, 0, 12]}).week()).toBe(3); // 'Jan 12 2008 should be week 3'
+ expect(dateTime({input: [2002, 11, 28]}).week()).toBe(1); // 'Dec 28 2002 should be week 1'
+ expect(dateTime({input: [2003, 0, 1]}).week()).toBe(1); // 'Jan 1 2003 should be week 1'
+ expect(dateTime({input: [2003, 0, 3]}).week()).toBe(1); // 'Jan 3 2003 should be week 1'
+ expect(dateTime({input: [2003, 0, 4]}).week()).toBe(2); // 'Jan 4 2003 should be week 2'
+ expect(dateTime({input: [2003, 0, 10]}).week()).toBe(2); // 'Jan 10 2003 should be week 2'
+ expect(dateTime({input: [2003, 0, 11]}).week()).toBe(3); // 'Jan 11 2003 should be week 3'
+ expect(dateTime({input: [2008, 11, 27]}).week()).toBe(1); // 'Dec 27 2008 should be week 1'
+ expect(dateTime({input: [2009, 0, 1]}).week()).toBe(1); // 'Jan 1 2009 should be week 1'
+ expect(dateTime({input: [2009, 0, 2]}).week()).toBe(1); // 'Jan 2 2009 should be week 1'
+ expect(dateTime({input: [2009, 0, 3]}).week()).toBe(2); // 'Jan 3 2009 should be week 2'
+ expect(dateTime({input: [2009, 0, 9]}).week()).toBe(2); // 'Jan 9 2009 should be week 2'
+ expect(dateTime({input: [2009, 0, 10]}).week()).toBe(3); // 'Jan 10 2009 should be week 3'
+ expect(dateTime({input: [2009, 11, 26]}).week()).toBe(1); // 'Dec 26 2009 should be week 1'
+ expect(dateTime({input: [2010, 0, 1]}).week()).toBe(1); // 'Jan 1 2010 should be week 1'
+ expect(dateTime({input: [2010, 0, 2]}).week()).toBe(2); // 'Jan 2 2010 should be week 2'
+ expect(dateTime({input: [2010, 0, 8]}).week()).toBe(2); // 'Jan 8 2010 should be week 2'
+ expect(dateTime({input: [2010, 0, 9]}).week()).toBe(3); // 'Jan 9 2010 should be week 3'
+ expect(dateTime({input: [2011, 0, 1]}).week()).toBe(1); // 'Jan 1 2011 should be week 1'
+ expect(dateTime({input: [2011, 0, 7]}).week()).toBe(1); // 'Jan 7 2011 should be week 1'
+ expect(dateTime({input: [2011, 0, 8]}).week()).toBe(2); // 'Jan 8 2011 should be week 2'
+ expect(dateTime({input: [2011, 0, 14]}).week()).toBe(2); // 'Jan 14 2011 should be week 2'
+ expect(dateTime({input: [2011, 0, 15]}).week()).toBe(3); // 'Jan 15 2011 should be week 3'
+});
+
+test('weeks numbers dow:1 doy:7', () => {
+ settings.updateLocale({weekStart: 1, yearStart: 1});
+ expect(dateTime({input: [2011, 11, 26]}).week()).toBe(1); // 'Dec 26 2011 should be week 1'
+ expect(dateTime({input: [2012, 0, 1]}).week()).toBe(1); // 'Jan 1 2012 should be week 1'
+ expect(dateTime({input: [2012, 0, 2]}).week()).toBe(2); // 'Jan 2 2012 should be week 2'
+ expect(dateTime({input: [2012, 0, 8]}).week()).toBe(2); // 'Jan 8 2012 should be week 2'
+ expect(dateTime({input: [2012, 0, 9]}).week()).toBe(3); // 'Jan 9 2012 should be week 3'
+ expect(dateTime({input: [2007, 0, 1]}).week()).toBe(1); // 'Jan 1 2007 should be week 1'
+ expect(dateTime({input: [2007, 0, 7]}).week()).toBe(1); // 'Jan 7 2007 should be week 1'
+ expect(dateTime({input: [2007, 0, 8]}).week()).toBe(2); // 'Jan 8 2007 should be week 2'
+ expect(dateTime({input: [2007, 0, 14]}).week()).toBe(2); // 'Jan 14 2007 should be week 2'
+ expect(dateTime({input: [2007, 0, 15]}).week()).toBe(3); // 'Jan 15 2007 should be week 3'
+ expect(dateTime({input: [2007, 11, 31]}).week()).toBe(1); // 'Dec 31 2007 should be week 1'
+ expect(dateTime({input: [2008, 0, 1]}).week()).toBe(1); // 'Jan 1 2008 should be week 1'
+ expect(dateTime({input: [2008, 0, 6]}).week()).toBe(1); // 'Jan 6 2008 should be week 1'
+ expect(dateTime({input: [2008, 0, 7]}).week()).toBe(2); // 'Jan 7 2008 should be week 2'
+ expect(dateTime({input: [2008, 0, 13]}).week()).toBe(2); // 'Jan 13 2008 should be week 2'
+ expect(dateTime({input: [2008, 0, 14]}).week()).toBe(3); // 'Jan 14 2008 should be week 3'
+ expect(dateTime({input: [2002, 11, 30]}).week()).toBe(1); // 'Dec 30 2002 should be week 1'
+ expect(dateTime({input: [2003, 0, 1]}).week()).toBe(1); // 'Jan 1 2003 should be week 1'
+ expect(dateTime({input: [2003, 0, 5]}).week()).toBe(1); // 'Jan 5 2003 should be week 1'
+ expect(dateTime({input: [2003, 0, 6]}).week()).toBe(2); // 'Jan 6 2003 should be week 2'
+ expect(dateTime({input: [2003, 0, 12]}).week()).toBe(2); // 'Jan 12 2003 should be week 2'
+ expect(dateTime({input: [2003, 0, 13]}).week()).toBe(3); // 'Jan 13 2003 should be week 3'
+ expect(dateTime({input: [2008, 11, 29]}).week()).toBe(1); // 'Dec 29 2008 should be week 1'
+ expect(dateTime({input: [2009, 0, 1]}).week()).toBe(1); // 'Jan 1 2009 should be week 1'
+ expect(dateTime({input: [2009, 0, 4]}).week()).toBe(1); // 'Jan 4 2009 should be week 1'
+ expect(dateTime({input: [2009, 0, 5]}).week()).toBe(2); // 'Jan 5 2009 should be week 2'
+ expect(dateTime({input: [2009, 0, 11]}).week()).toBe(2); // 'Jan 11 2009 should be week 2'
+ expect(dateTime({input: [2009, 0, 12]}).week()).toBe(3); // 'Jan 12 2009 should be week 3'
+ expect(dateTime({input: [2009, 11, 28]}).week()).toBe(1); // 'Dec 28 2009 should be week 1'
+ expect(dateTime({input: [2010, 0, 1]}).week()).toBe(1); // 'Jan 1 2010 should be week 1'
+ expect(dateTime({input: [2010, 0, 3]}).week()).toBe(1); // 'Jan 3 2010 should be week 1'
+ expect(dateTime({input: [2010, 0, 4]}).week()).toBe(2); // 'Jan 4 2010 should be week 2'
+ expect(dateTime({input: [2010, 0, 10]}).week()).toBe(2); // 'Jan 10 2010 should be week 2'
+ expect(dateTime({input: [2010, 0, 11]}).week()).toBe(3); // 'Jan 11 2010 should be week 3'
+ expect(dateTime({input: [2010, 11, 27]}).week()).toBe(1); // 'Dec 27 2010 should be week 1'
+ expect(dateTime({input: [2011, 0, 1]}).week()).toBe(1); // 'Jan 1 2011 should be week 1'
+ expect(dateTime({input: [2011, 0, 2]}).week()).toBe(1); // 'Jan 2 2011 should be week 1'
+ expect(dateTime({input: [2011, 0, 3]}).week()).toBe(2); // 'Jan 3 2011 should be week 2'
+ expect(dateTime({input: [2011, 0, 9]}).week()).toBe(2); // 'Jan 9 2011 should be week 2'
+ expect(dateTime({input: [2011, 0, 10]}).week()).toBe(3); // 'Jan 10 2011 should be week 3'
+});
+
+test('weeks numbers dow:0 doy:6', () => {
+ settings.updateLocale({weekStart: 0, yearStart: 1});
+ expect(dateTime({input: [2012, 0, 1]}).week()).toBe(1); // 'Jan 1 2012 should be week 1'
+ expect(dateTime({input: [2012, 0, 7]}).week()).toBe(1); // 'Jan 7 2012 should be week 1'
+ expect(dateTime({input: [2012, 0, 8]}).week()).toBe(2); // 'Jan 8 2012 should be week 2'
+ expect(dateTime({input: [2012, 0, 14]}).week()).toBe(2); // 'Jan 14 2012 should be week 2'
+ expect(dateTime({input: [2012, 0, 15]}).week()).toBe(3); // 'Jan 15 2012 should be week 3'
+ expect(dateTime({input: [2006, 11, 31]}).week()).toBe(1); // 'Dec 31 2006 should be week 1'
+ expect(dateTime({input: [2007, 0, 1]}).week()).toBe(1); // 'Jan 1 2007 should be week 1'
+ expect(dateTime({input: [2007, 0, 6]}).week()).toBe(1); // 'Jan 6 2007 should be week 1'
+ expect(dateTime({input: [2007, 0, 7]}).week()).toBe(2); // 'Jan 7 2007 should be week 2'
+ expect(dateTime({input: [2007, 0, 13]}).week()).toBe(2); // 'Jan 13 2007 should be week 2'
+ expect(dateTime({input: [2007, 0, 14]}).week()).toBe(3); // 'Jan 14 2007 should be week 3'
+ expect(dateTime({input: [2007, 11, 29]}).week()).toBe(52); // 'Dec 29 2007 should be week 52'
+ expect(dateTime({input: [2008, 0, 1]}).week()).toBe(1); // 'Jan 1 2008 should be week 1'
+ expect(dateTime({input: [2008, 0, 5]}).week()).toBe(1); // 'Jan 5 2008 should be week 1'
+ expect(dateTime({input: [2008, 0, 6]}).week()).toBe(2); // 'Jan 6 2008 should be week 2'
+ expect(dateTime({input: [2008, 0, 12]}).week()).toBe(2); // 'Jan 12 2008 should be week 2'
+ expect(dateTime({input: [2008, 0, 13]}).week()).toBe(3); // 'Jan 13 2008 should be week 3'
+ expect(dateTime({input: [2002, 11, 29]}).week()).toBe(1); // 'Dec 29 2002 should be week 1'
+ expect(dateTime({input: [2003, 0, 1]}).week()).toBe(1); // 'Jan 1 2003 should be week 1'
+ expect(dateTime({input: [2003, 0, 4]}).week()).toBe(1); // 'Jan 4 2003 should be week 1'
+ expect(dateTime({input: [2003, 0, 5]}).week()).toBe(2); // 'Jan 5 2003 should be week 2'
+ expect(dateTime({input: [2003, 0, 11]}).week()).toBe(2); // 'Jan 11 2003 should be week 2'
+ expect(dateTime({input: [2003, 0, 12]}).week()).toBe(3); // 'Jan 12 2003 should be week 3'
+ expect(dateTime({input: [2008, 11, 28]}).week()).toBe(1); // 'Dec 28 2008 should be week 1'
+ expect(dateTime({input: [2009, 0, 1]}).week()).toBe(1); // 'Jan 1 2009 should be week 1'
+ expect(dateTime({input: [2009, 0, 3]}).week()).toBe(1); // 'Jan 3 2009 should be week 1'
+ expect(dateTime({input: [2009, 0, 4]}).week()).toBe(2); // 'Jan 4 2009 should be week 2'
+ expect(dateTime({input: [2009, 0, 10]}).week()).toBe(2); // 'Jan 10 2009 should be week 2'
+ expect(dateTime({input: [2009, 0, 11]}).week()).toBe(3); // 'Jan 11 2009 should be week 3'
+ expect(dateTime({input: [2009, 11, 27]}).week()).toBe(1); // 'Dec 27 2009 should be week 1'
+ expect(dateTime({input: [2010, 0, 1]}).week()).toBe(1); // 'Jan 1 2010 should be week 1'
+ expect(dateTime({input: [2010, 0, 2]}).week()).toBe(1); // 'Jan 2 2010 should be week 1'
+ expect(dateTime({input: [2010, 0, 3]}).week()).toBe(2); // 'Jan 3 2010 should be week 2'
+ expect(dateTime({input: [2010, 0, 9]}).week()).toBe(2); // 'Jan 9 2010 should be week 2'
+ expect(dateTime({input: [2010, 0, 10]}).week()).toBe(3); // 'Jan 10 2010 should be week 3'
+ expect(dateTime({input: [2010, 11, 26]}).week()).toBe(1); // 'Dec 26 2010 should be week 1'
+ expect(dateTime({input: [2011, 0, 1]}).week()).toBe(1); // 'Jan 1 2011 should be week 1'
+ expect(dateTime({input: [2011, 0, 2]}).week()).toBe(2); // 'Jan 2 2011 should be week 2'
+ expect(dateTime({input: [2011, 0, 8]}).week()).toBe(2); // 'Jan 8 2011 should be week 2'
+ expect(dateTime({input: [2011, 0, 9]}).week()).toBe(3); // 'Jan 9 2011 should be week 3'
+});
+
+test('week year setter works', () => {
+ for (let year = 2000; year <= 2020; year += 1) {
+ expect(
+ dateTimeUtc({input: '2012-12-31T00:00:00.000Z'}).isoWeekYear(year).isoWeekYear(),
+ ).toBe(year);
+ expect(dateTimeUtc({input: '2012-12-31T00:00:00.000Z'}).weekYear(year).weekYear()).toBe(
+ year,
+ );
+ }
+});
diff --git a/src/dateTime/dateTime.ts b/src/dateTime/dateTime.ts
index 9b556f0..a15cc64 100644
--- a/src/dateTime/dateTime.ts
+++ b/src/dateTime/dateTime.ts
@@ -28,6 +28,7 @@ import {
tsToObject,
uncomputeOrdinal,
weekToGregorian,
+ weeksInWeekYear,
} from '../utils';
import type {DateObject} from '../utils';
@@ -85,8 +86,11 @@ class DateTimeImpl implements DateTime {
}
toISOString(keepOffset?: boolean): string {
+ // invalid date throws an error
if (keepOffset) {
- return this.format('YYYY-MM-DDTHH:mm:ss.SSSZ');
+ return new Date(this.valueOf() + this.utcOffset() * 60 * 1000)
+ .toISOString()
+ .replace('Z', this.format('Z'));
}
return this.toDate().toISOString();
}
@@ -132,6 +136,10 @@ class DateTimeImpl implements DateTime {
return this._timeZone === 'system' ? guessUserTimeZone() : this._timeZone;
}
+ if (!this.isValid()) {
+ return this;
+ }
+
const zone = normalizeTimeZone(timeZone, settings.getDefaultTimeZone());
let ts = this.valueOf();
let offset = timeZoneOffset(zone, ts);
@@ -269,11 +277,11 @@ class DateTimeImpl implements DateTime {
}
valueOf(): number {
- return this._timestamp;
+ return this.isValid() ? this._timestamp : NaN;
}
isSame(input?: DateTimeInput, granularity?: DurationUnit): boolean {
- const ts = getTimestamp(input);
+ const [ts] = getTimestamp(input, 'system');
if (!this.isValid() || isNaN(ts)) {
return false;
}
@@ -281,7 +289,7 @@ class DateTimeImpl implements DateTime {
}
isBefore(input?: DateTimeInput, granularity?: DurationUnit): boolean {
- const ts = getTimestamp(input);
+ const [ts] = getTimestamp(input, 'system');
if (!this.isValid() || isNaN(ts)) {
return false;
}
@@ -291,7 +299,7 @@ class DateTimeImpl implements DateTime {
}
isAfter(input?: DateTimeInput, granularity?: DurationUnit): boolean {
- const ts = getTimestamp(input);
+ const [ts] = getTimestamp(input, 'system');
if (!this.isValid() || isNaN(ts)) {
return false;
}
@@ -315,7 +323,7 @@ class DateTimeImpl implements DateTime {
const value = DateTimeImpl.isDateTime(amount)
? amount.timeZone(this._timeZone)
: createDateTime({
- ts: getTimestamp(amount),
+ ts: getTimestamp(amount, 'system')[0],
timeZone: this._timeZone,
locale: this._locale,
offset: this._offset,
@@ -371,7 +379,7 @@ class DateTimeImpl implements DateTime {
}
from(formaInput: DateTimeInput, withoutSuffix?: boolean): string {
if (!this.isValid()) {
- return INVALID_DATE_STRING;
+ return this._localeData.invalidDate || INVALID_DATE_STRING;
}
return fromTo(this, formaInput, this._localeData.relativeTime, withoutSuffix, true);
}
@@ -381,6 +389,9 @@ class DateTimeImpl implements DateTime {
if (!locale) {
return this._locale;
}
+ if (!this.isValid()) {
+ return this;
+ }
return createDateTime({
ts: this.valueOf(),
timeZone: this._timeZone,
@@ -392,13 +403,13 @@ class DateTimeImpl implements DateTime {
return new Date(this.valueOf());
}
unix(): number {
- return Math.floor(this.valueOf() / 1000);
+ return this.isValid() ? Math.floor(this.valueOf() / 1000) : NaN;
}
utc(keepLocalTime?: boolean | undefined): DateTime {
return this.timeZone(UtcTimeZone, keepLocalTime);
}
daysInMonth(): number {
- return daysInMonth(this._c.year, this._c.month);
+ return this.isValid() ? daysInMonth(this._c.year, this._c.month) : NaN;
}
// eslint-disable-next-line complexity
@@ -415,9 +426,11 @@ class DateTimeImpl implements DateTime {
const settingWeekStuff =
newComponents.day !== undefined ||
newComponents.weekNumber !== undefined ||
+ newComponents.weekYear !== undefined ||
newComponents.isoWeekNumber !== undefined ||
newComponents.weekday !== undefined ||
- newComponents.isoWeekday !== undefined;
+ newComponents.isoWeekday !== undefined ||
+ newComponents.isoWeekYear !== undefined;
const containsDayOfYear = newComponents.dayOfYear !== undefined;
const containsYear = newComponents.year !== undefined;
@@ -435,10 +448,15 @@ class DateTimeImpl implements DateTime {
let mixed;
if (settingWeekStuff) {
- const {weekday, weekNumber, isoWeekday, isoWeekNumber, day} = newComponents;
- const hasLocalWeekData = weekday !== undefined || weekNumber !== undefined;
+ const {weekday, weekNumber, weekYear, isoWeekday, isoWeekNumber, isoWeekYear, day} =
+ newComponents;
+ const hasLocalWeekData =
+ weekday !== undefined || weekNumber !== undefined || weekYear !== undefined;
const hasIsoWeekData =
- isoWeekday !== undefined || isoWeekNumber !== undefined || day !== undefined;
+ isoWeekday !== undefined ||
+ isoWeekNumber !== undefined ||
+ isoWeekYear !== undefined ||
+ day !== undefined;
if (hasLocalWeekData && hasIsoWeekData) {
throw new Error("Can't mix local week with ISO week");
}
@@ -448,7 +466,7 @@ class DateTimeImpl implements DateTime {
const weekData = {
weekday: (weekday ?? weekInfo.weekday) + 1,
weekNumber: weekNumber ?? weekInfo.weekNumber,
- weekYear: weekInfo.weekYear,
+ weekYear: weekYear ?? weekInfo.weekYear,
};
mixed = {
...dateComponents,
@@ -459,7 +477,7 @@ class DateTimeImpl implements DateTime {
const weekData = {
weekday: isoWeekday ?? (day === undefined ? weekInfo.isoWeekday : day || 7),
weekNumber: isoWeekNumber ?? weekInfo.isoWeekNumber,
- weekYear: weekInfo.isoWeekYear,
+ weekYear: isoWeekYear ?? weekInfo.isoWeekYear,
};
mixed = {...dateComponents, ...newComponents, ...weekToGregorian(weekData, 4, 1)};
}
@@ -589,6 +607,18 @@ class DateTimeImpl implements DateTime {
}
return this.isValid() ? this.weekInfo().weekNumber : NaN;
}
+ weekYear(): number;
+ weekYear(value: number): DateTime;
+ weekYear(value?: unknown): number | DateTime {
+ if (typeof value === 'number') {
+ return this.set('weekYear', value);
+ }
+ return this.isValid() ? this.weekInfo().weekYear : NaN;
+ }
+ weeksInYear(): number {
+ const {minDaysInFirstWeek, startOfWeek} = getLocaleWeekValues(this._localeData);
+ return this.isValid() ? weeksInWeekYear(this.year(), minDaysInFirstWeek, startOfWeek) : NaN;
+ }
isoWeek(): number;
isoWeek(value: number): DateTime;
isoWeek(value?: number): number | DateTime {
@@ -597,6 +627,17 @@ class DateTimeImpl implements DateTime {
}
return this.isValid() ? this.weekInfo().isoWeekNumber : NaN;
}
+ isoWeekYear(): number;
+ isoWeekYear(value: number): DateTime;
+ isoWeekYear(value?: unknown): number | DateTime {
+ if (typeof value === 'number') {
+ return this.set('isoWeekYear', value);
+ }
+ return this.isValid() ? this.weekInfo().isoWeekYear : NaN;
+ }
+ isoWeeksInYear(): number {
+ return this.isValid() ? weeksInWeekYear(this.year(), 4, 1) : NaN;
+ }
weekday(): number;
weekday(value: number): DateTime;
weekday(value?: number): number | DateTime {
@@ -616,15 +657,22 @@ class DateTimeImpl implements DateTime {
}
toString(): string {
- return this.toDate().toUTCString();
+ return this.isValid()
+ ? this.toDate().toUTCString()
+ : this._localeData.invalidDate || INVALID_DATE_STRING;
}
+
+ toJSON(): string | null {
+ return this.isValid() ? this.toISOString() : null;
+ }
+
/**
* Returns a string representation of this DateTime appropriate for the REPL.
* @return {string}
*/
[Symbol.for('nodejs.util.inspect.custom')]() {
if (this.isValid()) {
- return `DateTime { ts: ${this.toISOString()}, zone: ${this.timeZone()}, locale: ${this.locale()} }`;
+ return `DateTime { ts: ${this.toISOString()}, zone: ${this.timeZone()}, offset: ${this.utcOffset()}, locale: ${this.locale()} }`;
} else {
return `DateTime { ${INVALID_DATE_STRING} }`;
}
@@ -713,16 +761,23 @@ function createDateTime({
return new DateTimeImpl({ts, timeZone, offset, locale: loc, localeData, isValid});
}
-function getTimestamp(input: DateTimeInput, format?: string, lang?: string, utc = false) {
+function getTimestamp(
+ input: DateTimeInput,
+ timezone: string,
+ format?: string,
+ lang?: string,
+ utc = false,
+): [ts: number, offset: number] {
let ts: number;
+ let offset: number | undefined;
if (isDateTime(input) || typeof input === 'number' || input instanceof Date) {
ts = Number(input);
} else if (input === null || input === undefined) {
ts = Date.now();
} else if (Array.isArray(input)) {
- ts = getTimestampFromArray(input, utc);
+ [ts, offset] = getTimestampFromArray(input, timezone);
} else if (typeof input === 'object') {
- ts = getTimestampFromObject(input, utc);
+ [ts, offset] = getTimestampFromObject(input, timezone);
} else if (utc) {
ts = dayjs.utc(input, format, STRICT).valueOf();
} else {
@@ -733,7 +788,9 @@ function getTimestamp(input: DateTimeInput, format?: string, lang?: string, utc
ts = localDate.valueOf();
}
- return ts;
+
+ offset = offset ?? timeZoneOffset(timezone, ts);
+ return [ts, offset];
}
/**
@@ -763,9 +820,7 @@ export function dateTime(opt?: {
const timeZoneOrDefault = normalizeTimeZone(timeZone, settings.getDefaultTimeZone());
const locale = dayjs.locale(lang || settings.getLocale(), undefined, true);
- const ts = getTimestamp(input, format, lang);
-
- const offset = timeZoneOffset(timeZoneOrDefault, ts);
+ const [ts, offset] = getTimestamp(input, timeZoneOrDefault, format, lang);
const date = createDateTime({
ts,
@@ -782,7 +837,7 @@ export function dateTimeUtc(opt?: {input?: DateTimeInput; format?: FormatInput;
const locale = dayjs.locale(lang || settings.getLocale(), undefined, true);
- const ts = getTimestamp(input, format, lang, true);
+ const [ts] = getTimestamp(input, UtcTimeZone, format, lang, true);
const date = createDateTime({
ts,
diff --git a/src/dateTime/format.ts b/src/dateTime/format.ts
index 68dadce..ce51a60 100644
--- a/src/dateTime/format.ts
+++ b/src/dateTime/format.ts
@@ -40,7 +40,7 @@ export function expandFormat(
export const FORMAT_DEFAULT = 'YYYY-MM-DDTHH:mm:ssZ';
const formattingTokens =
- /(\[[^[]*\])|([Hh]mm(ss)?|Mo|M{1,4}|Do|DDDo|D{1,4}|d{2,4}|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
+ /(\[[^[]*\])|([Hh]mm(ss)?|Mo|M{1,4}|Do|DDDo|D{1,4}|d{2,4}|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|Y{4,6}|YY?|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
const formatTokenFunctions: Record<
string,
@@ -57,10 +57,19 @@ export function formatDate(
if (formatTokenFunctions[match]) {
return formatTokenFunctions[match](date, locale, expandedFormat);
}
- return match.replace(/^\[|\]$/g, '');
+ return removeFormattingTokens(match);
});
}
+function removeFormattingTokens(input: string) {
+ return input.replace(/^\[([\s\S)]*)\]$/g, '$1');
+}
+
+formatTokenFunctions['Y'] = (date) => {
+ const y = date.year();
+ return y <= 9999 ? zeroPad(y, 4) : '+' + y;
+};
+
formatTokenFunctions['YY'] = (date) => {
const y = date.year();
return zeroPad(y % 100, 2);
@@ -85,7 +94,8 @@ formatTokenFunctions['MM'] = (date) => {
};
formatTokenFunctions['Mo'] = (date, locale) => {
- return `${locale.ordinal?.(date.month() + 1, 'M')}`;
+ // dayjs locales ordinal method returns value inside brackets '[' ']'
+ return removeFormattingTokens(`${locale.ordinal?.(date.month() + 1, 'M')}`);
};
formatTokenFunctions['MMM'] = (date, locale, format) => {
@@ -119,7 +129,8 @@ formatTokenFunctions['ww'] = (date) => {
};
formatTokenFunctions['wo'] = (date, locale) => {
- return `${locale.ordinal?.(date.week(), 'w')}`;
+ // dayjs locales ordinal method returns value inside brackets '[' ']'
+ return removeFormattingTokens(`${locale.ordinal?.(date.week(), 'w')}`);
};
formatTokenFunctions['W'] = (date) => {
@@ -131,7 +142,8 @@ formatTokenFunctions['WW'] = (date) => {
};
formatTokenFunctions['Wo'] = (date, locale) => {
- return `${locale.ordinal?.(date.isoWeek(), 'W')}`;
+ // dayjs locales ordinal method returns value inside brackets '[' ']'
+ return removeFormattingTokens(`${locale.ordinal?.(date.isoWeek(), 'W')}`);
};
formatTokenFunctions['d'] = (date) => {
@@ -139,7 +151,8 @@ formatTokenFunctions['d'] = (date) => {
};
formatTokenFunctions['do'] = (date, locale) => {
- return `${locale.ordinal?.(date.day(), 'd')}`;
+ // dayjs locales ordinal method returns value inside brackets '[' ']'
+ return removeFormattingTokens(`${locale.ordinal?.(date.day(), 'd')}`);
};
formatTokenFunctions['dd'] = (date, locale, format) => {
@@ -274,7 +287,8 @@ formatTokenFunctions['Q'] = (date) => {
};
formatTokenFunctions['Qo'] = (date, locale) => {
- return `${locale.ordinal?.(date.quarter(), 'Q')}`;
+ // dayjs locales ordinal method returns value inside brackets '[' ']'
+ return removeFormattingTokens(`${locale.ordinal?.(date.quarter(), 'Q')}`);
};
formatTokenFunctions['D'] = (date) => {
@@ -286,7 +300,8 @@ formatTokenFunctions['DD'] = (date) => {
};
formatTokenFunctions['Do'] = (date, locale) => {
- return `${locale.ordinal?.(date.date(), 'D')}`;
+ // dayjs locales ordinal method returns value inside brackets '[' ']'
+ return removeFormattingTokens(`${locale.ordinal?.(date.date(), 'D')}`);
};
formatTokenFunctions['m'] = (date) => {
@@ -378,7 +393,32 @@ formatTokenFunctions['DDDD'] = (date) => {
};
formatTokenFunctions['DDDo'] = (date, locale) => {
- return `${locale.ordinal?.(date.dayOfYear(), 'DDD')}`;
+ // dayjs locales ordinal method returns value inside brackets '[' ']'
+ return removeFormattingTokens(`${locale.ordinal?.(date.dayOfYear(), 'DDD')}`);
+};
+
+formatTokenFunctions['gg'] = (date) => {
+ return zeroPad(date.weekYear() % 100, 2);
+};
+
+formatTokenFunctions['gggg'] = (date) => {
+ return zeroPad(date.weekYear(), 4);
+};
+
+formatTokenFunctions['ggggg'] = (date) => {
+ return zeroPad(date.weekYear(), 5);
+};
+
+formatTokenFunctions['GG'] = (date) => {
+ return zeroPad(date.isoWeekYear() % 100, 2);
+};
+
+formatTokenFunctions['GGGG'] = (date) => {
+ return zeroPad(date.isoWeekYear(), 4);
+};
+
+formatTokenFunctions['GGGGG'] = (date) => {
+ return zeroPad(date.isoWeekYear(), 5);
};
function getShort({
diff --git a/src/dateTime/parse.ts b/src/dateTime/parse.ts
index 1174dc0..d1251cc 100644
--- a/src/dateTime/parse.ts
+++ b/src/dateTime/parse.ts
@@ -1,64 +1,53 @@
+import {fixOffset, timeZoneOffset} from '../timeZone';
import type {InputObject} from '../typings';
-import {normalizeComponent, normalizeDateComponents} from '../utils';
+import {normalizeComponent, normalizeDateComponents, objToTS, tsToObject} from '../utils';
+import type {DateObject} from '../utils';
-export function getTimestampFromArray(input: (number | string)[], utc = false) {
+export function getTimestampFromArray(input: (number | string)[], timezone: string) {
if (input.length === 0) {
- return Date.now();
+ return getTimestampFromObject({}, timezone);
}
const dateParts = input.map(Number);
- let date: Date;
- const [year, month = 0, day = 1, hours = 0, minutes = 0, seconds = 0, milliseconds = 0] =
+ const [year, month = 0, date = 1, hour = 0, minute = 0, second = 0, millisecond = 0] =
dateParts;
- if (utc) {
- date = new Date(Date.UTC(year, month, day, hours, minutes, seconds, milliseconds));
- } else {
- date = new Date(year, month, day, hours, minutes, seconds, milliseconds);
- }
-
- if (year >= 0 && year < 100) {
- if (utc) {
- date.setUTCFullYear(year, month, day);
- } else {
- date.setFullYear(year, month, day);
- }
- }
- return date.valueOf();
+ return getTimestampFromObject({year, month, date, hour, minute, second, millisecond}, timezone);
}
-export function getTimestampFromObject(input: InputObject, utc = false) {
- if (Object.keys(input).length === 0) {
- return Date.now();
- }
+const defaultUnitValues = {
+ year: 1,
+ month: 1,
+ date: 1,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisecond: 0,
+} as const;
+const orderedUnits = ['year', 'month', 'date', 'hour', 'minute', 'second', 'millisecond'] as const;
+
+export function getTimestampFromObject(
+ input: InputObject,
+ timezone: string,
+): [ts: number, offset: number] {
const normalized = normalizeDateComponents(input, normalizeComponent);
- normalized.day = normalized.day ?? normalized.date;
- const hasYear = normalized.year !== undefined;
- const hasMonth = normalized.month !== undefined;
- const hasDate = normalized.date !== undefined;
+ normalized.date = normalized.day ?? normalized.date;
- const now = new Date(Date.now());
- const year = normalized.year ?? utc ? now.getUTCFullYear() : now.getFullYear();
- let month = normalized.month;
- if (month === undefined) {
- if (!hasYear && !hasDate) {
- month = utc ? now.getUTCMonth() : now.getMonth();
+ const objNow = tsToObject(Date.now(), timeZoneOffset(timezone, Date.now()));
+ let foundFirst = false;
+ for (const unit of orderedUnits) {
+ if (normalized[unit] !== undefined) {
+ foundFirst = true;
+ } else if (foundFirst) {
+ normalized[unit] = defaultUnitValues[unit];
} else {
- month = 0;
+ normalized[unit] = objNow[unit];
}
}
- let day = normalized.day;
- if (day === undefined) {
- if (!hasYear && !hasMonth) {
- day = utc ? now.getUTCDate() : now.getDate();
- } else {
- day = 1;
- }
- }
- const hours = normalized.hour ?? 0;
- const minutes = normalized.minute ?? 0;
- const seconds = normalized.second ?? 0;
- const milliseconds = normalized.millisecond ?? 0;
-
- return getTimestampFromArray([year, month, day, hours, minutes, seconds, milliseconds], utc);
+ const [ts, offset] = fixOffset(
+ objToTS(normalized as DateObject),
+ timeZoneOffset(timezone, Date.now()),
+ timezone,
+ );
+ return [ts, offset];
}
diff --git a/src/index.ts b/src/index.ts
index bf4d9dd..8e14736 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -8,5 +8,5 @@ export {parse as defaultRelativeParse, isLikeRelative as defaultIsLikeRelative}
export {dateTimeParse, isValid, isLikeRelative} from './parser';
export {getTimeZonesList, guessUserTimeZone, isValidTimeZone, timeZoneOffset} from './timeZone';
export type {DateTime, DateTimeInput, Duration, DurationInput} from './typings';
-export {UtcTimeZone} from './constants';
+export {UtcTimeZone, HTML5_INPUT_FORMATS} from './constants';
export {duration, isDuration} from './duration';
diff --git a/src/settings/locales.ts b/src/settings/locales.ts
index 6fc07c8..00481e1 100644
--- a/src/settings/locales.ts
+++ b/src/settings/locales.ts
@@ -1,3 +1,4 @@
+// eslint-disable-next-line @typescript-eslint/consistent-type-imports
type LocaleLoader = () => Promise;
export const localeLoaders: Record = {
diff --git a/src/timeZone/timeZone.ts b/src/timeZone/timeZone.ts
index f98f934..7a57499 100644
--- a/src/timeZone/timeZone.ts
+++ b/src/timeZone/timeZone.ts
@@ -56,7 +56,7 @@ export function timeZoneOffset(zone: TimeZone, ts: number) {
}
if (zone === 'system') {
- return -date.getTimezoneOffset();
+ return -date.getTimezoneOffset() || 0;
}
const dtf = getDateTimeFormat('en-US', {
diff --git a/src/typings/dateTime.ts b/src/typings/dateTime.ts
index 1a8fcbf..fd9fb7f 100644
--- a/src/typings/dateTime.ts
+++ b/src/typings/dateTime.ts
@@ -52,7 +52,9 @@ export type AllUnit =
| 'E'
| 'dayOfYear'
| 'dayOfYears'
- | 'DDD';
+ | 'DDD'
+ | 'weekYear'
+ | 'isoWeekYear';
export type InputObject = Partial>;
export type SetObject = Partial>;
@@ -77,6 +79,7 @@ export interface DateTime {
endOf(unitOfTime: StartOfUnit): DateTime;
toDate(): Date;
toISOString(keepOffset?: boolean): string;
+ toJSON(): string | null;
valueOf(): number;
unix(): number;
utc(keepLocalTime?: boolean): DateTime;
@@ -102,10 +105,22 @@ export interface DateTime {
week(): number;
/** Sets the week of the year according to the locale. */
week(value: number): DateTime;
+ /** Gets the week-year according to the locale. */
+ weekYear(): number;
+ /** Sets the week-year according to the locale. */
+ weekYear(value: number): DateTime;
+ /** Gets the number of weeks in the year according to locale */
+ weeksInYear(): number;
/** Gets the ISO week of the year. First week is the week with the first Thursday of the year (i.e. of January) in it.*/
isoWeek(): number;
/** Sets the ISO week of the year. */
isoWeek(value: number): DateTime;
+ /** Gets the ISO week-year. */
+ isoWeekYear(): number;
+ /** Sets the ISO week-year. */
+ isoWeekYear(value: number): DateTime;
+ /** Gets the number of weeks in the year, according to ISO weeks. */
+ isoWeeksInYear(): number;
/** Gets the day of the year. */
dayOfYear(): number;
/** Sets the day of the year. */
diff --git a/src/utils/utils.ts b/src/utils/utils.ts
index 639209c..1906c99 100644
--- a/src/utils/utils.ts
+++ b/src/utils/utils.ts
@@ -163,6 +163,8 @@ const normalizedUnits = {
dayOfYear: 'dayOfYear',
dayOfYears: 'dayOfYear',
DDD: 'dayOfYear',
+ weekyear: 'weekYear',
+ isoweekyear: 'isoWeekYear',
} as const;
export function normalizeComponent(component: string) {