All files / src/utils date.ts

94.28% Statements 33/35
82.6% Branches 19/23
100% Functions 8/8
94.11% Lines 32/34

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108                              35x           2x 8x           2x 7x   7x           2x 16x 16x                     2x 33x 8x 8x 8x       25x 7x 7x 7x       18x 7x     11x             2x 17x   3x     14x   14x           2x 2x           2x 19x 19x 19x              
import { DateTime } from 'luxon';
import _ from 'lodash';
 
/**
 * Accepted date types for input are:
 * - string for any date ISO string representation
 * - number for timestamp
 * - JS Date
 * - luxon DateTime
 */
export type DateType = string | number | Date | DateTime;
 
/**
 * Helper util that returns default time zone as a fallback.
 */
export const tz = (timeZoneId?: string) => timeZoneId || 'Etc/UTC';
 
/**
 * Parse a date ISO string with zone implied.
 * eg. '2023-01-10 in 'America/Los_Angeles'
 */
const getDateFromISOString = (date: string, timeZoneId?: string) => {
  return DateTime.fromISO(date, { zone: tz(timeZoneId) });
};
 
/**
 * Parse a date from milliseconds, with time zone implied.
 */
const getDateFromMillis = (date: number, timeZoneId?: string) => {
  const millis = new Date(date).getTime();
 
  return DateTime.fromMillis(millis, { zone: tz(timeZoneId) });
};
 
/**
 * Return the display value for a date in ISO 8601 format.
 */
const getDisplayValue = (date: DateTime) => {
  Eif (date.isValid) {
    return date.toFormat('yyyy-MM-dd');
  }
 
  return date.toString();
};
 
/**
 * Utility that constructs a valid DateTime object from
 * any DateType value passed in (ISO string or epoch milliseconds or DateTime object).
 * Note: the DateTime object input support is mostly for ease of use and will essentially be a pass-through.
 */
export const getDate = (date: DateType, timeZoneId?: string) => {
  if (typeof date === 'string') {
    const fromString = getDateFromISOString(date, timeZoneId);
    Eif (fromString.isValid) {
      return fromString;
    }
  }
 
  if (typeof date === 'number') {
    const fromMillis = getDateFromMillis(date, timeZoneId);
    Eif (fromMillis.isValid) {
      return fromMillis;
    }
  }
 
  if (_.isDate(date) || typeof date === 'string' || typeof date === 'number') {
    return DateTime.fromJSDate(new Date(date), { zone: tz(timeZoneId) });
  }
 
  return (date as DateTime).setZone(tz(timeZoneId));
};
 
/**
 * Default export function that provides a display value for a date
 * with optional implied time zone.
 */
const getDateDisplayValue = (date: DateType, timeZoneId?: string) => {
  if (typeof date === 'string' && date.match(/^\d\d\d\d-\d\d-\d\d$/)) {
    // if already in display format, return as-is, do not apply time zone
    return date;
  }
 
  const dateObj = getDate(date, timeZoneId);
 
  return getDisplayValue(dateObj);
};
 
/**
 * Exported function that returns todays date in a specific (optional) time zone.
 */
export const getTodaysDateFormatted = (timeZoneId?: string) => {
  return getDisplayValue(DateTime.now().setZone(tz(timeZoneId)));
};
 
/**
 * Checks if a date is in the future, time zone for date is optional.
 */
export const isInTheFuture = (date: DateType, timeZoneId?: string) => {
  const d = getDate(date, timeZoneId);
  Eif (d.isValid) {
    return d.toMillis() > Date.now();
  }
 
  return false;
};
 
export default getDateDisplayValue;