diff options
Diffstat (limited to 'date-fns/src/_lib')
44 files changed, 2622 insertions, 0 deletions
diff --git a/date-fns/src/_lib/addLeadingZeros/index.js b/date-fns/src/_lib/addLeadingZeros/index.js new file mode 100644 index 0000000..62f812b --- /dev/null +++ b/date-fns/src/_lib/addLeadingZeros/index.js @@ -0,0 +1,8 @@ +export default function addLeadingZeros(number, targetLength) { + var sign = number < 0 ? '-' : '' + var output = Math.abs(number).toString() + while (output.length < targetLength) { + output = '0' + output + } + return sign + output +} diff --git a/date-fns/src/_lib/assign/index.js b/date-fns/src/_lib/assign/index.js new file mode 100644 index 0000000..6fd8782 --- /dev/null +++ b/date-fns/src/_lib/assign/index.js @@ -0,0 +1,17 @@ +export default function assign(target, dirtyObject) { + if (target == null) { + throw new TypeError( + 'assign requires that input parameter not be null or undefined' + ) + } + + dirtyObject = dirtyObject || {} + + for (var property in dirtyObject) { + if (dirtyObject.hasOwnProperty(property)) { + target[property] = dirtyObject[property] + } + } + + return target +} diff --git a/date-fns/src/_lib/assign/test.js b/date-fns/src/_lib/assign/test.js new file mode 100644 index 0000000..629358f --- /dev/null +++ b/date-fns/src/_lib/assign/test.js @@ -0,0 +1,30 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import assign from '.' + +describe('assign', function() { + it('assigns properties of the second argument to the first argument', function() { + var object = {} + assign(object, { a: 1, b: 2, c: 3 }) + assert.deepEqual(object, { a: 1, b: 2, c: 3 }) + }) + + it('the object passed as 2nd argument remains unchanged when the result is mutated', function() { + var object = { a: 1, b: 2, c: 3 } + var result = assign({}, object) + result.c = 4 + assert.deepEqual(object, { a: 1, b: 2, c: 3 }) + }) + + it('returns the first argument when the second argument is `undefined`', function() { + var original = { a: 1, b: 2, c: 3 } + var result = assign(original, undefined) + assert(original === result) + }) + + it('throws TypeError exception if the first argument is `undefined', function() { + assert.throws(assign.bind(null, undefined, { a: 1, b: 2, c: 3 }), TypeError) + }) +}) diff --git a/date-fns/src/_lib/cloneObject/index.js b/date-fns/src/_lib/cloneObject/index.js new file mode 100644 index 0000000..34dd17b --- /dev/null +++ b/date-fns/src/_lib/cloneObject/index.js @@ -0,0 +1,5 @@ +import assign from '../assign/index' + +export default function cloneObject(dirtyObject) { + return assign({}, dirtyObject) +} diff --git a/date-fns/src/_lib/cloneObject/test.js b/date-fns/src/_lib/cloneObject/test.js new file mode 100644 index 0000000..96302bb --- /dev/null +++ b/date-fns/src/_lib/cloneObject/test.js @@ -0,0 +1,31 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import cloneObject from '.' + +describe('cloneObject', function () { + it('makes a copy of an object', function () { + var result = cloneObject({a: 1, b: 2, c: 3}) + assert.deepEqual(result, {a: 1, b: 2, c: 3}) + }) + + it('the copy remains unchanged when the original is changed', function () { + var original = {a: 1, b: 2, c: 3} + var copy = cloneObject(original) + original.c = 4 + assert.deepEqual(copy, {a: 1, b: 2, c: 3}) + }) + + it('the original remains unchanged when the copy is changed', function () { + var original = {a: 1, b: 2, c: 3} + var copy = cloneObject(original) + copy.c = 4 + assert.deepEqual(original, {a: 1, b: 2, c: 3}) + }) + + it('returns an empty object when argument is `undefined`', function () { + var result = cloneObject(undefined) + assert.deepEqual(result, {}) + }) +}) diff --git a/date-fns/src/_lib/format/formatters/index.js b/date-fns/src/_lib/format/formatters/index.js new file mode 100644 index 0000000..4638060 --- /dev/null +++ b/date-fns/src/_lib/format/formatters/index.js @@ -0,0 +1,768 @@ +import lightFormatters from '../lightFormatters/index' +import getUTCDayOfYear from '../../../_lib/getUTCDayOfYear/index' +import getUTCISOWeek from '../../../_lib/getUTCISOWeek/index' +import getUTCISOWeekYear from '../../../_lib/getUTCISOWeekYear/index' +import getUTCWeek from '../../../_lib/getUTCWeek/index' +import getUTCWeekYear from '../../../_lib/getUTCWeekYear/index' +import addLeadingZeros from '../../addLeadingZeros/index' + +var dayPeriodEnum = { + am: 'am', + pm: 'pm', + midnight: 'midnight', + noon: 'noon', + morning: 'morning', + afternoon: 'afternoon', + evening: 'evening', + night: 'night' +} + +/* + * | | Unit | | Unit | + * |-----|--------------------------------|-----|--------------------------------| + * | a | AM, PM | A* | Milliseconds in day | + * | b | AM, PM, noon, midnight | B | Flexible day period | + * | c | Stand-alone local day of week | C* | Localized hour w/ day period | + * | d | Day of month | D | Day of year | + * | e | Local day of week | E | Day of week | + * | f | | F* | Day of week in month | + * | g* | Modified Julian day | G | Era | + * | h | Hour [1-12] | H | Hour [0-23] | + * | i! | ISO day of week | I! | ISO week of year | + * | j* | Localized hour w/ day period | J* | Localized hour w/o day period | + * | k | Hour [1-24] | K | Hour [0-11] | + * | l* | (deprecated) | L | Stand-alone month | + * | m | Minute | M | Month | + * | n | | N | | + * | o! | Ordinal number modifier | O | Timezone (GMT) | + * | p! | Long localized time | P! | Long localized date | + * | q | Stand-alone quarter | Q | Quarter | + * | r* | Related Gregorian year | R! | ISO week-numbering year | + * | s | Second | S | Fraction of second | + * | t! | Seconds timestamp | T! | Milliseconds timestamp | + * | u | Extended year | U* | Cyclic year | + * | v* | Timezone (generic non-locat.) | V* | Timezone (location) | + * | w | Local week of year | W* | Week of month | + * | x | Timezone (ISO-8601 w/o Z) | X | Timezone (ISO-8601) | + * | y | Year (abs) | Y | Local week-numbering year | + * | z | Timezone (specific non-locat.) | Z* | Timezone (aliases) | + * + * Letters marked by * are not implemented but reserved by Unicode standard. + * + * Letters marked by ! are non-standard, but implemented by date-fns: + * - `o` modifies the previous token to turn it into an ordinal (see `format` docs) + * - `i` is ISO day of week. For `i` and `ii` is returns numeric ISO week days, + * i.e. 7 for Sunday, 1 for Monday, etc. + * - `I` is ISO week of year, as opposed to `w` which is local week of year. + * - `R` is ISO week-numbering year, as opposed to `Y` which is local week-numbering year. + * `R` is supposed to be used in conjunction with `I` and `i` + * for universal ISO week-numbering date, whereas + * `Y` is supposed to be used in conjunction with `w` and `e` + * for week-numbering date specific to the locale. + * - `P` is long localized date format + * - `p` is long localized time format + */ + +var formatters = { + // Era + G: function(date, token, localize) { + var era = date.getUTCFullYear() > 0 ? 1 : 0 + switch (token) { + // AD, BC + case 'G': + case 'GG': + case 'GGG': + return localize.era(era, { width: 'abbreviated' }) + // A, B + case 'GGGGG': + return localize.era(era, { width: 'narrow' }) + // Anno Domini, Before Christ + case 'GGGG': + default: + return localize.era(era, { width: 'wide' }) + } + }, + + // Year + y: function(date, token, localize) { + // Ordinal number + if (token === 'yo') { + var signedYear = date.getUTCFullYear() + // Returns 1 for 1 BC (which is year 0 in JavaScript) + var year = signedYear > 0 ? signedYear : 1 - signedYear + return localize.ordinalNumber(year, { unit: 'year' }) + } + + return lightFormatters.y(date, token) + }, + + // Local week-numbering year + Y: function(date, token, localize, options) { + var signedWeekYear = getUTCWeekYear(date, options) + // Returns 1 for 1 BC (which is year 0 in JavaScript) + var weekYear = signedWeekYear > 0 ? signedWeekYear : 1 - signedWeekYear + + // Two digit year + if (token === 'YY') { + var twoDigitYear = weekYear % 100 + return addLeadingZeros(twoDigitYear, 2) + } + + // Ordinal number + if (token === 'Yo') { + return localize.ordinalNumber(weekYear, { unit: 'year' }) + } + + // Padding + return addLeadingZeros(weekYear, token.length) + }, + + // ISO week-numbering year + R: function(date, token) { + var isoWeekYear = getUTCISOWeekYear(date) + + // Padding + return addLeadingZeros(isoWeekYear, token.length) + }, + + // Extended year. This is a single number designating the year of this calendar system. + // The main difference between `y` and `u` localizers are B.C. years: + // | Year | `y` | `u` | + // |------|-----|-----| + // | AC 1 | 1 | 1 | + // | BC 1 | 1 | 0 | + // | BC 2 | 2 | -1 | + // Also `yy` always returns the last two digits of a year, + // while `uu` pads single digit years to 2 characters and returns other years unchanged. + u: function(date, token) { + var year = date.getUTCFullYear() + return addLeadingZeros(year, token.length) + }, + + // Quarter + Q: function(date, token, localize) { + var quarter = Math.ceil((date.getUTCMonth() + 1) / 3) + switch (token) { + // 1, 2, 3, 4 + case 'Q': + return String(quarter) + // 01, 02, 03, 04 + case 'QQ': + return addLeadingZeros(quarter, 2) + // 1st, 2nd, 3rd, 4th + case 'Qo': + return localize.ordinalNumber(quarter, { unit: 'quarter' }) + // Q1, Q2, Q3, Q4 + case 'QQQ': + return localize.quarter(quarter, { + width: 'abbreviated', + context: 'formatting' + }) + // 1, 2, 3, 4 (narrow quarter; could be not numerical) + case 'QQQQQ': + return localize.quarter(quarter, { + width: 'narrow', + context: 'formatting' + }) + // 1st quarter, 2nd quarter, ... + case 'QQQQ': + default: + return localize.quarter(quarter, { + width: 'wide', + context: 'formatting' + }) + } + }, + + // Stand-alone quarter + q: function(date, token, localize) { + var quarter = Math.ceil((date.getUTCMonth() + 1) / 3) + switch (token) { + // 1, 2, 3, 4 + case 'q': + return String(quarter) + // 01, 02, 03, 04 + case 'qq': + return addLeadingZeros(quarter, 2) + // 1st, 2nd, 3rd, 4th + case 'qo': + return localize.ordinalNumber(quarter, { unit: 'quarter' }) + // Q1, Q2, Q3, Q4 + case 'qqq': + return localize.quarter(quarter, { + width: 'abbreviated', + context: 'standalone' + }) + // 1, 2, 3, 4 (narrow quarter; could be not numerical) + case 'qqqqq': + return localize.quarter(quarter, { + width: 'narrow', + context: 'standalone' + }) + // 1st quarter, 2nd quarter, ... + case 'qqqq': + default: + return localize.quarter(quarter, { + width: 'wide', + context: 'standalone' + }) + } + }, + + // Month + M: function(date, token, localize) { + var month = date.getUTCMonth() + switch (token) { + case 'M': + case 'MM': + return lightFormatters.M(date, token) + // 1st, 2nd, ..., 12th + case 'Mo': + return localize.ordinalNumber(month + 1, { unit: 'month' }) + // Jan, Feb, ..., Dec + case 'MMM': + return localize.month(month, { + width: 'abbreviated', + context: 'formatting' + }) + // J, F, ..., D + case 'MMMMM': + return localize.month(month, { width: 'narrow', context: 'formatting' }) + // January, February, ..., December + case 'MMMM': + default: + return localize.month(month, { width: 'wide', context: 'formatting' }) + } + }, + + // Stand-alone month + L: function(date, token, localize) { + var month = date.getUTCMonth() + switch (token) { + // 1, 2, ..., 12 + case 'L': + return String(month + 1) + // 01, 02, ..., 12 + case 'LL': + return addLeadingZeros(month + 1, 2) + // 1st, 2nd, ..., 12th + case 'Lo': + return localize.ordinalNumber(month + 1, { unit: 'month' }) + // Jan, Feb, ..., Dec + case 'LLL': + return localize.month(month, { + width: 'abbreviated', + context: 'standalone' + }) + // J, F, ..., D + case 'LLLLL': + return localize.month(month, { width: 'narrow', context: 'standalone' }) + // January, February, ..., December + case 'LLLL': + default: + return localize.month(month, { width: 'wide', context: 'standalone' }) + } + }, + + // Local week of year + w: function(date, token, localize, options) { + var week = getUTCWeek(date, options) + + if (token === 'wo') { + return localize.ordinalNumber(week, { unit: 'week' }) + } + + return addLeadingZeros(week, token.length) + }, + + // ISO week of year + I: function(date, token, localize) { + var isoWeek = getUTCISOWeek(date) + + if (token === 'Io') { + return localize.ordinalNumber(isoWeek, { unit: 'week' }) + } + + return addLeadingZeros(isoWeek, token.length) + }, + + // Day of the month + d: function(date, token, localize) { + if (token === 'do') { + return localize.ordinalNumber(date.getUTCDate(), { unit: 'date' }) + } + + return lightFormatters.d(date, token) + }, + + // Day of year + D: function(date, token, localize) { + var dayOfYear = getUTCDayOfYear(date) + + if (token === 'Do') { + return localize.ordinalNumber(dayOfYear, { unit: 'dayOfYear' }) + } + + return addLeadingZeros(dayOfYear, token.length) + }, + + // Day of week + E: function(date, token, localize) { + var dayOfWeek = date.getUTCDay() + switch (token) { + // Tue + case 'E': + case 'EE': + case 'EEE': + return localize.day(dayOfWeek, { + width: 'abbreviated', + context: 'formatting' + }) + // T + case 'EEEEE': + return localize.day(dayOfWeek, { + width: 'narrow', + context: 'formatting' + }) + // Tu + case 'EEEEEE': + return localize.day(dayOfWeek, { + width: 'short', + context: 'formatting' + }) + // Tuesday + case 'EEEE': + default: + return localize.day(dayOfWeek, { width: 'wide', context: 'formatting' }) + } + }, + + // Local day of week + e: function(date, token, localize, options) { + var dayOfWeek = date.getUTCDay() + var localDayOfWeek = (dayOfWeek - options.weekStartsOn + 8) % 7 || 7 + switch (token) { + // Numerical value (Nth day of week with current locale or weekStartsOn) + case 'e': + return String(localDayOfWeek) + // Padded numerical value + case 'ee': + return addLeadingZeros(localDayOfWeek, 2) + // 1st, 2nd, ..., 7th + case 'eo': + return localize.ordinalNumber(localDayOfWeek, { unit: 'day' }) + case 'eee': + return localize.day(dayOfWeek, { + width: 'abbreviated', + context: 'formatting' + }) + // T + case 'eeeee': + return localize.day(dayOfWeek, { + width: 'narrow', + context: 'formatting' + }) + // Tu + case 'eeeeee': + return localize.day(dayOfWeek, { + width: 'short', + context: 'formatting' + }) + // Tuesday + case 'eeee': + default: + return localize.day(dayOfWeek, { width: 'wide', context: 'formatting' }) + } + }, + + // Stand-alone local day of week + c: function(date, token, localize, options) { + var dayOfWeek = date.getUTCDay() + var localDayOfWeek = (dayOfWeek - options.weekStartsOn + 8) % 7 || 7 + switch (token) { + // Numerical value (same as in `e`) + case 'c': + return String(localDayOfWeek) + // Padded numerical value + case 'cc': + return addLeadingZeros(localDayOfWeek, token.length) + // 1st, 2nd, ..., 7th + case 'co': + return localize.ordinalNumber(localDayOfWeek, { unit: 'day' }) + case 'ccc': + return localize.day(dayOfWeek, { + width: 'abbreviated', + context: 'standalone' + }) + // T + case 'ccccc': + return localize.day(dayOfWeek, { + width: 'narrow', + context: 'standalone' + }) + // Tu + case 'cccccc': + return localize.day(dayOfWeek, { + width: 'short', + context: 'standalone' + }) + // Tuesday + case 'cccc': + default: + return localize.day(dayOfWeek, { width: 'wide', context: 'standalone' }) + } + }, + + // ISO day of week + i: function(date, token, localize) { + var dayOfWeek = date.getUTCDay() + var isoDayOfWeek = dayOfWeek === 0 ? 7 : dayOfWeek + switch (token) { + // 2 + case 'i': + return String(isoDayOfWeek) + // 02 + case 'ii': + return addLeadingZeros(isoDayOfWeek, token.length) + // 2nd + case 'io': + return localize.ordinalNumber(isoDayOfWeek, { unit: 'day' }) + // Tue + case 'iii': + return localize.day(dayOfWeek, { + width: 'abbreviated', + context: 'formatting' + }) + // T + case 'iiiii': + return localize.day(dayOfWeek, { + width: 'narrow', + context: 'formatting' + }) + // Tu + case 'iiiiii': + return localize.day(dayOfWeek, { + width: 'short', + context: 'formatting' + }) + // Tuesday + case 'iiii': + default: + return localize.day(dayOfWeek, { width: 'wide', context: 'formatting' }) + } + }, + + // AM or PM + a: function(date, token, localize) { + var hours = date.getUTCHours() + var dayPeriodEnumValue = hours / 12 >= 1 ? 'pm' : 'am' + + switch (token) { + case 'a': + case 'aa': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'abbreviated', + context: 'formatting' + }) + case 'aaa': + return localize + .dayPeriod(dayPeriodEnumValue, { + width: 'abbreviated', + context: 'formatting' + }) + .toLowerCase() + case 'aaaaa': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'narrow', + context: 'formatting' + }) + case 'aaaa': + default: + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'wide', + context: 'formatting' + }) + } + }, + + // AM, PM, midnight, noon + b: function(date, token, localize) { + var hours = date.getUTCHours() + var dayPeriodEnumValue + if (hours === 12) { + dayPeriodEnumValue = dayPeriodEnum.noon + } else if (hours === 0) { + dayPeriodEnumValue = dayPeriodEnum.midnight + } else { + dayPeriodEnumValue = hours / 12 >= 1 ? 'pm' : 'am' + } + + switch (token) { + case 'b': + case 'bb': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'abbreviated', + context: 'formatting' + }) + case 'bbb': + return localize + .dayPeriod(dayPeriodEnumValue, { + width: 'abbreviated', + context: 'formatting' + }) + .toLowerCase() + case 'bbbbb': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'narrow', + context: 'formatting' + }) + case 'bbbb': + default: + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'wide', + context: 'formatting' + }) + } + }, + + // in the morning, in the afternoon, in the evening, at night + B: function(date, token, localize) { + var hours = date.getUTCHours() + var dayPeriodEnumValue + if (hours >= 17) { + dayPeriodEnumValue = dayPeriodEnum.evening + } else if (hours >= 12) { + dayPeriodEnumValue = dayPeriodEnum.afternoon + } else if (hours >= 4) { + dayPeriodEnumValue = dayPeriodEnum.morning + } else { + dayPeriodEnumValue = dayPeriodEnum.night + } + + switch (token) { + case 'B': + case 'BB': + case 'BBB': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'abbreviated', + context: 'formatting' + }) + case 'BBBBB': + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'narrow', + context: 'formatting' + }) + case 'BBBB': + default: + return localize.dayPeriod(dayPeriodEnumValue, { + width: 'wide', + context: 'formatting' + }) + } + }, + + // Hour [1-12] + h: function(date, token, localize) { + if (token === 'ho') { + var hours = date.getUTCHours() % 12 + if (hours === 0) hours = 12 + return localize.ordinalNumber(hours, { unit: 'hour' }) + } + + return lightFormatters.h(date, token) + }, + + // Hour [0-23] + H: function(date, token, localize) { + if (token === 'Ho') { + return localize.ordinalNumber(date.getUTCHours(), { unit: 'hour' }) + } + + return lightFormatters.H(date, token) + }, + + // Hour [0-11] + K: function(date, token, localize) { + var hours = date.getUTCHours() % 12 + + if (token === 'Ko') { + return localize.ordinalNumber(hours, { unit: 'hour' }) + } + + return addLeadingZeros(hours, token.length) + }, + + // Hour [1-24] + k: function(date, token, localize) { + var hours = date.getUTCHours() + if (hours === 0) hours = 24 + + if (token === 'ko') { + return localize.ordinalNumber(hours, { unit: 'hour' }) + } + + return addLeadingZeros(hours, token.length) + }, + + // Minute + m: function(date, token, localize) { + if (token === 'mo') { + return localize.ordinalNumber(date.getUTCMinutes(), { unit: 'minute' }) + } + + return lightFormatters.m(date, token) + }, + + // Second + s: function(date, token, localize) { + if (token === 'so') { + return localize.ordinalNumber(date.getUTCSeconds(), { unit: 'second' }) + } + + return lightFormatters.s(date, token) + }, + + // Fraction of second + S: function(date, token) { + return lightFormatters.S(date, token) + }, + + // Timezone (ISO-8601. If offset is 0, output is always `'Z'`) + X: function(date, token, _localize, options) { + var originalDate = options._originalDate || date + var timezoneOffset = originalDate.getTimezoneOffset() + + if (timezoneOffset === 0) { + return 'Z' + } + + switch (token) { + // Hours and optional minutes + case 'X': + return formatTimezoneWithOptionalMinutes(timezoneOffset) + + // Hours, minutes and optional seconds without `:` delimiter + // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets + // so this token always has the same output as `XX` + case 'XXXX': + case 'XX': // Hours and minutes without `:` delimiter + return formatTimezone(timezoneOffset) + + // Hours, minutes and optional seconds with `:` delimiter + // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets + // so this token always has the same output as `XXX` + case 'XXXXX': + case 'XXX': // Hours and minutes with `:` delimiter + default: + return formatTimezone(timezoneOffset, ':') + } + }, + + // Timezone (ISO-8601. If offset is 0, output is `'+00:00'` or equivalent) + x: function(date, token, _localize, options) { + var originalDate = options._originalDate || date + var timezoneOffset = originalDate.getTimezoneOffset() + + switch (token) { + // Hours and optional minutes + case 'x': + return formatTimezoneWithOptionalMinutes(timezoneOffset) + + // Hours, minutes and optional seconds without `:` delimiter + // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets + // so this token always has the same output as `xx` + case 'xxxx': + case 'xx': // Hours and minutes without `:` delimiter + return formatTimezone(timezoneOffset) + + // Hours, minutes and optional seconds with `:` delimiter + // Note: neither ISO-8601 nor JavaScript supports seconds in timezone offsets + // so this token always has the same output as `xxx` + case 'xxxxx': + case 'xxx': // Hours and minutes with `:` delimiter + default: + return formatTimezone(timezoneOffset, ':') + } + }, + + // Timezone (GMT) + O: function(date, token, _localize, options) { + var originalDate = options._originalDate || date + var timezoneOffset = originalDate.getTimezoneOffset() + + switch (token) { + // Short + case 'O': + case 'OO': + case 'OOO': + return 'GMT' + formatTimezoneShort(timezoneOffset, ':') + // Long + case 'OOOO': + default: + return 'GMT' + formatTimezone(timezoneOffset, ':') + } + }, + + // Timezone (specific non-location) + z: function(date, token, _localize, options) { + var originalDate = options._originalDate || date + var timezoneOffset = originalDate.getTimezoneOffset() + + switch (token) { + // Short + case 'z': + case 'zz': + case 'zzz': + return 'GMT' + formatTimezoneShort(timezoneOffset, ':') + // Long + case 'zzzz': + default: + return 'GMT' + formatTimezone(timezoneOffset, ':') + } + }, + + // Seconds timestamp + t: function(date, token, _localize, options) { + var originalDate = options._originalDate || date + var timestamp = Math.floor(originalDate.getTime() / 1000) + return addLeadingZeros(timestamp, token.length) + }, + + // Milliseconds timestamp + T: function(date, token, _localize, options) { + var originalDate = options._originalDate || date + var timestamp = originalDate.getTime() + return addLeadingZeros(timestamp, token.length) + } +} + +function formatTimezoneShort(offset, dirtyDelimiter) { + var sign = offset > 0 ? '-' : '+' + var absOffset = Math.abs(offset) + var hours = Math.floor(absOffset / 60) + var minutes = absOffset % 60 + if (minutes === 0) { + return sign + String(hours) + } + var delimiter = dirtyDelimiter || '' + return sign + String(hours) + delimiter + addLeadingZeros(minutes, 2) +} + +function formatTimezoneWithOptionalMinutes(offset, dirtyDelimiter) { + if (offset % 60 === 0) { + var sign = offset > 0 ? '-' : '+' + return sign + addLeadingZeros(Math.abs(offset) / 60, 2) + } + return formatTimezone(offset, dirtyDelimiter) +} + +function formatTimezone(offset, dirtyDelimiter) { + var delimiter = dirtyDelimiter || '' + var sign = offset > 0 ? '-' : '+' + var absOffset = Math.abs(offset) + var hours = addLeadingZeros(Math.floor(absOffset / 60), 2) + var minutes = addLeadingZeros(absOffset % 60, 2) + return sign + hours + delimiter + minutes +} + +export default formatters diff --git a/date-fns/src/_lib/format/lightFormatters/index.ts b/date-fns/src/_lib/format/lightFormatters/index.ts new file mode 100644 index 0000000..9e7138e --- /dev/null +++ b/date-fns/src/_lib/format/lightFormatters/index.ts @@ -0,0 +1,94 @@ +import addLeadingZeros from '../../addLeadingZeros/index' + +/* + * | | Unit | | Unit | + * |-----|--------------------------------|-----|--------------------------------| + * | a | AM, PM | A* | | + * | d | Day of month | D | | + * | h | Hour [1-12] | H | Hour [0-23] | + * | m | Minute | M | Month | + * | s | Second | S | Fraction of second | + * | y | Year (abs) | Y | | + * + * Letters marked by * are not implemented but reserved by Unicode standard. + */ + +const formatters = { + // Year + y(date: Date, token: string): string { + // From http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_tokens + // | Year | y | yy | yyy | yyyy | yyyyy | + // |----------|-------|----|-------|-------|-------| + // | AD 1 | 1 | 01 | 001 | 0001 | 00001 | + // | AD 12 | 12 | 12 | 012 | 0012 | 00012 | + // | AD 123 | 123 | 23 | 123 | 0123 | 00123 | + // | AD 1234 | 1234 | 34 | 1234 | 1234 | 01234 | + // | AD 12345 | 12345 | 45 | 12345 | 12345 | 12345 | + + const signedYear = date.getUTCFullYear() + // Returns 1 for 1 BC (which is year 0 in JavaScript) + const year = signedYear > 0 ? signedYear : 1 - signedYear + return addLeadingZeros(token === 'yy' ? year % 100 : year, token.length) + }, + + // Month + M(date: Date, token: string): string { + const month = date.getUTCMonth() + return token === 'M' ? String(month + 1) : addLeadingZeros(month + 1, 2) + }, + + // Day of the month + d(date: Date, token: string): string { + return addLeadingZeros(date.getUTCDate(), token.length) + }, + + // AM or PM + a(date: Date, token: string): string { + const dayPeriodEnumValue = date.getUTCHours() / 12 >= 1 ? 'pm' : 'am' + + switch (token) { + case 'a': + case 'aa': + return dayPeriodEnumValue.toUpperCase() + case 'aaa': + return dayPeriodEnumValue + case 'aaaaa': + return dayPeriodEnumValue[0] + case 'aaaa': + default: + return dayPeriodEnumValue === 'am' ? 'a.m.' : 'p.m.' + } + }, + + // Hour [1-12] + h(date: Date, token: string): string { + return addLeadingZeros(date.getUTCHours() % 12 || 12, token.length) + }, + + // Hour [0-23] + H(date: Date, token: string): string { + return addLeadingZeros(date.getUTCHours(), token.length) + }, + + // Minute + m(date: Date, token: string): string { + return addLeadingZeros(date.getUTCMinutes(), token.length) + }, + + // Second + s(date: Date, token: string): string { + return addLeadingZeros(date.getUTCSeconds(), token.length) + }, + + // Fraction of second + S(date: Date, token: string): string { + const numberOfDigits = token.length + const milliseconds = date.getUTCMilliseconds() + const fractionalSeconds = Math.floor( + milliseconds * Math.pow(10, numberOfDigits - 3) + ) + return addLeadingZeros(fractionalSeconds, token.length) + }, +} + +export default formatters diff --git a/date-fns/src/_lib/format/longFormatters/index.js b/date-fns/src/_lib/format/longFormatters/index.js new file mode 100644 index 0000000..ff84163 --- /dev/null +++ b/date-fns/src/_lib/format/longFormatters/index.js @@ -0,0 +1,66 @@ +function dateLongFormatter(pattern, formatLong) { + switch (pattern) { + case 'P': + return formatLong.date({ width: 'short' }) + case 'PP': + return formatLong.date({ width: 'medium' }) + case 'PPP': + return formatLong.date({ width: 'long' }) + case 'PPPP': + default: + return formatLong.date({ width: 'full' }) + } +} + +function timeLongFormatter(pattern, formatLong) { + switch (pattern) { + case 'p': + return formatLong.time({ width: 'short' }) + case 'pp': + return formatLong.time({ width: 'medium' }) + case 'ppp': + return formatLong.time({ width: 'long' }) + case 'pppp': + default: + return formatLong.time({ width: 'full' }) + } +} + +function dateTimeLongFormatter(pattern, formatLong) { + var matchResult = pattern.match(/(P+)(p+)?/) + var datePattern = matchResult[1] + var timePattern = matchResult[2] + + if (!timePattern) { + return dateLongFormatter(pattern, formatLong) + } + + var dateTimeFormat + + switch (datePattern) { + case 'P': + dateTimeFormat = formatLong.dateTime({ width: 'short' }) + break + case 'PP': + dateTimeFormat = formatLong.dateTime({ width: 'medium' }) + break + case 'PPP': + dateTimeFormat = formatLong.dateTime({ width: 'long' }) + break + case 'PPPP': + default: + dateTimeFormat = formatLong.dateTime({ width: 'full' }) + break + } + + return dateTimeFormat + .replace('{{date}}', dateLongFormatter(datePattern, formatLong)) + .replace('{{time}}', timeLongFormatter(timePattern, formatLong)) +} + +var longFormatters = { + p: timeLongFormatter, + P: dateTimeLongFormatter +} + +export default longFormatters diff --git a/date-fns/src/_lib/getTimezoneOffsetInMilliseconds/index.js b/date-fns/src/_lib/getTimezoneOffsetInMilliseconds/index.js new file mode 100644 index 0000000..0b637c4 --- /dev/null +++ b/date-fns/src/_lib/getTimezoneOffsetInMilliseconds/index.js @@ -0,0 +1,26 @@ +/** + * Google Chrome as of 67.0.3396.87 introduced timezones with offset that includes seconds. + * They usually appear for dates that denote time before the timezones were introduced + * (e.g. for 'Europe/Prague' timezone the offset is GMT+00:57:44 before 1 October 1891 + * and GMT+01:00:00 after that date) + * + * Date#getTimezoneOffset returns the offset in minutes and would return 57 for the example above, + * which would lead to incorrect calculations. + * + * This function returns the timezone offset in milliseconds that takes seconds in account. + */ +export default function getTimezoneOffsetInMilliseconds(date) { + const utcDate = new Date( + Date.UTC( + date.getFullYear(), + date.getMonth(), + date.getDate(), + date.getHours(), + date.getMinutes(), + date.getSeconds(), + date.getMilliseconds() + ) + ) + utcDate.setUTCFullYear(date.getFullYear()) + return date.getTime() - utcDate.getTime() +} diff --git a/date-fns/src/_lib/getTimezoneOffsetInMilliseconds/test.js b/date-fns/src/_lib/getTimezoneOffsetInMilliseconds/test.js new file mode 100644 index 0000000..821e16f --- /dev/null +++ b/date-fns/src/_lib/getTimezoneOffsetInMilliseconds/test.js @@ -0,0 +1,28 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import getTimezoneOffsetInMilliseconds from '.' + +describe('getTimezoneOffsetInMilliseconds', function () { + it('works for a modern date', function () { + var date = new Date(2018, 0 /* Jan */, 1, 12, 34, 56, 789) + var result = date.getTime() - getTimezoneOffsetInMilliseconds(date) + var expectedResult = Date.UTC(2018, 0 /* Jan */, 1, 12, 34, 56, 789) + assert(result === expectedResult) + }) + + it('works for a date before standardized timezones', function () { + var date = new Date(1800, 0 /* Jan */, 1, 12, 34, 56, 789) + var result = date.getTime() - getTimezoneOffsetInMilliseconds(date) + var expectedResult = Date.UTC(1800, 0 /* Jan */, 1, 12, 34, 56, 789) + assert(result === expectedResult) + }) + + it('works for a date BC', function () { + var date = new Date(-500, 0 /* Jan */, 1, 12, 34, 56, 789) + var result = date.getTime() - getTimezoneOffsetInMilliseconds(date) + var expectedResult = Date.UTC(-500, 0 /* Jan */, 1, 12, 34, 56, 789) + assert(result === expectedResult) + }) +}) diff --git a/date-fns/src/_lib/getUTCDayOfYear/index.js b/date-fns/src/_lib/getUTCDayOfYear/index.js new file mode 100644 index 0000000..37cdc0e --- /dev/null +++ b/date-fns/src/_lib/getUTCDayOfYear/index.js @@ -0,0 +1,18 @@ +import toDate from '../../toDate/index' +import requiredArgs from '../requiredArgs/index' + +var MILLISECONDS_IN_DAY = 86400000 + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function getUTCDayOfYear(dirtyDate) { + requiredArgs(1, arguments) + + var date = toDate(dirtyDate) + var timestamp = date.getTime() + date.setUTCMonth(0, 1) + date.setUTCHours(0, 0, 0, 0) + var startOfYearTimestamp = date.getTime() + var difference = timestamp - startOfYearTimestamp + return Math.floor(difference / MILLISECONDS_IN_DAY) + 1 +} diff --git a/date-fns/src/_lib/getUTCDayOfYear/test.js b/date-fns/src/_lib/getUTCDayOfYear/test.js new file mode 100644 index 0000000..b4f2963 --- /dev/null +++ b/date-fns/src/_lib/getUTCDayOfYear/test.js @@ -0,0 +1,36 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import getUTCDayOfYear from '.' + +describe('getUTCDayOfYear', function() { + it('returns the day of the year of the given date', function() { + var result = getUTCDayOfYear(new Date(Date.UTC(2014, 6 /* Jul */, 2))) + assert(result === 183) + }) + + it('accepts a timestamp', function() { + var result = getUTCDayOfYear( + new Date(Date.UTC(2014, 0 /* Jan */, 2)).getTime() + ) + assert(result === 2) + }) + + it('handles dates before 100 AD', function() { + var initialDate = new Date(0) + initialDate.setUTCFullYear(0, 11 /* Dec */, 31) + initialDate.setUTCHours(0, 0, 0, 0) + var result = getUTCDayOfYear(initialDate) + assert(result === 366) + }) + + it('returns NaN if the given date is invalid', function() { + var result = getUTCDayOfYear(new Date(NaN)) + assert(isNaN(result)) + }) + + it('throws TypeError exception if passed less than 1 argument', function() { + assert.throws(getUTCDayOfYear.bind(null), TypeError) + }) +}) diff --git a/date-fns/src/_lib/getUTCISOWeek/index.js b/date-fns/src/_lib/getUTCISOWeek/index.js new file mode 100644 index 0000000..ab17ea2 --- /dev/null +++ b/date-fns/src/_lib/getUTCISOWeek/index.js @@ -0,0 +1,21 @@ +import toDate from '../../toDate/index' +import startOfUTCISOWeek from '../startOfUTCISOWeek/index' +import startOfUTCISOWeekYear from '../startOfUTCISOWeekYear/index' +import requiredArgs from '../requiredArgs/index' + +var MILLISECONDS_IN_WEEK = 604800000 + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function getUTCISOWeek(dirtyDate) { + requiredArgs(1, arguments) + + var date = toDate(dirtyDate) + var diff = + startOfUTCISOWeek(date).getTime() - startOfUTCISOWeekYear(date).getTime() + + // Round the number of days to the nearest integer + // because the number of milliseconds in a week is not constant + // (e.g. it's different in the week of the daylight saving time clock shift) + return Math.round(diff / MILLISECONDS_IN_WEEK) + 1 +} diff --git a/date-fns/src/_lib/getUTCISOWeek/test.js b/date-fns/src/_lib/getUTCISOWeek/test.js new file mode 100644 index 0000000..29dc6b2 --- /dev/null +++ b/date-fns/src/_lib/getUTCISOWeek/test.js @@ -0,0 +1,58 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import getUTCISOWeek from '.' + +describe('getUTCISOWeek', function() { + it('returns the ISO week of the given date', function() { + var result = getUTCISOWeek(new Date(Date.UTC(2005, 0 /* Jan */, 2))) + assert(result === 53) + }) + + it('accepts a timestamp', function() { + var result = getUTCISOWeek( + new Date(Date.UTC(2008, 11 /* Dec */, 29)).getTime() + ) + assert(result === 1) + }) + + describe('edge cases', function() { + it('returns the ISO week at 1 January 2016', function() { + var result = getUTCISOWeek(new Date(Date.UTC(2016, 0 /* Jan */, 1))) + assert(result === 53) + }) + + it('returns the ISO week at 1 May 2016', function() { + var result = getUTCISOWeek(new Date(Date.UTC(2016, 4 /* May */, 1))) + assert(result === 17) + }) + + it('returns the ISO week at 2 May 2016', function() { + var result = getUTCISOWeek(new Date(Date.UTC(2016, 4 /* May */, 2))) + assert(result === 18) + }) + + it('returns the ISO week at 31 May 2016', function() { + var result = getUTCISOWeek(new Date(Date.UTC(2016, 4 /* May */, 31))) + assert(result === 22) + }) + }) + + it('handles dates before 100 AD', function() { + var initialDate = new Date(0) + initialDate.setUTCFullYear(7, 11 /* Dec */, 30) + initialDate.setUTCHours(0, 0, 0, 0) + var result = getUTCISOWeek(initialDate) + assert(result === 52) + }) + + it('returns NaN if the given date is invalid', function() { + var result = getUTCISOWeek(new Date(NaN)) + assert(isNaN(result)) + }) + + it('throws TypeError exception if passed less than 1 argument', function() { + assert.throws(getUTCISOWeek.bind(null), TypeError) + }) +}) diff --git a/date-fns/src/_lib/getUTCISOWeekYear/index.js b/date-fns/src/_lib/getUTCISOWeekYear/index.js new file mode 100644 index 0000000..e098159 --- /dev/null +++ b/date-fns/src/_lib/getUTCISOWeekYear/index.js @@ -0,0 +1,30 @@ +import toDate from '../../toDate/index' +import startOfUTCISOWeek from '../startOfUTCISOWeek/index' +import requiredArgs from '../requiredArgs/index' + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function getUTCISOWeekYear(dirtyDate) { + requiredArgs(1, arguments) + + var date = toDate(dirtyDate) + var year = date.getUTCFullYear() + + var fourthOfJanuaryOfNextYear = new Date(0) + fourthOfJanuaryOfNextYear.setUTCFullYear(year + 1, 0, 4) + fourthOfJanuaryOfNextYear.setUTCHours(0, 0, 0, 0) + var startOfNextYear = startOfUTCISOWeek(fourthOfJanuaryOfNextYear) + + var fourthOfJanuaryOfThisYear = new Date(0) + fourthOfJanuaryOfThisYear.setUTCFullYear(year, 0, 4) + fourthOfJanuaryOfThisYear.setUTCHours(0, 0, 0, 0) + var startOfThisYear = startOfUTCISOWeek(fourthOfJanuaryOfThisYear) + + if (date.getTime() >= startOfNextYear.getTime()) { + return year + 1 + } else if (date.getTime() >= startOfThisYear.getTime()) { + return year + } else { + return year - 1 + } +} diff --git a/date-fns/src/_lib/getUTCISOWeekYear/test.js b/date-fns/src/_lib/getUTCISOWeekYear/test.js new file mode 100644 index 0000000..07aab97 --- /dev/null +++ b/date-fns/src/_lib/getUTCISOWeekYear/test.js @@ -0,0 +1,36 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import getUTCISOWeekYear from '.' + +describe('getUTCISOWeekYear', function() { + it('returns the ISO week-numbering year of the given date', function() { + var result = getUTCISOWeekYear(new Date(Date.UTC(2007, 11 /* Dec */, 31))) + assert(result === 2008) + }) + + it('accepts a timestamp', function() { + var result = getUTCISOWeekYear( + new Date(Date.UTC(2005, 0 /* Jan */, 1)).getTime() + ) + assert(result === 2004) + }) + + it('handles dates before 100 AD', function() { + var initialDate = new Date(0) + initialDate.setUTCFullYear(7, 11 /* Dec */, 31) + initialDate.setUTCHours(0, 0, 0, 0) + var result = getUTCISOWeekYear(initialDate) + assert(result === 8) + }) + + it('returns NaN if the given date is invalid', function() { + var result = getUTCISOWeekYear(new Date(NaN)) + assert(isNaN(result)) + }) + + it('throws TypeError exception if passed less than 1 argument', function() { + assert.throws(getUTCISOWeekYear.bind(null), TypeError) + }) +}) diff --git a/date-fns/src/_lib/getUTCWeek/index.js b/date-fns/src/_lib/getUTCWeek/index.js new file mode 100644 index 0000000..0b69ba2 --- /dev/null +++ b/date-fns/src/_lib/getUTCWeek/index.js @@ -0,0 +1,22 @@ +import toDate from '../../toDate/index' +import startOfUTCWeek from '../startOfUTCWeek/index' +import startOfUTCWeekYear from '../startOfUTCWeekYear/index' +import requiredArgs from '../requiredArgs/index' + +var MILLISECONDS_IN_WEEK = 604800000 + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function getUTCWeek(dirtyDate, options) { + requiredArgs(1, arguments) + + var date = toDate(dirtyDate) + var diff = + startOfUTCWeek(date, options).getTime() - + startOfUTCWeekYear(date, options).getTime() + + // Round the number of days to the nearest integer + // because the number of milliseconds in a week is not constant + // (e.g. it's different in the week of the daylight saving time clock shift) + return Math.round(diff / MILLISECONDS_IN_WEEK) + 1 +} diff --git a/date-fns/src/_lib/getUTCWeek/test.js b/date-fns/src/_lib/getUTCWeek/test.js new file mode 100644 index 0000000..0814368 --- /dev/null +++ b/date-fns/src/_lib/getUTCWeek/test.js @@ -0,0 +1,70 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import getUTCWeek from '.' + +describe('getUTCWeek', function() { + it('returns the local week of year of the given date', function() { + var result = getUTCWeek(new Date(Date.UTC(2005, 0 /* Jan */, 2))) + assert(result === 2) + }) + + it('accepts a timestamp', function() { + var result = getUTCWeek(Date.UTC(2008, 11 /* Dec */, 29)) + assert(result === 1) + }) + + it('handles dates before 100 AD', function() { + var initialDate = new Date(0) + initialDate.setUTCFullYear(7, 11 /* Dec */, 30) + initialDate.setUTCHours(0, 0, 0, 0) + var result = getUTCWeek(initialDate) + assert(result === 1) + }) + + it('returns NaN if the given date is invalid', function() { + var result = getUTCWeek(new Date(NaN)) + assert(isNaN(result)) + }) + + it('allows to specify `weekStartsOn` and `firstWeekContainsDate` in locale', function() { + var date = new Date(Date.UTC(2005, 0 /* Jan */, 2)) + var result = getUTCWeek(date, { + locale: { + options: { weekStartsOn: 1, firstWeekContainsDate: 4 } + } + }) + assert(result === 53) + }) + + it('`options.weekStartsOn` overwrites the first day of the week specified in locale', function() { + var date = new Date(Date.UTC(2005, 0 /* Jan */, 2)) + var result = getUTCWeek(date, { + weekStartsOn: 1, + firstWeekContainsDate: 4, + locale: { + options: { weekStartsOn: 0, firstWeekContainsDate: 1 } + } + }) + assert(result === 53) + }) + + it('throws `RangeError` if `options.weekStartsOn` is not convertable to 0, 1, ..., 6 or undefined', function() { + var block = getUTCWeek.bind(null, new Date(2007, 11 /* Dec */, 31), { + weekStartsOn: NaN + }) + assert.throws(block, RangeError) + }) + + it('throws `RangeError` if `options.firstWeekContainsDate` is not convertable to 1, 2, ..., 7 or undefined', function() { + var block = getUTCWeek.bind(null, new Date(2007, 11 /* Dec */, 31), { + firstWeekContainsDate: NaN + }) + assert.throws(block, RangeError) + }) + + it('throws TypeError exception if passed less than 1 argument', function() { + assert.throws(getUTCWeek.bind(null), TypeError) + }) +}) diff --git a/date-fns/src/_lib/getUTCWeekYear/index.js b/date-fns/src/_lib/getUTCWeekYear/index.js new file mode 100644 index 0000000..1f561c7 --- /dev/null +++ b/date-fns/src/_lib/getUTCWeekYear/index.js @@ -0,0 +1,51 @@ +import toInteger from '../toInteger/index' +import toDate from '../../toDate/index' +import startOfUTCWeek from '../startOfUTCWeek/index' +import requiredArgs from '../requiredArgs/index' + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function getUTCWeekYear(dirtyDate, dirtyOptions) { + requiredArgs(1, arguments) + + var date = toDate(dirtyDate, dirtyOptions) + var year = date.getUTCFullYear() + + var options = dirtyOptions || {} + var locale = options.locale + var localeFirstWeekContainsDate = + locale && locale.options && locale.options.firstWeekContainsDate + var defaultFirstWeekContainsDate = + localeFirstWeekContainsDate == null + ? 1 + : toInteger(localeFirstWeekContainsDate) + var firstWeekContainsDate = + options.firstWeekContainsDate == null + ? defaultFirstWeekContainsDate + : toInteger(options.firstWeekContainsDate) + + // Test if weekStartsOn is between 1 and 7 _and_ is not NaN + if (!(firstWeekContainsDate >= 1 && firstWeekContainsDate <= 7)) { + throw new RangeError( + 'firstWeekContainsDate must be between 1 and 7 inclusively' + ) + } + + var firstWeekOfNextYear = new Date(0) + firstWeekOfNextYear.setUTCFullYear(year + 1, 0, firstWeekContainsDate) + firstWeekOfNextYear.setUTCHours(0, 0, 0, 0) + var startOfNextYear = startOfUTCWeek(firstWeekOfNextYear, dirtyOptions) + + var firstWeekOfThisYear = new Date(0) + firstWeekOfThisYear.setUTCFullYear(year, 0, firstWeekContainsDate) + firstWeekOfThisYear.setUTCHours(0, 0, 0, 0) + var startOfThisYear = startOfUTCWeek(firstWeekOfThisYear, dirtyOptions) + + if (date.getTime() >= startOfNextYear.getTime()) { + return year + 1 + } else if (date.getTime() >= startOfThisYear.getTime()) { + return year + } else { + return year - 1 + } +} diff --git a/date-fns/src/_lib/getUTCWeekYear/test.js b/date-fns/src/_lib/getUTCWeekYear/test.js new file mode 100644 index 0000000..3b45fc4 --- /dev/null +++ b/date-fns/src/_lib/getUTCWeekYear/test.js @@ -0,0 +1,70 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import getUTCWeekYear from '.' + +describe('getUTCWeekYear', function() { + it('returns the local week-numbering year of the given date', function() { + var result = getUTCWeekYear(new Date(Date.UTC(2004, 11 /* Dec */, 26))) + assert(result === 2005) + }) + + it('accepts a timestamp', function() { + var result = getUTCWeekYear(Date.UTC(2000, 11 /* Dec */, 30)) + assert(result === 2000) + }) + + it('handles dates before 100 AD', function() { + var initialDate = new Date(0) + initialDate.setUTCFullYear(7, 11 /* Dec */, 31) + initialDate.setUTCHours(0, 0, 0, 0) + var result = getUTCWeekYear(initialDate) + assert(result === 8) + }) + + it('returns NaN if the given date is invalid', function() { + var result = getUTCWeekYear(new Date(NaN)) + assert(isNaN(result)) + }) + + it('allows to specify `weekStartsOn` and `firstWeekContainsDate` in locale', function() { + var date = new Date(Date.UTC(2004, 11 /* Dec */, 26)) + var result = getUTCWeekYear(date, { + locale: { + options: { weekStartsOn: 1, firstWeekContainsDate: 4 } + } + }) + assert(result === 2004) + }) + + it('`options.weekStartsOn` overwrites the first day of the week specified in locale', function() { + var date = new Date(Date.UTC(2004, 11 /* Dec */, 26)) + var result = getUTCWeekYear(date, { + weekStartsOn: 1, + firstWeekContainsDate: 4, + locale: { + options: { weekStartsOn: 0, firstWeekContainsDate: 1 } + } + }) + assert(result === 2004) + }) + + it('throws `RangeError` if `options.weekStartsOn` is not convertable to 0, 1, ..., 6 or undefined', function() { + var block = getUTCWeekYear.bind(null, new Date(2007, 11 /* Dec */, 31), { + weekStartsOn: NaN + }) + assert.throws(block, RangeError) + }) + + it('throws `RangeError` if `options.firstWeekContainsDate` is not convertable to 1, 2, ..., 7 or undefined', function() { + var block = getUTCWeekYear.bind(null, new Date(2007, 11 /* Dec */, 31), { + firstWeekContainsDate: NaN + }) + assert.throws(block, RangeError) + }) + + it('throws TypeError exception if passed less than 1 argument', function() { + assert.throws(getUTCWeekYear.bind(null), TypeError) + }) +}) diff --git a/date-fns/src/_lib/isSameUTCWeek/index.js b/date-fns/src/_lib/isSameUTCWeek/index.js new file mode 100644 index 0000000..699806f --- /dev/null +++ b/date-fns/src/_lib/isSameUTCWeek/index.js @@ -0,0 +1,13 @@ +import startOfUTCWeek from '../startOfUTCWeek/index' +import requiredArgs from '../requiredArgs/index' + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function isSameUTCWeek(dirtyDateLeft, dirtyDateRight, options) { + requiredArgs(2, arguments) + + var dateLeftStartOfWeek = startOfUTCWeek(dirtyDateLeft, options) + var dateRightStartOfWeek = startOfUTCWeek(dirtyDateRight, options) + + return dateLeftStartOfWeek.getTime() === dateRightStartOfWeek.getTime() +} diff --git a/date-fns/src/_lib/isSameUTCWeek/test.js b/date-fns/src/_lib/isSameUTCWeek/test.js new file mode 100644 index 0000000..909d034 --- /dev/null +++ b/date-fns/src/_lib/isSameUTCWeek/test.js @@ -0,0 +1,111 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import isSameUTCWeek from '.' + +describe('isSameUTCWeek', function() { + it('returns true if the given dates have the same week', function() { + var result = isSameUTCWeek( + new Date(Date.UTC(2014, 7 /* Aug */, 31)), + new Date(Date.UTC(2014, 8 /* Sep */, 4)) + ) + assert(result === true) + }) + + it('returns false if the given dates have different weeks', function() { + var result = isSameUTCWeek( + new Date(Date.UTC(2014, 7 /* Aug */, 30)), + new Date(Date.UTC(2014, 8 /* Sep */, 4)) + ) + assert(result === false) + }) + + it('allows to specify which day is the first day of the week', function() { + var result = isSameUTCWeek( + new Date(Date.UTC(2014, 7 /* Aug */, 31)), + new Date(Date.UTC(2014, 8 /* Sep */, 4)), + { weekStartsOn: 1 } + ) + assert(result === false) + }) + + it('allows to specify which day is the first day of the week in locale', function() { + var result = isSameUTCWeek( + new Date(Date.UTC(2014, 7 /* Aug */, 31)), + new Date(Date.UTC(2014, 8 /* Sep */, 4)), + { + locale: { + options: { weekStartsOn: 1 } + } + } + ) + assert(result === false) + }) + + it('`options.weekStartsOn` overwrites the first day of the week specified in locale', function() { + var result = isSameUTCWeek( + new Date(Date.UTC(2014, 7 /* Aug */, 31)), + new Date(Date.UTC(2014, 8 /* Sep */, 4)), + { + weekStartsOn: 1, + locale: { + options: { weekStartsOn: 0 } + } + } + ) + assert(result === false) + }) + + it('implicitly converts options', function() { + var result = isSameUTCWeek( + new Date(Date.UTC(2014, 7 /* Aug */, 31)), + new Date(Date.UTC(2014, 8 /* Sep */, 4)), + { weekStartsOn: '1' } + ) + assert(result === false) + }) + + it('accepts a timestamp', function() { + var result = isSameUTCWeek( + Date.UTC(2014, 7 /* Aug */, 31), + Date.UTC(2014, 8 /* Sep */, 4) + ) + assert(result === true) + }) + + it('returns false if the first date is `Invalid Date`', function() { + var result = isSameUTCWeek( + new Date(NaN), + new Date(Date.UTC(1989, 6 /* Jul */, 10)) + ) + assert(result === false) + }) + + it('returns false if the second date is `Invalid Date`', function() { + var result = isSameUTCWeek( + new Date(Date.UTC(1987, 1 /* Feb */, 11)), + new Date(NaN) + ) + assert(result === false) + }) + + it('returns false if the both dates are `Invalid Date`', function() { + var result = isSameUTCWeek(new Date(NaN), new Date(NaN)) + assert(result === false) + }) + + it('throws `RangeError` if `options.weekStartsOn` is not convertable to 0, 1, ..., 6 or undefined', function() { + var block = isSameUTCWeek.bind( + null, + new Date(Date.UTC(2014, 7 /* Aug */, 31)), + new Date(Date.UTC(2014, 8 /* Sep */, 4)), + { weekStartsOn: NaN } + ) + assert.throws(block, RangeError) + }) + + it('throws TypeError exception if passed less than 1 argument', function() { + assert.throws(isSameUTCWeek.bind(null, 1), TypeError) + }) +}) diff --git a/date-fns/src/_lib/protectedTokens/index.js b/date-fns/src/_lib/protectedTokens/index.js new file mode 100644 index 0000000..c62313f --- /dev/null +++ b/date-fns/src/_lib/protectedTokens/index.js @@ -0,0 +1,30 @@ +var protectedDayOfYearTokens = ['D', 'DD'] +var protectedWeekYearTokens = ['YY', 'YYYY'] + +export function isProtectedDayOfYearToken(token) { + return protectedDayOfYearTokens.indexOf(token) !== -1 +} + +export function isProtectedWeekYearToken(token) { + return protectedWeekYearTokens.indexOf(token) !== -1 +} + +export function throwProtectedError(token, format, input) { + if (token === 'YYYY') { + throw new RangeError( + `Use \`yyyy\` instead of \`YYYY\` (in \`${format}\`) for formatting years to the input \`${input}\`; see: https://git.io/fxCyr` + ) + } else if (token === 'YY') { + throw new RangeError( + `Use \`yy\` instead of \`YY\` (in \`${format}\`) for formatting years to the input \`${input}\`; see: https://git.io/fxCyr` + ) + } else if (token === 'D') { + throw new RangeError( + `Use \`d\` instead of \`D\` (in \`${format}\`) for formatting days of the month to the input \`${input}\`; see: https://git.io/fxCyr` + ) + } else if (token === 'DD') { + throw new RangeError( + `Use \`dd\` instead of \`DD\` (in \`${format}\`) for formatting days of the month to the input \`${input}\`; see: https://git.io/fxCyr` + ) + } +} diff --git a/date-fns/src/_lib/requiredArgs/index.ts b/date-fns/src/_lib/requiredArgs/index.ts new file mode 100644 index 0000000..bdbb950 --- /dev/null +++ b/date-fns/src/_lib/requiredArgs/index.ts @@ -0,0 +1,12 @@ +export default function requiredArgs(required: number, args: IArguments) { + if (args.length < required) { + throw new TypeError( + required + + ' argument' + + (required > 1 ? 's' : '') + + ' required, but only ' + + args.length + + ' present' + ) + } +} diff --git a/date-fns/src/_lib/requiredArgs/test.js b/date-fns/src/_lib/requiredArgs/test.js new file mode 100644 index 0000000..a6cbe4a --- /dev/null +++ b/date-fns/src/_lib/requiredArgs/test.js @@ -0,0 +1,37 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import requiredArgs from '.' + +describe('requiredArgs', function () { + function wrapperFn(required) { + // $ExpectedMistake + return function () { + requiredArgs(required, arguments) + } + } + const twoArgsRequired = wrapperFn(2) + + describe('with correct number of passed arguments', function () { + it('does not throw an error', function () { + assert.doesNotThrow(() => twoArgsRequired(1, 2)) + }) + }) + + describe('with wrong number of arguments', function () { + it('throws correct error message', function () { + assert.throws( + function () { + twoArgsRequired(1) + }, + function (err) { + return ( + err instanceof TypeError && + err.message === '2 arguments required, but only 1 present' + ) + } + ) + }) + }) +}) diff --git a/date-fns/src/_lib/setUTCDay/index.js b/date-fns/src/_lib/setUTCDay/index.js new file mode 100644 index 0000000..6e4e472 --- /dev/null +++ b/date-fns/src/_lib/setUTCDay/index.js @@ -0,0 +1,38 @@ +import toInteger from '../toInteger/index' +import toDate from '../../toDate/index' +import requiredArgs from '../requiredArgs/index' + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function setUTCDay(dirtyDate, dirtyDay, dirtyOptions) { + requiredArgs(2, arguments) + + var options = dirtyOptions || {} + var locale = options.locale + var localeWeekStartsOn = + locale && locale.options && locale.options.weekStartsOn + var defaultWeekStartsOn = + localeWeekStartsOn == null ? 0 : toInteger(localeWeekStartsOn) + var weekStartsOn = + options.weekStartsOn == null + ? defaultWeekStartsOn + : toInteger(options.weekStartsOn) + + // Test if weekStartsOn is between 0 and 6 _and_ is not NaN + if (!(weekStartsOn >= 0 && weekStartsOn <= 6)) { + throw new RangeError('weekStartsOn must be between 0 and 6 inclusively') + } + + var date = toDate(dirtyDate) + var day = toInteger(dirtyDay) + + var currentDay = date.getUTCDay() + + var remainder = day % 7 + var dayIndex = (remainder + 7) % 7 + + var diff = (dayIndex < weekStartsOn ? 7 : 0) + day - currentDay + + date.setUTCDate(date.getUTCDate() + diff) + return date +} diff --git a/date-fns/src/_lib/setUTCDay/test.js b/date-fns/src/_lib/setUTCDay/test.js new file mode 100644 index 0000000..a34074b --- /dev/null +++ b/date-fns/src/_lib/setUTCDay/test.js @@ -0,0 +1,132 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import setUTCDay from '.' + +describe('setUTCDay', function () { + it('sets the day of the week', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 0) + assert.deepEqual(result, new Date(Date.UTC(2014, 7 /* Aug */, 31))) + }) + + it('allows to specify which day is the first day of the week', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 0, { + weekStartsOn: 1, + }) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 7))) + }) + + it('allows to specify which day is the first day of the week in locale', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 0, { + locale: { + options: { weekStartsOn: 1 }, + }, + }) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 7))) + }) + + it('`options.weekStartsOn` overwrites the first day of the week specified in locale', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 0, { + weekStartsOn: 1, + locale: { + options: { weekStartsOn: 0 }, + }, + }) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 7))) + }) + + describe('the day index is more than 6', function () { + it('sets the day of the next week', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 8) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 8))) + }) + + it('allows to specify which day is the first day of the week', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 7, { + weekStartsOn: 1, + }) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 14))) + }) + + it('sets the day of another week in the future', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 14, { + weekStartsOn: 1, + }) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 21))) + }) + }) + + describe('the day index is less than 0', function () { + it('sets the day of the last week', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), -6) + assert.deepEqual(result, new Date(Date.UTC(2014, 7 /* Aug */, 25))) + }) + + it('allows to specify which day is the first day of the week', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), -7, { + weekStartsOn: 1, + }) + assert.deepEqual(result, new Date(Date.UTC(2014, 7 /* Aug */, 31))) + }) + + it('set the day of another week in the past', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), -14, { + weekStartsOn: 1, + }) + assert.deepEqual(result, new Date(Date.UTC(2014, 7 /* Aug */, 24))) + }) + }) + + it('accepts a timestamp', function () { + var result = setUTCDay( + new Date(Date.UTC(2014, 8 /* Sep */, 1)).getTime(), + 3 + ) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 3))) + }) + + it('converts a fractional number to an integer', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 0.9) + assert.deepEqual(result, new Date(Date.UTC(2014, 7 /* Aug */, 31))) + }) + + it('implicitly converts number arguments', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), '0') + assert.deepEqual(result, new Date(Date.UTC(2014, 7 /* Aug */, 31))) + }) + + it('implicitly converts options', function () { + var result = setUTCDay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 0, { + weekStartsOn: '1', + }) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 7))) + }) + + it('does not mutate the original date', function () { + var date = new Date(Date.UTC(2014, 8 /* Sep */, 1)) + setUTCDay(date, 3) + assert.deepEqual(date, new Date(Date.UTC(2014, 8 /* Sep */, 1))) + }) + + it('returns `Invalid Date` if the given date is invalid', function () { + var result = setUTCDay(new Date(NaN), 0) + assert(result instanceof Date && isNaN(result)) + }) + + it('returns `Invalid Date` if the given amount is NaN', function () { + var result = setUTCDay(new Date(2014, 8 /* Sep */, 1), NaN) + assert(result instanceof Date && isNaN(result)) + }) + + it('throws `RangeError` if `options.weekStartsOn` is not convertable to 0, 1, ..., 6 or undefined', function () { + var block = setUTCDay.bind(null, new Date(2014, 8 /* Sep */, 1), 0, { + weekStartsOn: NaN, + }) + assert.throws(block, RangeError) + }) + + it('throws TypeError exception if passed less than 1 argument', function () { + assert.throws(setUTCDay.bind(null, 1), TypeError) + }) +}) diff --git a/date-fns/src/_lib/setUTCISODay/index.js b/date-fns/src/_lib/setUTCISODay/index.js new file mode 100644 index 0000000..cbd2fbc --- /dev/null +++ b/date-fns/src/_lib/setUTCISODay/index.js @@ -0,0 +1,27 @@ +import toInteger from '../toInteger/index' +import toDate from '../../toDate/index' +import requiredArgs from '../requiredArgs/index' + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function setUTCISODay(dirtyDate, dirtyDay) { + requiredArgs(2, arguments) + + var day = toInteger(dirtyDay) + + if (day % 7 === 0) { + day = day - 7 + } + + var weekStartsOn = 1 + var date = toDate(dirtyDate) + var currentDay = date.getUTCDay() + + var remainder = day % 7 + var dayIndex = (remainder + 7) % 7 + + var diff = (dayIndex < weekStartsOn ? 7 : 0) + day - currentDay + + date.setUTCDate(date.getUTCDate() + diff) + return date +} diff --git a/date-fns/src/_lib/setUTCISODay/test.js b/date-fns/src/_lib/setUTCISODay/test.js new file mode 100644 index 0000000..11b6019 --- /dev/null +++ b/date-fns/src/_lib/setUTCISODay/test.js @@ -0,0 +1,79 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import setUTCISODay from '.' + +describe('setUTCISODay', function () { + it('sets the day of the ISO week', function () { + var result = setUTCISODay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 3) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 3))) + }) + + it('sets the day to Sunday of this ISO week if the index is 7', function () { + var result = setUTCISODay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 7) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 7))) + }) + + describe('the day index is more than 7', function () { + it('sets the day of the next ISO week', function () { + var result = setUTCISODay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 8) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 8))) + }) + + it('sets the day of another ISO week in the future', function () { + var result = setUTCISODay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 21) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 21))) + }) + }) + + describe('the day index is less than 1', function () { + it('sets the day of the last ISO week', function () { + var result = setUTCISODay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 0) + assert.deepEqual(result, new Date(Date.UTC(2014, 7 /* Aug */, 31))) + }) + + it('set the day of another ISO week in the past', function () { + var result = setUTCISODay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), -13) + assert.deepEqual(result, new Date(Date.UTC(2014, 7 /* Aug */, 18))) + }) + }) + + it('accepts a timestamp', function () { + var result = setUTCISODay( + new Date(Date.UTC(2014, 8 /* Sep */, 1)).getTime(), + 3 + ) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 3))) + }) + + it('converts a fractional number to an integer', function () { + var result = setUTCISODay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), 3.33) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 3))) + }) + + it('implicitly converts number arguments', function () { + var result = setUTCISODay(new Date(Date.UTC(2014, 8 /* Sep */, 1)), '3') + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 3))) + }) + + it('does not mutate the original date', function () { + var date = new Date(Date.UTC(2014, 8 /* Sep */, 1)) + setUTCISODay(date, 3) + assert.deepEqual(date, new Date(Date.UTC(2014, 8 /* Sep */, 1))) + }) + + it('returns `Invalid Date` if the given date is invalid', function () { + var result = setUTCISODay(new Date(NaN), 3) + assert(result instanceof Date && isNaN(result)) + }) + + it('returns `Invalid Date` if the given amount is NaN', function () { + var result = setUTCISODay(new Date(2014, 8 /* Sep */, 1), NaN) + assert(result instanceof Date && isNaN(result)) + }) + + it('throws TypeError exception if passed less than 1 argument', function () { + assert.throws(setUTCISODay.bind(null, 1), TypeError) + }) +}) diff --git a/date-fns/src/_lib/setUTCISOWeek/index.js b/date-fns/src/_lib/setUTCISOWeek/index.js new file mode 100644 index 0000000..99ce6da --- /dev/null +++ b/date-fns/src/_lib/setUTCISOWeek/index.js @@ -0,0 +1,16 @@ +import toInteger from '../toInteger/index' +import toDate from '../../toDate/index' +import getUTCISOWeek from '../getUTCISOWeek/index' +import requiredArgs from '../requiredArgs/index' + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function setUTCISOWeek(dirtyDate, dirtyISOWeek) { + requiredArgs(2, arguments) + + var date = toDate(dirtyDate) + var isoWeek = toInteger(dirtyISOWeek) + var diff = getUTCISOWeek(date) - isoWeek + date.setUTCDate(date.getUTCDate() - diff * 7) + return date +} diff --git a/date-fns/src/_lib/setUTCISOWeek/test.js b/date-fns/src/_lib/setUTCISOWeek/test.js new file mode 100644 index 0000000..07b7276 --- /dev/null +++ b/date-fns/src/_lib/setUTCISOWeek/test.js @@ -0,0 +1,61 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import setUTCISOWeek from '.' + +describe('setUTCISOWeek', function() { + it('sets the ISO week', function() { + var result = setUTCISOWeek(new Date(Date.UTC(2004, 7 /* Aug */, 7)), 53) + assert.deepEqual(result, new Date(Date.UTC(2005, 0 /* Jan */, 1))) + }) + + it('accepts a timestamp', function() { + var result = setUTCISOWeek( + new Date(Date.UTC(2009, 11 /* Dec */, 2)).getTime(), + 1 + ) + assert.deepEqual(result, new Date(Date.UTC(2008, 11 /* Dec */, 31))) + }) + + it('converts a fractional number to an integer', function() { + var result = setUTCISOWeek(new Date(Date.UTC(2004, 7 /* Aug */, 7)), 53.53) + assert.deepEqual(result, new Date(Date.UTC(2005, 0 /* Jan */, 1))) + }) + + it('implicitly converts number arguments', function() { + var result = setUTCISOWeek(new Date(Date.UTC(2004, 7 /* Aug */, 7)), '53') + assert.deepEqual(result, new Date(Date.UTC(2005, 0 /* Jan */, 1))) + }) + + it('does not mutate the original date', function() { + var date = new Date(Date.UTC(2014, 6 /* Jul */, 2)) + setUTCISOWeek(date, 52) + assert.deepEqual(date, new Date(Date.UTC(2014, 6 /* Jul */, 2))) + }) + + it('handles dates before 100 AD', function() { + var initialDate = new Date(0) + initialDate.setUTCFullYear(4, 0 /* Jan */, 4) + initialDate.setUTCHours(0, 0, 0, 0) + var expectedResult = new Date(0) + expectedResult.setUTCFullYear(4, 11 /* Dec */, 26) + expectedResult.setUTCHours(0, 0, 0, 0) + var result = setUTCISOWeek(initialDate, 52) + assert.deepEqual(result, expectedResult) + }) + + it('returns `Invalid Date` if the given date is invalid', function() { + var result = setUTCISOWeek(new Date(NaN), 53) + assert(result instanceof Date && isNaN(result)) + }) + + it('returns `Invalid Date` if the given amount is NaN', function() { + var result = setUTCISOWeek(new Date(2004, 7 /* Aug */, 7), NaN) + assert(result instanceof Date && isNaN(result)) + }) + + it('throws TypeError exception if passed less than 1 argument', function() { + assert.throws(setUTCISOWeek.bind(null, 1), TypeError) + }) +}) diff --git a/date-fns/src/_lib/setUTCWeek/index.js b/date-fns/src/_lib/setUTCWeek/index.js new file mode 100644 index 0000000..606d817 --- /dev/null +++ b/date-fns/src/_lib/setUTCWeek/index.js @@ -0,0 +1,16 @@ +import toInteger from '../toInteger/index' +import toDate from '../../toDate/index' +import getUTCWeek from '../getUTCWeek/index' +import requiredArgs from '../requiredArgs/index' + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function setUTCWeek(dirtyDate, dirtyWeek, options) { + requiredArgs(2, arguments) + + var date = toDate(dirtyDate) + var week = toInteger(dirtyWeek) + var diff = getUTCWeek(date, options) - week + date.setUTCDate(date.getUTCDate() - diff * 7) + return date +} diff --git a/date-fns/src/_lib/setUTCWeek/test.js b/date-fns/src/_lib/setUTCWeek/test.js new file mode 100644 index 0000000..58aea10 --- /dev/null +++ b/date-fns/src/_lib/setUTCWeek/test.js @@ -0,0 +1,95 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import setUTCWeek from '.' + +describe('setUTCWeek', function() { + it('sets the local week', function() { + var result = setUTCWeek(new Date(Date.UTC(2005, 0 /* Jan */, 2)), 1) + assert.deepEqual(result, new Date(Date.UTC(2004, 11 /* Dec */, 26))) + }) + + it('accepts a timestamp', function() { + var result = setUTCWeek(Date.UTC(2009, 11 /* Dec */, 2), 1) + assert.deepEqual(result, new Date(Date.UTC(2008, 11 /* Dec */, 31))) + }) + + it('converts a fractional number to an integer', function() { + var result = setUTCWeek(new Date(Date.UTC(2005, 0 /* Jan */, 2)), 1.1) + assert.deepEqual(result, new Date(Date.UTC(2004, 11 /* Dec */, 26))) + }) + + it('implicitly converts number arguments', function() { + var result = setUTCWeek(new Date(Date.UTC(2004, 7 /* Aug */, 7)), '53') + assert.deepEqual(result, new Date(Date.UTC(2005, 0 /* Jan */, 1))) + }) + + it('does not mutate the original date', function() { + var date = new Date(2014, 6 /* Jul */, 2) + setUTCWeek(date, 52) + assert.deepEqual(date, new Date(2014, 6 /* Jul */, 2)) + }) + + it('handles dates before 100 AD', function() { + var initialDate = new Date(0) + initialDate.setUTCFullYear(4, 0 /* Jan */, 4) + initialDate.setUTCHours(0, 0, 0, 0) + var expectedResult = new Date(0) + expectedResult.setUTCFullYear(4, 11 /* Dec */, 19) + expectedResult.setUTCHours(0, 0, 0, 0) + var result = setUTCWeek(initialDate, 52) + assert.deepEqual(result, expectedResult) + }) + + it('returns `Invalid Date` if the given date is invalid', function() { + var result = setUTCWeek(new Date(NaN), 53) + assert(result instanceof Date && isNaN(result)) + }) + + it('returns `Invalid Date` if the given amount is NaN', function() { + var result = setUTCWeek(new Date(2004, 7 /* Aug */, 7), NaN) + assert(result instanceof Date && isNaN(result)) + }) + + it('allows to specify `weekStartsOn` and `firstWeekContainsDate` in locale', function() { + var date = new Date(Date.UTC(2005, 0 /* Jan */, 2)) + var result = setUTCWeek(date, 1, { + locale: { + options: { weekStartsOn: 1, firstWeekContainsDate: 4 } + } + }) + assert.deepEqual(result, new Date(Date.UTC(2004, 0 /* Jan */, 4))) + }) + + it('`options.weekStartsOn` overwrites the first day of the week specified in locale', function() { + var date = new Date(Date.UTC(2005, 0 /* Jan */, 2)) + var result = setUTCWeek(date, 1, { + weekStartsOn: 1, + firstWeekContainsDate: 4, + locale: { + options: { weekStartsOn: 0, firstWeekContainsDate: 1 } + } + }) + assert.deepEqual(result, new Date(Date.UTC(2004, 0 /* Jan */, 4))) + }) + + it('throws `RangeError` if `options.weekStartsOn` is not convertable to 0, 1, ..., 6 or undefined', function() { + var block = setUTCWeek.bind(null, new Date(2004, 7 /* Aug */, 7), 53, { + weekStartsOn: NaN + }) + assert.throws(block, RangeError) + }) + + it('throws `RangeError` if `options.firstWeekContainsDate` is not convertable to 1, 2, ..., 7 or undefined', function() { + var block = setUTCWeek.bind(null, new Date(2004, 7 /* Aug */, 7), 53, { + firstWeekContainsDate: NaN + }) + assert.throws(block, RangeError) + }) + + it('throws TypeError exception if passed less than 2 arguments', function() { + assert.throws(setUTCWeek.bind(null), TypeError) + assert.throws(setUTCWeek.bind(null, 1), TypeError) + }) +}) diff --git a/date-fns/src/_lib/startOfUTCISOWeek/index.js b/date-fns/src/_lib/startOfUTCISOWeek/index.js new file mode 100644 index 0000000..4633c38 --- /dev/null +++ b/date-fns/src/_lib/startOfUTCISOWeek/index.js @@ -0,0 +1,18 @@ +import toDate from '../../toDate/index' +import requiredArgs from '../requiredArgs/index' + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function startOfUTCISOWeek(dirtyDate) { + requiredArgs(1, arguments) + + var weekStartsOn = 1 + + var date = toDate(dirtyDate) + var day = date.getUTCDay() + var diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn + + date.setUTCDate(date.getUTCDate() - diff) + date.setUTCHours(0, 0, 0, 0) + return date +} diff --git a/date-fns/src/_lib/startOfUTCISOWeek/test.js b/date-fns/src/_lib/startOfUTCISOWeek/test.js new file mode 100644 index 0000000..1c93535 --- /dev/null +++ b/date-fns/src/_lib/startOfUTCISOWeek/test.js @@ -0,0 +1,34 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import startOfUTCISOWeek from '.' + +describe('startOfUTCISOWeek', function() { + it('returns the date with the time set to 00:00:00 and the date set to the first day of an ISO week', function() { + var date = new Date(Date.UTC(2014, 8 /* Sep */, 2, 11, 55, 0)) + var result = startOfUTCISOWeek(date) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 1))) + }) + + it('accepts a timestamp', function() { + var date = new Date(Date.UTC(2014, 1 /* Feb */, 11, 11, 55, 0)).getTime() + var result = startOfUTCISOWeek(date) + assert.deepEqual(result, new Date(Date.UTC(2014, 1 /* Feb */, 10))) + }) + + it('does not mutate the original date', function() { + var date = new Date(Date.UTC(2014, 8 /* Sep */, 2, 11, 55, 0)) + startOfUTCISOWeek(date) + assert.deepEqual(date, new Date(Date.UTC(2014, 8 /* Sep */, 2, 11, 55, 0))) + }) + + it('returns `Invalid Date` if the given date is invalid', function() { + var result = startOfUTCISOWeek(new Date(NaN)) + assert(result instanceof Date && isNaN(result)) + }) + + it('throws TypeError exception if passed less than 1 argument', function() { + assert.throws(startOfUTCISOWeek.bind(null), TypeError) + }) +}) diff --git a/date-fns/src/_lib/startOfUTCISOWeekYear/index.js b/date-fns/src/_lib/startOfUTCISOWeekYear/index.js new file mode 100644 index 0000000..db3313c --- /dev/null +++ b/date-fns/src/_lib/startOfUTCISOWeekYear/index.js @@ -0,0 +1,16 @@ +import getUTCISOWeekYear from '../getUTCISOWeekYear/index' +import startOfUTCISOWeek from '../startOfUTCISOWeek/index' +import requiredArgs from '../requiredArgs/index' + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function startOfUTCISOWeekYear(dirtyDate) { + requiredArgs(1, arguments) + + var year = getUTCISOWeekYear(dirtyDate) + var fourthOfJanuary = new Date(0) + fourthOfJanuary.setUTCFullYear(year, 0, 4) + fourthOfJanuary.setUTCHours(0, 0, 0, 0) + var date = startOfUTCISOWeek(fourthOfJanuary) + return date +} diff --git a/date-fns/src/_lib/startOfUTCISOWeekYear/test.js b/date-fns/src/_lib/startOfUTCISOWeekYear/test.js new file mode 100644 index 0000000..5d0485f --- /dev/null +++ b/date-fns/src/_lib/startOfUTCISOWeekYear/test.js @@ -0,0 +1,58 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import startOfUTCISOWeekYear from '.' + +describe('startOfUTCISOWeekYear', function() { + it('returns the date with the time set to 00:00:00 and the date set to the first day of an ISO year', function() { + var result = startOfUTCISOWeekYear( + new Date(Date.UTC(2009, 0 /* Jan */, 1, 16, 0)) + ) + assert.deepEqual( + result, + new Date(Date.UTC(2008, 11 /* Dec */, 29, 0, 0, 0, 0)) + ) + }) + + it('accepts a timestamp', function() { + var result = startOfUTCISOWeekYear( + new Date(Date.UTC(2005, 0 /* Jan */, 1, 6, 0)).getTime() + ) + assert.deepEqual( + result, + new Date(Date.UTC(2003, 11 /* Dec */, 29, 0, 0, 0, 0)) + ) + }) + + it('does not mutate the original date', function() { + var date = new Date(Date.UTC(2014, 6 /* Jul */, 2)) + startOfUTCISOWeekYear(date) + assert.deepEqual(date, new Date(Date.UTC(2014, 6 /* Jul */, 2))) + }) + + it('handles dates before 100 AD', function() { + var initialDate = new Date(0) + initialDate.setUTCFullYear(9, 0 /* Jan */, 1) + initialDate.setUTCHours(0, 0, 0, 0) + var expectedResult = new Date(0) + expectedResult.setUTCFullYear(8, 11 /* Dec */, 29) + expectedResult.setUTCHours(0, 0, 0, 0) + var result = startOfUTCISOWeekYear(initialDate) + assert.deepEqual(result, expectedResult) + }) + + it('correctly handles years in which 4 January is Sunday', function() { + var result = startOfUTCISOWeekYear(new Date(Date.UTC(2009, 6 /* Jul */, 2))) + assert.deepEqual(result, new Date(Date.UTC(2008, 11 /* Dec */, 29))) + }) + + it('returns `Invalid Date` if the given date is invalid', function() { + var result = startOfUTCISOWeekYear(new Date(NaN)) + assert(result instanceof Date && isNaN(result)) + }) + + it('throws TypeError exception if passed less than 1 argument', function() { + assert.throws(startOfUTCISOWeekYear.bind(null), TypeError) + }) +}) diff --git a/date-fns/src/_lib/startOfUTCWeek/index.js b/date-fns/src/_lib/startOfUTCWeek/index.js new file mode 100644 index 0000000..fb5db75 --- /dev/null +++ b/date-fns/src/_lib/startOfUTCWeek/index.js @@ -0,0 +1,33 @@ +import toInteger from '../toInteger/index' +import toDate from '../../toDate/index' +import requiredArgs from '../requiredArgs/index' + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function startOfUTCWeek(dirtyDate, dirtyOptions) { + requiredArgs(1, arguments) + + var options = dirtyOptions || {} + var locale = options.locale + var localeWeekStartsOn = + locale && locale.options && locale.options.weekStartsOn + var defaultWeekStartsOn = + localeWeekStartsOn == null ? 0 : toInteger(localeWeekStartsOn) + var weekStartsOn = + options.weekStartsOn == null + ? defaultWeekStartsOn + : toInteger(options.weekStartsOn) + + // Test if weekStartsOn is between 0 and 6 _and_ is not NaN + if (!(weekStartsOn >= 0 && weekStartsOn <= 6)) { + throw new RangeError('weekStartsOn must be between 0 and 6 inclusively') + } + + var date = toDate(dirtyDate) + var day = date.getUTCDay() + var diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn + + date.setUTCDate(date.getUTCDate() - diff) + date.setUTCHours(0, 0, 0, 0) + return date +} diff --git a/date-fns/src/_lib/startOfUTCWeek/test.js b/date-fns/src/_lib/startOfUTCWeek/test.js new file mode 100644 index 0000000..15680f0 --- /dev/null +++ b/date-fns/src/_lib/startOfUTCWeek/test.js @@ -0,0 +1,108 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import startOfUTCWeek from '.' + +describe('startOfUTCWeek', function () { + it('returns the date with the time set to 00:00:00 and the date set to the first day of a week', function () { + var date = new Date(Date.UTC(2014, 8 /* Sep */, 2, 11, 55, 0)) + var result = startOfUTCWeek(date) + assert.deepEqual(result, new Date(Date.UTC(2014, 7 /* Aug */, 31))) + }) + + it('allows to specify which day is the first day of the week', function () { + var date = new Date(Date.UTC(2014, 8 /* Sep */, 2, 11, 55, 0)) + var result = startOfUTCWeek(date, { weekStartsOn: 1 }) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 1))) + }) + + it('allows to specify which day is the first day of the week in locale', function () { + var date = new Date(Date.UTC(2014, 8 /* Sep */, 2, 11, 55, 0)) + var result = startOfUTCWeek(date, { + locale: { + options: { weekStartsOn: 1 }, + }, + }) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 1))) + }) + + it('`options.weekStartsOn` overwrites the first day of the week specified in locale', function () { + var date = new Date(Date.UTC(2014, 8 /* Sep */, 2, 11, 55, 0)) + var result = startOfUTCWeek(date, { + weekStartsOn: 1, + locale: { + options: { weekStartsOn: 0 }, + }, + }) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 1))) + }) + + it('implicitly converts options', function () { + var date = new Date(Date.UTC(2014, 8 /* Sep */, 2, 11, 55, 0)) + var result = startOfUTCWeek(date, { weekStartsOn: '1' }) + assert.deepEqual(result, new Date(Date.UTC(2014, 8 /* Sep */, 1))) + }) + + it('accepts a timestamp', function () { + var date = new Date(Date.UTC(2014, 8 /* Sep */, 2, 11, 55, 0)).getTime() + var result = startOfUTCWeek(date) + assert.deepEqual(result, new Date(Date.UTC(2014, 7 /* Aug */, 31))) + }) + + it('does not mutate the original date', function () { + var date = new Date(Date.UTC(2014, 8 /* Sep */, 2, 11, 55, 0)) + startOfUTCWeek(date) + assert.deepEqual(date, new Date(Date.UTC(2014, 8 /* Sep */, 2, 11, 55, 0))) + }) + + describe('edge cases', function () { + describe('when the given day is before the start of a week', function () { + it('it returns the start of a week', function () { + var date = new Date(Date.UTC(2014, 9 /* Oct */, 6)) + var result = startOfUTCWeek(date, { weekStartsOn: 3 }) + assert.deepEqual(result, new Date(Date.UTC(2014, 9 /* Oct */, 1))) + }) + }) + + describe('when the given day is the start of a week', function () { + it('it returns the start of a week', function () { + var date = new Date(Date.UTC(2014, 9 /* Oct */, 8)) + var result = startOfUTCWeek(date, { weekStartsOn: 3 }) + assert.deepEqual(result, new Date(Date.UTC(2014, 9 /* Oct */, 8))) + }) + }) + + describe('when the given day is after the start of a week', function () { + it('it returns the start of a week', function () { + var date = new Date(Date.UTC(2014, 9 /* Oct */, 10)) + var result = startOfUTCWeek(date, { weekStartsOn: 3 }) + assert.deepEqual(result, new Date(Date.UTC(2014, 9 /* Oct */, 8))) + }) + }) + + it('handles the week at the start of a year', function () { + var date = new Date(Date.UTC(2014, 0 /* Jan */, 1)) + var result = startOfUTCWeek(date) + assert.deepEqual(result, new Date(Date.UTC(2013, 11 /* Dec */, 29))) + }) + }) + + it('returns `Invalid Date` if the given date is invalid', function () { + var result = startOfUTCWeek(new Date(NaN)) + assert(result instanceof Date && isNaN(result)) + }) + + it('throws `RangeError` if `options.weekStartsOn` is not convertable to 0, 1, ..., 6 or undefined', function () { + var block = startOfUTCWeek.bind( + null, + new Date(Date.UTC(2014, 8 /* Sep */, 2, 11, 55, 0)), + { weekStartsOn: NaN } + ) + assert.throws(block, RangeError) + }) + + it('throws TypeError exception if passed less than 1 argument', function () { + assert.throws(startOfUTCWeek.bind(null), TypeError) + }) +}) diff --git a/date-fns/src/_lib/startOfUTCWeekYear/index.js b/date-fns/src/_lib/startOfUTCWeekYear/index.js new file mode 100644 index 0000000..5b505db --- /dev/null +++ b/date-fns/src/_lib/startOfUTCWeekYear/index.js @@ -0,0 +1,30 @@ +import toInteger from '../toInteger/index' +import getUTCWeekYear from '../getUTCWeekYear/index' +import startOfUTCWeek from '../startOfUTCWeek/index' +import requiredArgs from '../requiredArgs/index' + +// This function will be a part of public API when UTC function will be implemented. +// See issue: https://github.com/date-fns/date-fns/issues/376 +export default function startOfUTCWeekYear(dirtyDate, dirtyOptions) { + requiredArgs(1, arguments) + + var options = dirtyOptions || {} + var locale = options.locale + var localeFirstWeekContainsDate = + locale && locale.options && locale.options.firstWeekContainsDate + var defaultFirstWeekContainsDate = + localeFirstWeekContainsDate == null + ? 1 + : toInteger(localeFirstWeekContainsDate) + var firstWeekContainsDate = + options.firstWeekContainsDate == null + ? defaultFirstWeekContainsDate + : toInteger(options.firstWeekContainsDate) + + var year = getUTCWeekYear(dirtyDate, dirtyOptions) + var firstWeek = new Date(0) + firstWeek.setUTCFullYear(year, 0, firstWeekContainsDate) + firstWeek.setUTCHours(0, 0, 0, 0) + var date = startOfUTCWeek(firstWeek, dirtyOptions) + return date +} diff --git a/date-fns/src/_lib/startOfUTCWeekYear/test.js b/date-fns/src/_lib/startOfUTCWeekYear/test.js new file mode 100644 index 0000000..73bb518 --- /dev/null +++ b/date-fns/src/_lib/startOfUTCWeekYear/test.js @@ -0,0 +1,95 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import startOfUTCWeekYear from '.' + +describe('startOfUTCWeekYear', function() { + it('returns the date with the time set to 00:00:00 and the date set to the first day of a week year', function() { + var result = startOfUTCWeekYear(new Date(Date.UTC(2005, 6 /* Jul */, 2))) + assert.deepEqual( + result, + new Date(Date.UTC(2004, 11 /* Dec */, 26, 0, 0, 0, 0)) + ) + }) + + it('accepts a timestamp', function() { + var result = startOfUTCWeekYear(Date.UTC(2005, 0 /* Jan */, 1, 6, 0)) + assert.deepEqual( + result, + new Date(Date.UTC(2004, 11 /* Dec */, 26, 0, 0, 0, 0)) + ) + }) + + it('does not mutate the original date', function() { + var date = new Date(Date.UTC(2014, 6 /* Jul */, 2)) + startOfUTCWeekYear(date) + assert.deepEqual(date, new Date(Date.UTC(2014, 6 /* Jul */, 2))) + }) + + it('handles dates before 100 AD', function() { + var initialDate = new Date(0) + initialDate.setUTCFullYear(9, 0 /* Jan */, 1) + initialDate.setUTCHours(0, 0, 0, 0) + var expectedResult = new Date(0) + expectedResult.setUTCFullYear(8, 11 /* Dec */, 28) + expectedResult.setUTCHours(0, 0, 0, 0) + var result = startOfUTCWeekYear(initialDate) + assert.deepEqual(result, expectedResult) + }) + + it('returns `Invalid Date` if the given date is invalid', function() { + var result = startOfUTCWeekYear(new Date(NaN)) + assert(result instanceof Date && isNaN(result)) + }) + + it('allows to specify `weekStartsOn` and `firstWeekContainsDate` in locale', function() { + var date = new Date(Date.UTC(2005, 6 /* Jul */, 2)) + var result = startOfUTCWeekYear(date, { + locale: { + options: { weekStartsOn: 1, firstWeekContainsDate: 4 } + } + }) + assert.deepEqual( + result, + new Date(Date.UTC(2005, 0 /* Jan */, 3, 0, 0, 0, 0)) + ) + }) + + it('`options.weekStartsOn` overwrites the first day of the week specified in locale', function() { + var date = new Date(2005, 6 /* Jul */, 2) + var result = startOfUTCWeekYear(date, { + weekStartsOn: 1, + firstWeekContainsDate: 4, + locale: { + options: { weekStartsOn: 0, firstWeekContainsDate: 1 } + } + }) + assert.deepEqual( + result, + new Date(Date.UTC(2005, 0 /* Jan */, 3, 0, 0, 0, 0)) + ) + }) + + it('throws `RangeError` if `options.weekStartsOn` is not convertable to 0, 1, ..., 6 or undefined', function() { + var block = startOfUTCWeekYear.bind( + null, + new Date(2007, 11 /* Dec */, 31), + { weekStartsOn: NaN } + ) + assert.throws(block, RangeError) + }) + + it('throws `RangeError` if `options.firstWeekContainsDate` is not convertable to 1, 2, ..., 7 or undefined', function() { + var block = startOfUTCWeekYear.bind( + null, + new Date(2007, 11 /* Dec */, 31), + { firstWeekContainsDate: NaN } + ) + assert.throws(block, RangeError) + }) + + it('throws TypeError exception if passed less than 1 argument', function() { + assert.throws(startOfUTCWeekYear.bind(null), TypeError) + }) +}) diff --git a/date-fns/src/_lib/test/index.ts b/date-fns/src/_lib/test/index.ts new file mode 100644 index 0000000..ecd8f8c --- /dev/null +++ b/date-fns/src/_lib/test/index.ts @@ -0,0 +1 @@ +export function assertType<T>(_: T) {} diff --git a/date-fns/src/_lib/toInteger/index.ts b/date-fns/src/_lib/toInteger/index.ts new file mode 100644 index 0000000..e9a9359 --- /dev/null +++ b/date-fns/src/_lib/toInteger/index.ts @@ -0,0 +1,13 @@ +export default function toInteger(dirtyNumber: unknown) { + if (dirtyNumber === null || dirtyNumber === true || dirtyNumber === false) { + return NaN + } + + const number = Number(dirtyNumber) + + if (isNaN(number)) { + return number + } + + return number < 0 ? Math.ceil(number) : Math.floor(number) +} diff --git a/date-fns/src/_lib/toInteger/test.js b/date-fns/src/_lib/toInteger/test.js new file mode 100644 index 0000000..6542890 --- /dev/null +++ b/date-fns/src/_lib/toInteger/test.js @@ -0,0 +1,64 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import toInteger from '.' + +describe('toInteger', function () { + it('truncates positive numbers', function () { + var result = toInteger(10.99) + assert(result === 10) + }) + + it('truncates negative numbers', function () { + var result = toInteger(-5.5) + assert(result === -5) + }) + + it('converts convertable strings', function () { + var result = toInteger('-10.75') + assert(result === -10) + }) + + it('returns NaN for non-convertable strings', function () { + var result = toInteger('Foobar') + assert(typeof result === 'number' && isNaN(result)) + }) + + it('returns NaN for false', function () { + var result = toInteger(false) + assert(typeof result === 'number' && isNaN(result)) + }) + + it('returns NaN for true', function () { + var result = toInteger(true) + assert(typeof result === 'number' && isNaN(result)) + }) + + it('returns NaN for null', function () { + var result = toInteger(null) + assert(typeof result === 'number' && isNaN(result)) + }) + + it('returns NaN for undefined', function () { + var result = toInteger(undefined) + assert(typeof result === 'number' && isNaN(result)) + }) + + it('returns NaN for NaN', function () { + var result = toInteger(NaN) + assert(typeof result === 'number' && isNaN(result)) + }) + + it('converts convertable objects', function () { + // eslint-disable-next-line no-new-wrappers + var result = toInteger(new Number(123)) + assert(result === 123) + }) + + it('returns NaN for non-convertable objects', function () { + // eslint-disable-next-line no-new-wrappers + var result = toInteger({}) + assert(typeof result === 'number' && isNaN(result)) + }) +}) |