chartjs/chartjs-adapter-date-fns

Support timezone?

jledentu opened this issue · 4 comments

Hi,

This adapter doesn't allow to specify a timezone when parsing/formatting dates, since, unline Luxon, date-fns options don't support timezones. There is an official complementary library, date-fns-tz, that adds functions with timezone support:

  • zonedTimeToUtc - Given a date and any time zone, returns a Date with the equivalent UTC time
  • utcToZonedTime - Get a date/time representing local time in a given time zone from the UTC date
  • getTimezoneOffset - Gets the offset in milliseconds between the time zone and UTC time
  • format - Extends date-fns/format with full time zone support
  • toDate - Can be used to create a zoned Date from a string containing an offset or IANA time zone

I wonder what is the best strategy to support timezones:

  • Create a chartjs-adapter-date-fns-tz adapter that extends this one,
  • Or add a timezone option in this adapter, then calling date-fns-tz functions (I guess we should then make the dependency optional)?

Since there is no too much logic in date adapters (i.e we just pass options to the underlying library), creating a distinct adapter may be a cleaner option?

JEK58 commented

Did you come up with a solution? Would be interested how you did manage to get it work.

@JEK58 No, sorry I didn't found time to work on this. :( I think that the library should handle a timezone option natively

For what it's worth, I came up with this hack to present all my dates in UTC regardless of user-timezone:

import { Chart,   _adapters } from "chart.js";
import "chartjs-adapter-date-fns";
import locale from "lib/browser_locale";

const Formats: Record<string, Intl.DateTimeFormatOptions> = {
  "MMM d": {
    month: "short",
    day: "2-digit",
    timeZone: "UTC",
  },
  PP: {
    year: "numeric",
    month: "short",
    day: "2-digit",
    timeZone: "UTC",
  },
};

_adapters._date.override({
  format: function (time, fmt) {
    let utcTime = new Date(time);
    let format = Formats[fmt];
    if (!format) console.warn(`Missing datetime format for ${fmt}`);
    return utcTime.toLocaleDateString(locale, format || { timeZone: "UTC" });
  },
});

Here, "MMM d" is chart.js's default format for a date, and "PP" is my format for scales.x.time.tooltipFormat. If you're using other format strings, you'd probably need to figure out your own equivalents.

_adapters._date.override({
  format: function (time, fmt) {
    let utcTime = new Date(time);
    let format = Formats[fmt];
    if (!format) console.warn(`Missing datetime format for ${fmt}`);
    return utcTime.toLocaleDateString(locale, format || { timeZone: "UTC" });
  },
});

This worked great for me as well. Thanks for the solution. The date-fns format function is quite simple:

 format: function(time, fmt) {
    return format(time, fmt, this.options);
  },

I think we should be fine to override it in this manner