React-big-calendar: Moment.js alternatives (date-fns)

Created on 20 Apr 2018  Β·  18Comments  Β·  Source: jquense/react-big-calendar

Do you want to request a _feature_ or report a _bug_?

Feature

This library supports Moment.js and Globalize.js for localization. I was wondering if you had any plans to add other localization libraries, specifically date-fns. Moment is a very powerful library, but it does not offer the same bundle size optimizations as date-fns. There's a great discussion on the differences here. The main benefits of date-fns over Moment are performance and a more optimized bundle.

If this isn't really on your radar, no worries. I may still make an attempt at a PR if that's the case.

feature request wontfix

Most helpful comment

Inspired by some conversation in #118, Here's a first swag at a luxon localizer. Hasn't been tested enough for me to call it bulletproof, but it seems to work so far in a quick smoke test.

import { set } from 'react-big-calendar/lib/formats'
import { set as setLocalizer } from 'react-big-calendar/lib/localizer'
import dates from 'react-big-calendar/lib/utils/dates'

const dateRangeFormat = ({ start, end }, culture, local) =>
  `${local.format(start, 'D', culture)} β€” ${local.format(end, 'D', culture)}`

const timeRangeFormat = ({ start, end }, culture, local) =>
  `${local.format(start, 't', culture)} β€” ${local.format(end, 't', culture)}`

const timeRangeStartFormat = ({ start }, culture, local) =>
  `${local.format(start, 't', culture)} β€” `

const timeRangeEndFormat = ({ end }, culture, local) => ` β€” ${local.format(end, 't', culture)}`

const weekRangeFormat = ({ start, end }, culture, local) =>
  `${local.format(start, 'MMMM dd', culture)} - ${local.format(
    end,
    dates.eq(start, end, 'month') ? 'dd' : 'MMMM dd',
    culture
  )}`

export const formats = {
  dateFormat: 'dd',
  dayFormat: 'dd EEE',
  weekdayFormat: 'ccc',

  selectRangeFormat: timeRangeFormat,
  eventTimeRangeFormat: timeRangeFormat,
  eventTimeRangeStartFormat: timeRangeStartFormat,
  eventTimeRangeEndFormat: timeRangeEndFormat,

  timeGutterFormat: 't',

  monthHeaderFormat: 'MMMM yyyy',
  dayHeaderFormat: 'dddd MMM dd',
  dayRangeHeaderFormat: weekRangeFormat,
  agendaHeaderFormat: dateRangeFormat,

  agendaDateFormat: 'EEE MMM dd',
  agendaTimeFormat: 't',
  agendaTimeRangeFormat: timeRangeFormat,
}

export default function(DateTime, { firstDayOfWeek }) {
  const locale = (d, c) => (c ? d.reconfigure(c) : d)

  set(formats)

  return setLocalizer({
    firstOfWeek() {
      return firstDayOfWeek
    },

    parse(value, format, culture) {
      return locale(DateTime.fromFormat(value, format), culture).toJSDate()
    },

    format(value, format, culture) {
      return locale(DateTime.fromJSDate(value), culture).toFormat(format)
    },
  })
}
LuxonLocalizer(DateTime, { firstDayOfWeek: 0 })

All 18 comments

@amkoehler I think it's a good idea to allow other alternatives like date-fns. I like date-fns as well and use it with this library outside of the initial setup with moment. It will be nice to see a PR on this if you get around to it!

@amkoehler @arecvlohe I tried to implement RBC localizer for date-fns v1.29.0. I've found the next issues:

  1. RBC's localizers require parse function with possibility to provide locale argument. Date-fns v1 doesn't support parsing with localization. It seems that it will be added in v2.
  2. startOfWeek function from date-fns v1 doesn't take locale parameter (it can take weekStartsOn value but not an actual locale object). date-fns v2-alpha already has this feature. A possible workaround for v1 is to hardcode mapping between locales and weekStartsOn number.

Therefore probably it's better to wait for date-fns v2. Let's help date-fns community to update locales for v2: https://github.com/date-fns/date-fns/blob/master/outdatedLocales.json

I would also really like to see support for different packages. I need to use luxon, which is going to be moment's predecessor. Moment.js is taboo here because of optimization..

We aren't likely to support a lot of options out of box, but the API is pluggable specifically so folks can use whatever they want @GavinThomas1192 can you give a Luxon localizer a shot and if there are api failings please report back.

Yes, this will be my priority tomorrow! I’ve spent about a week implementing a super custom react big calendar and would really like to be able to use all of my work. So this is a high priority. My company absolutely won’t allow me to use moment

Inspired by some conversation in #118, Here's a first swag at a luxon localizer. Hasn't been tested enough for me to call it bulletproof, but it seems to work so far in a quick smoke test.

import { set } from 'react-big-calendar/lib/formats'
import { set as setLocalizer } from 'react-big-calendar/lib/localizer'
import dates from 'react-big-calendar/lib/utils/dates'

const dateRangeFormat = ({ start, end }, culture, local) =>
  `${local.format(start, 'D', culture)} β€” ${local.format(end, 'D', culture)}`

const timeRangeFormat = ({ start, end }, culture, local) =>
  `${local.format(start, 't', culture)} β€” ${local.format(end, 't', culture)}`

const timeRangeStartFormat = ({ start }, culture, local) =>
  `${local.format(start, 't', culture)} β€” `

const timeRangeEndFormat = ({ end }, culture, local) => ` β€” ${local.format(end, 't', culture)}`

