Skip to content

Optional moment.js Part 2 #1052

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules
.sass-cache
npm-debug.log
.DS_Store
.idea
.vscode
dist
Expand Down
46 changes: 46 additions & 0 deletions src/date_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ function getStartOf (date, unit) {
return date.startOf(unit)
}

function getEndOf (date, unit) {
return date.endOf(unit)
}

function getDiff (date1, date2, unit) {
return date1.diff(date2, unit)
}

function isSame (date1, date2, unit) {
return date1.isSame(date2, unit)
}
Expand Down Expand Up @@ -92,6 +100,10 @@ export function setYear (date, year) {
return set(date, 'year', year)
}

export function setUTCOffset (date, offset) {
return date.utcOffset(offset)
}

// ** Date Getters **

export function getSecond (date) {
Expand All @@ -106,6 +118,7 @@ export function getHour (date) {
return get(date, 'hour')
}

// Returns day of week
export function getDay (date) {
return get(date, 'day')
}
Expand All @@ -122,6 +135,7 @@ export function getYear (date) {
return get(date, 'year')
}

// Returns day of month
export function getDate (date) {
return get(date, 'date')
}
Expand Down Expand Up @@ -151,6 +165,16 @@ export function getStartOfDate (date) {
return getStartOf(date, 'date')
}

// *** End of ***

export function getEndOfWeek (date) {
return getEndOf(date, 'week')
}

export function getEndOfMonth (date) {
return getEndOf(date, 'month')
}

// ** Date Math **

// *** Addition ***
Expand Down Expand Up @@ -202,6 +226,10 @@ export function isAfter (date1, date2) {
return date1.isAfter(date2)
}

export function equals (date1, date2) {
return date1.isSame(date2)
}

export function isSameMonth (date1, date2) {
return isSame(date1, date2, 'month')
}
Expand All @@ -228,12 +256,30 @@ export function isDayInRange (day, startDate, endDate) {
return day.clone().startOf('day').isBetween(before, after)
}

// *** Diffing ***

export function getDaysDiff (date1, date2) {
return getDiff(date1, date2, 'days')
}

// ** Date Localization **

export function localizeDate (date, locale) {
return date.clone().locale(locale || moment.locale())
}

export function getDefaultLocale () {
return moment.locale()
}

export function getDefaultLocaleData () {
return moment.localeData()
}

export function registerLocale (localeName, localeData) {
moment.defineLocale(localeName, localeData)
}

export function getLocaleData (date) {
return date.localeData()
}
Expand Down
119 changes: 61 additions & 58 deletions test/calendar_test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React from 'react'
import moment from 'moment'
import Calendar from '../src/calendar'
import Month from '../src/month'
import Day from '../src/day'
import YearDropdown from '../src/year_dropdown'
import MonthDropdown from '../src/month_dropdown'
import { shallow, mount } from 'enzyme'
import sinon from 'sinon'
import * as utils from '../src/date_utils'

// TODO Possibly rename
const DATE_FORMAT = 'MM/DD/YYYY'

describe('Calendar', function () {
const dateFormat = 'MMMM YYYY'
Expand All @@ -24,105 +27,105 @@ describe('Calendar', function () {
}

it('should start with the current date in view if no date range', function () {
const now = moment()
const now = utils.newDate()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a bit cleaner to use separate functions to parse a date and to get the current date. We can leave that for later though, since moment() did serve both purposes too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, had exactly the same thought :)

const calendar = getCalendar()
assert(calendar.state().date.isSame(now, 'day'))
assert(utils.isSameDay(calendar.state().date, now))
})

it('should start with the today date with specified time zone', function () {
const utcOffset = 12
const calendar = getCalendar({utcOffset})
assert(calendar.state().date.isSame(moment.utc().utcOffset(utcOffset), 'day'))
assert(utils.isSameDay(calendar.state().date, utils.newDateWithOffset(utcOffset)))
})

it('should start with the selected date in view if provided', function () {
const selected = moment().add(1, 'year')
const selected = utils.addYears(utils.newDate(), 1)
const calendar = getCalendar({selected})
assert(calendar.state().date.isSame(selected, 'day'))
assert(utils.isSameDay(calendar.state().date, selected))
})

it('should start with the pre-selected date in view if provided', function () {
const preSelected = moment().add(2, 'year')
const selected = moment().add(1, 'year')
const preSelected = utils.addYears(utils.newDate(), 2)
const selected = utils.addYears(utils.newDate(), 1)
const calendar = getCalendar({ preSelected, selected })
assert(calendar.state().date.isSame(selected, 'day'))
assert(utils.isSameDay(calendar.state().date, selected))
})

it('should start with the current date in view if in date range', function () {
const now = moment()
const minDate = now.clone().subtract(1, 'year')
const maxDate = now.clone().add(1, 'year')
const now = utils.newDate()
const minDate = utils.subtractYears(utils.cloneDate(now), 1)
const maxDate = utils.addYears(utils.cloneDate(now), 1)
const calendar = getCalendar({ minDate, maxDate })
assert(calendar.state().date.isSame(now, 'day'))
assert(utils.isSameDay(calendar.state().date, now))
})

it('should start with the min date in view if after the current date', function () {
const minDate = moment().add(1, 'year')
const minDate = utils.addYears(utils.newDate(), 1)
const calendar = getCalendar({ minDate })
assert(calendar.state().date.isSame(minDate, 'day'))
assert(utils.isSameDay(calendar.state().date, minDate))
})

it('should start with the min include date in view if after the current date', function () {
const minDate = moment().add(1, 'year')
const minDate = utils.addYears(utils.newDate(), 1)
const calendar = getCalendar({ includeDates: [minDate] })
assert(calendar.state().date.isSame(minDate, 'day'))
assert(utils.isSameDay(calendar.state().date, minDate))
})

it('should start with the max date in view if before the current date', function () {
const maxDate = moment().subtract(1, 'year')
const maxDate = utils.subtractYears(utils.newDate(), 1)
const calendar = getCalendar({ maxDate })
assert(calendar.state().date.isSame(maxDate, 'day'))
assert(utils.isSameDay(calendar.state().date, maxDate))
})

it('should start with the max include date in view if before the current date', function () {
const maxDate = moment().subtract(1, 'year')
const maxDate = utils.subtractYears(utils.newDate(), 1)
const calendar = getCalendar({ includeDates: [maxDate] })
assert(calendar.state().date.isSame(maxDate, 'day'))
assert(utils.isSameDay(calendar.state().date, maxDate))
})

it('should start with the open to date in view if given and no selected/min/max dates given', function () {
const openToDate = moment('09/28/1993', 'MM/DD/YYYY')
const openToDate = utils.parseDate('09/28/1993', { dateFormat: DATE_FORMAT })
const calendar = getCalendar({ openToDate })
assert(calendar.state().date.isSame(openToDate, 'day'))
assert(utils.isSameDay(calendar.state().date, openToDate))
})

it('should start with the open to date in view if given and after a min date', function () {
const openToDate = moment('09/28/1993', 'MM/DD/YYYY')
const minDate = moment('01/01/1993', 'MM/DD/YYYY')
const openToDate = utils.parseDate('09/28/1993', { dateFormat: DATE_FORMAT })
const minDate = utils.parseDate('01/01/1993', { dateFormat: DATE_FORMAT })
const calendar = getCalendar({ openToDate, minDate })
assert(calendar.state().date.isSame(openToDate, 'day'))
assert(utils.isSameDay(calendar.state().date, openToDate))
})

it('should start with the open to date in view if given and before a max date', function () {
const openToDate = moment('09/28/1993', 'MM/DD/YYYY')
const maxDate = moment('12/31/1993', 'MM/DD/YYYY')
const openToDate = utils.parseDate('09/28/1993', { dateFormat: DATE_FORMAT })
const maxDate = utils.parseDate('12/31/1993', { dateFormat: DATE_FORMAT })
const calendar = getCalendar({ openToDate, maxDate })
assert(calendar.state().date.isSame(openToDate, 'day'))
assert(utils.isSameDay(calendar.state().date, openToDate))
})

it('should start with the open to date in view if given and in range of the min/max dates', function () {
const openToDate = moment('09/28/1993', 'MM/DD/YYYY')
const minDate = moment('01/01/1993', 'MM/DD/YYYY')
const maxDate = moment('12/31/1993', 'MM/DD/YYYY')
const openToDate = utils.parseDate('09/28/1993', { dateFormat: DATE_FORMAT })
const minDate = utils.parseDate('01/01/1993', { dateFormat: DATE_FORMAT })
const maxDate = utils.parseDate('12/31/1993', { dateFormat: DATE_FORMAT })
const calendar = getCalendar({ openToDate, minDate, maxDate })
assert(calendar.state().date.isSame(openToDate, 'day'))
assert(utils.isSameDay(calendar.state().date, openToDate))
})

it('should open on openToDate date rather than selected date when both are specified', function () {
var openToDate = moment('09/28/1993', 'MM/DD/YYYY')
var selected = moment('09/28/1995', 'MM/DD/YYYY')
var openToDate = utils.parseDate('09/28/1993', { dateFormat: DATE_FORMAT })
var selected = utils.parseDate('09/28/1995', { dateFormat: DATE_FORMAT })
var calendar = getCalendar({ openToDate, selected })
assert(calendar.state().date.isSame(openToDate, 'day'))
assert(utils.isSameDay(calendar.state().date, openToDate))
})

it('should trigger date change when openToDate prop is set after calcInitialState()', () => {
const openToDate = moment('09/28/1993', 'MM/DD/YYYY')
const oneMonthFromOpenToDate = moment('10/28/1993', 'MM/DD/YYYY')
const openToDate = utils.parseDate('09/28/1993', { dateFormat: DATE_FORMAT })
const oneMonthFromOpenToDate = utils.parseDate('10/28/1993', { dateFormat: DATE_FORMAT })
const calendar = getCalendar({ openToDate })

assert(calendar.state().date.isSame(openToDate, 'day'))
assert(utils.isSameDay(calendar.state().date, openToDate))
calendar.setProps({ openToDate: oneMonthFromOpenToDate })
assert(calendar.state().date.isSame(oneMonthFromOpenToDate))
assert(utils.isSameDay(calendar.state().date, oneMonthFromOpenToDate))
})

it('should not show the year dropdown menu by default', function () {
Expand All @@ -138,7 +141,7 @@ describe('Calendar', function () {
})

it('should show month navigation if toggled on', function () {
const calendar = getCalendar({ includeDates: [moment()], forceShowMonthNavigation: true })
const calendar = getCalendar({ includeDates: [utils.newDate()], forceShowMonthNavigation: true })
const nextNavigationButton = calendar.find('.react-datepicker__navigation--next')
expect(nextNavigationButton).to.have.length(1)
})
Expand Down Expand Up @@ -172,15 +175,15 @@ describe('Calendar', function () {
const calendar = getCalendar({ todayButton: 'Vandaag' })
const todayButton = calendar.find('.react-datepicker__today-button')
todayButton.simulate('click')
expect(calendar.state().date.isSame(moment(), 'day'))
expect(calendar.state().date.isSame(utils.newDate(), 'day'))
})

it('should set custom today date when pressing todayButton', () => {
const todayInAuckland = moment.utc().utcOffset(12)
const todayInAuckland = utils.newDateWithOffset(12)
const calendar = getCalendar({ todayButton: 'Vandaag', utcOffset: 12 })
const todayButton = calendar.find('.react-datepicker__today-button')
todayButton.simulate('click')
expect(calendar.state().date.isSame(todayInAuckland, 'day'))
expect(utils.isSameDay(calendar.state().date, todayInAuckland))
})

it('should use a hash for week label if weekLabel is NOT provided', () => {
Expand All @@ -207,7 +210,7 @@ describe('Calendar', function () {
const month = calendar.find(Month).first()
day.simulate('mouseenter')
expect(month.prop('selectingDate')).to.exist
expect(month.prop('selectingDate').isSame(day.prop('day'), 'day')).to.be.true
expect(utils.isSameDay(month.prop('selectingDate'), day.prop('day'))).to.be.true
})

it('should clear the hovered day when the mouse leaves', () => {
Expand All @@ -218,15 +221,15 @@ describe('Calendar', function () {
onClickOutside={() => {}}
onSelect={() => {}}/>
)
calendar.setState({ selectingDate: moment() })
calendar.setState({ selectingDate: utils.newDate() })
const month = calendar.find(Month).first()
expect(month.prop('selectingDate')).to.exist
month.simulate('mouseleave')
expect(month.prop('selectingDate')).not.to.exist
})

it('uses MomentJS\'s weekdaysShort instead of weekdaysMin provided useWeekdaysShort prop is present', () => {
moment.defineLocale('weekDaysLocale', {
it('uses weekdaysShort instead of weekdaysMin provided useWeekdaysShort prop is present', () => {
utils.registerLocale('weekDaysLocale', {
parentLocale: 'en',
weekdaysMin: 'AA_BB_CC_DD_EE_FF_GG'.split('_'),
weekdaysShort: 'AAA_BBB_CCC_DDD_EEE_FFF_GGG'.split('_')
Expand Down Expand Up @@ -333,39 +336,39 @@ describe('Calendar', function () {

describe('localization', function () {
function testLocale (calendar, selected, locale) {
const localized = selected.clone().locale(locale)
const localized = utils.localizeDate(selected, locale)

const calendarText = calendar.find('.react-datepicker__current-month')
expect(calendarText.text()).to.equal(localized.format(dateFormat))
expect(calendarText.text()).to.equal(utils.formatDate(localized, dateFormat))

const firstDateOfWeek = localized.clone().startOf('week')
const firstWeekDayMin = firstDateOfWeek.localeData().weekdaysMin(firstDateOfWeek)
const firstDateOfWeek = utils.getStartOfWeek(utils.cloneDate(localized))
const firstWeekDayMin = utils.getWeekdayMinInLocale(utils.getLocaleData(firstDateOfWeek), firstDateOfWeek)
const firstHeader = calendar.find('.react-datepicker__day-name').at(0)
expect(firstHeader.text()).to.equal(firstWeekDayMin)
}

it('should use the globally-defined locale by default', function () {
const selected = moment()
const selected = utils.newDate()
const calendar = getCalendar({ selected })
testLocale(calendar, selected, moment.locale())
testLocale(calendar, selected, utils.getDefaultLocale())
})

it('should use the locale specified as a prop', function () {
const locale = 'fr'
const selected = moment().locale(locale)
const selected = utils.localizeDate(utils.newDate(), locale)
const calendar = getCalendar({ selected, locale })
testLocale(calendar, selected, locale)
})

it('should override the locale of the date with the globally-defined locale', function () {
const selected = moment().locale('fr')
const selected = utils.localizeDate(utils.newDate(), 'fr')
const calendar = getCalendar({ selected })
testLocale(calendar, selected, moment.locale())
testLocale(calendar, selected, utils.getDefaultLocale())
})

it('should override the locale of the date with the locale prop', function () {
const locale = 'fr'
const selected = moment()
const selected = utils.newDate()
const calendar = getCalendar({ selected, locale })
testLocale(calendar, selected, locale)
})
Expand Down
Loading