Vizzuality/landgriffon

View on GitHub
cookie-traceability/src/lib/flowmap/data/time.ts

Summary

Maintainability
B
5 hrs
Test Coverage
import { timeFormat, timeParse } from 'd3-time-format';
import {
  timeDay,
  timeHour,
  TimeInterval,
  timeMinute,
  timeMonth,
  timeSecond,
  timeWeek,
  timeYear,
} from 'd3-time';

const dateParsers = [
  timeParse('%Y-%m-%d'),
  timeParse('%Y-%m-%d %H:%M'),
  timeParse('%Y-%m-%d %H:%M:%S'),
  timeParse('%Y'),
  timeParse('%Y-%m'),
];

export function parseTime(input: string | Date | undefined): Date | undefined {
  if (input != null) {
    if (input instanceof Date) {
      return input;
    }
    for (const parse of dateParsers) {
      const date = parse(input);
      if (date) {
        return date;
      }
    }
  }
  return undefined;
}

export enum TimeGranularityKey {
  SECOND = 'SECOND',
  MINUTE = 'MINUTE',
  HOUR = 'HOUR',
  DAY = 'DAY',
  MONTH = 'MONTH',
  YEAR = 'YEAR',
}

export interface TimeGranularity {
  key: TimeGranularityKey;
  order: number;
  interval: TimeInterval;
  format: (date: Date) => string;
  formatFull: (date: Date) => string;
}

// const preferredLocale = navigator.languages ? navigator.languages[0] : 'en';

const formatMillisecond = timeFormat('.%L'),
  formatSecond = timeFormat(':%S'),
  formatMinute = timeFormat('%I:%M'),
  // formatHour = (d: Date) => d.toLocaleString(preferredLocale, { hour: 'numeric' }),
  formatHour = timeFormat('%I %p'),
  formatDay = timeFormat('%a %d'),
  formatWeek = timeFormat('%b %d'),
  formatMonth = timeFormat('%b'),
  formatYear = timeFormat('%Y');

export function tickMultiFormat(date: Date) {
  return (
    timeSecond(date) < date
      ? formatMillisecond
      : timeMinute(date) < date
      ? formatSecond
      : timeHour(date) < date
      ? formatMinute
      : timeDay(date) < date
      ? formatHour
      : timeMonth(date) < date
      ? timeWeek(date) < date
        ? formatDay
        : formatWeek
      : timeYear(date) < date
      ? formatMonth
      : formatYear
  )(date);
}

export const TIME_GRANULARITIES: TimeGranularity[] = [
  {
    order: 0,
    key: TimeGranularityKey.SECOND,
    interval: timeSecond,
    format: formatSecond,
    formatFull: timeFormat('%Y-%m-%d %H:%M:%S'),
  },
  {
    order: 1,
    key: TimeGranularityKey.MINUTE,
    interval: timeMinute,
    format: formatMinute,
    formatFull: timeFormat('%Y-%m-%d %H:%M'),
  },
  {
    order: 2,
    key: TimeGranularityKey.HOUR,
    interval: timeHour,
    // format: (d: Date) => d.toLocaleString(preferredLocale, { hour: 'numeric', minute: '2-digit' }),
    format: formatHour,
    formatFull: timeFormat('%a %d %b %Y, %I %p'),
  },
  {
    order: 3,
    key: TimeGranularityKey.DAY,
    interval: timeDay,
    format: formatDay,
    formatFull: timeFormat('%a %d %b %Y'),
  },
  {
    order: 4,
    key: TimeGranularityKey.MONTH,
    interval: timeMonth,
    format: formatMonth,
    formatFull: timeFormat('%b %Y'),
  },
  {
    order: 5,
    key: TimeGranularityKey.YEAR,
    interval: timeYear,
    format: formatYear,
    formatFull: timeFormat('%Y'),
  },
];

export function getTimeGranularityByKey(key: TimeGranularityKey) {
  return TIME_GRANULARITIES.find((s) => s.key === key);
}

export function getTimeGranularityByOrder(order: number) {
  return TIME_GRANULARITIES.find((s) => s.order === order);
}

export function getTimeGranularityForDate(date: Date): TimeGranularity {
  let prev = undefined;
  for (const current of TIME_GRANULARITIES) {
    const { interval } = current;
    const floored = interval(date);
    if (floored < date) {
      if (!prev) return current;
      return prev;
    }
    prev = current;
  }
  return TIME_GRANULARITIES[TIME_GRANULARITIES.length - 1];
}

export function areRangesEqual(a: [Date, Date] | undefined, b: [Date, Date] | undefined): boolean {
  if (!a && !b) return true;
  if (!a || !b) return false;
  return a[0] === b[0] && a[1] === b[1];
}