const weekRangeFormat = ({ start, end }, culture, local) =>
  `${local.format(start, 'MMMM dd', culture)} - ${local.format(
    end,
    dates.eq(start, end, 'month') ? 'dd' : 'MMMM dd',
    culture
  )}`

export const formats = {
  dateFormat: 'dd',
  dayFormat: 'dd EEE',
  weekdayFormat: 'ccc',

  selectRangeFormat: timeRangeFormat,
  eventTimeRangeFormat: timeRangeFormat,
  eventTimeRangeStartFormat: timeRangeStartFormat,
  eventTimeRangeEndFormat: timeRangeEndFormat,

  timeGutterFormat: 't',

  monthHeaderFormat: 'MMMM yyyy',
  dayHeaderFormat: 'dddd MMM dd',
  dayRangeHeaderFormat: weekRangeFormat,
  agendaHeaderFormat: dateRangeFormat,

  agendaDateFormat: 'EEE MMM dd',
  agendaTimeFormat: 't',
  agendaTimeRangeFormat: timeRangeFormat,
}

export default function(DateTime, { firstDayOfWeek }) {
  const locale = (d, c) => (c ? d.reconfigure(c) : d)

  set(formats)

  return setLocalizer({
    firstOfWeek() {
      return firstDayOfWeek
    },

    parse(value, format, culture) {
      return locale(DateTime.fromFormat(value, format), culture).toJSDate()
    },

    format(value, format, culture) {
      return locale(DateTime.fromJSDate(value), culture).toFormat(format)
    },
  })
}
LuxonLocalizer(DateTime, { firstDayOfWeek: 0 })

Thank you @ltegman, really hoping this works well. I really would love to be able to display a calendar based on a set time zone, and not the time zone of the client's browser. (ie. issue #118)

Could you please provide a bit more detail about how exactly you use this with react-big-calendar?

Right now I am using moment like this:

import moment from 'moment';
import BigCalendar from 'react-big-calendar';
import 'react-big-calendar/lib/css/react-big-calendar.css';
const localizer = BigCalendar.momentLocalizer(moment);

then on my calendar component:

<BigCalendar 
    localizer={localizer}
    events={this.state.events}
    startAccessor="start"
    endAccessor="end"
/>

How exactly would I import the code and attach the LuxonLocalizer as per your example above?

Thanks for the help if possible. πŸ™‡

@adueck I'm also interested in date-fns support. There is a pull request you can look at, they are waiting for date-fns v2 to come out of alpha before they merge it, but it has been in alpha for so long, they can just as well add it. https://github.com/intljusticemission/react-big-calendar/pull/855

@steph4nc Not sure how clean this, but I actually made a work around that works great for me. I am adjusting the date/times in all the events based on the offset from the the timezone in the client's browser.

function calculateTimeDifference() {
  const testDate = new Date();
  const timezoneOffset = testDate.getTimezoneOffset();
  const calendarTimeOffset = -120; // THE TIMEZONE OFFSET FROM THE TIMEZONE YOU WANT THE CALENDAR TO DISPLAY IN
  return (timezoneOffset - calendarTimeOffset) / 60;
}

const timeDifference = calculateTimeDifference();
this.setState({ timeDifference: timeDifference });
// Adjust all the events in state according to the client's difference in time from desired calendar time
this.setState(prevState => {
    const adjusted = prevState.events;
    adjusted.forEach(event => {
        event.start = new Date(event.start.setHours(event.start.getHours() + timeDifference));
        event.end = new Date(event.end.setHours(event.end.getHours() + timeDifference));
    });
    return { events: adjusted };
});

This can also be applied to the clicking and dragging creation of events, to adjust their times accordingly

handleSelect({start, end}) {
  const title = window.prompt('New Event name');
  if (title) {
    // Add event to db (compensating for users timezone offset)
    const eventToSubmit = {
      title: title,
      start: new Date(start.setHours(start.getHours() - this.state.timeDifference)),
      end: new Date(end.setHours(end.getHours() - this.state.timeDifference))
    };
    fetch(`${apiUrl}events`,
    {
        method: 'POST',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(eventToSubmit),
        credentials: "include"
    }).then((res) => res.json())
    .then((res) => {
      // Add event to state - with id for event returned from db
      const _id = res._id
      const adjustedStart = new Date(start.setHours(start.getHours() + this.state.timeDifference));
      const adjustedEnd = new Date(end.setHours(end.getHours() + this.state.timeDifference));
      this.setState({ events: [...this.state.events,
        {
          start,
          end,
          title,
          _id
        },],});
    });
  }
}

Can't personally vouch for it but have read about Day.Js as an alternative

⏰ Day.js 2KB immutable date library alternative to Moment.js with the same modern API

https://github.com/iamkun/dayjs

reference: moment/moment#2373 (comment)

@xxyuk We are planning to migrate to https://github.com/dmtrKovalenko/date-io as interop layer which supports day.js and date-fns.

@TrySound do you have a timeline on that?

Not yet. Would you like to help?

I do have a day week our company donates to open source :) How big of a project is it?

Are there plans to support Luxon for localization?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

PR for Luxon localizer is RFR here: https://github.com/intljusticemission/react-big-calendar/pull/1574
Can't say whether it will be merged or not, but wanted to point this conversation to it.

@jquense I don't know what your availability is but I would love to see this PR reviewed and released! (just a nudge to help get it over the finish line)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nicolasriccardi picture nicolasriccardi  Β·  3Comments

tiaaaa123 picture tiaaaa123  Β·  4Comments

ZacharyLangley picture ZacharyLangley  Β·  3Comments

connercms picture connercms  Β·  3Comments

nirchernia picture nirchernia  Β·  3Comments