packages/@fbcmobile-ui/Utils/DateUtils.js (95 lines of code) (raw):
/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */
'use strict';
import 'moment/min/locales';
import * as React from 'react';
import fbt from 'fbt';
import moment from 'moment/min/moment-with-locales.min.js';
/**
 * Checks if the device locale is available in moment and returns the locale
 * to be loaded
 * @param  {string} locale locale to be checked
 * @return {string}        locale to be loaded by moment
 */
export function chooseMomentLocale(locale: string): string {
  // make the locale lower case
  // will fix crashes caused by "en-GB" (instead of "en-gb") not being found
  const localeLowerCase = locale.toLowerCase();
  if (moment.locales().includes(localeLowerCase)) {
    // check if the locale is included in the array returned by `locales()`
    // which (in this case) tells us which locales moment will support
    return localeLowerCase;
  } else if (moment.locales().includes(localeLowerCase.substring(0, 2))) {
    // check if the first two letters of the locale are included in the array
    // returned by `locales()` which (in this case) tells us which locales
    // moment will support
    // will fixes crashes caused by "en-US" not being found, as we'll tell
    // moment to load "en" instead
    return localeLowerCase.substring(0, 2);
  }
  // use "en" (the default language and locale for my app) as
  // a fallback if we can't find any other locale
  return 'en';
}
export function getReadableDateString(
  date: moment$Moment,
  locale: string,
): React.Node {
  const today = moment();
  const tomorrow = moment(today).add(1, 'd');
  if (today.isSame(date, 'day')) {
    return <fbt desc="Date label shown as today">Today</fbt>;
  } else if (tomorrow.isSame(date, 'day')) {
    return <fbt desc="Date label shown as tomorrow">Tomorrow</fbt>;
  }
  return date.locale(locale).format('MMM DD');
}
export function getClosestFutureDayToToday(
  dates: Array<moment$Moment>,
  jsLocale: string,
): ?moment$Moment {
  const todayMoment = moment()
    .locale(jsLocale)
    .startOf('day');
  const closestMoment = dates
    .map<moment$Moment>(date =>
      moment(date)
        .locale(jsLocale)
        .startOf('day'),
    )
    .filter(moment => moment.isSameOrAfter(todayMoment, 'days'))
    .reduce((closestMoment, currentMoment) => {
      if (closestMoment == null) {
        return currentMoment;
      }
      if (
        currentMoment.diff(todayMoment, 'days') <
        closestMoment.diff(todayMoment, 'days')
      ) {
        return currentMoment;
      }
      return closestMoment;
    }, null);
  return closestMoment;
}
export function getSimpleDateString(date: moment$Moment, locale: string) {
  return date.locale(locale).format('MM DD YYYY');
}
export function getLocaleDateTimeString(date: moment$Moment, locale: string) {
  return date.locale(locale).format('L LT');
}
// TODO: Support translations
export function timeSince(
  date: moment$Moment,
  locale: string,
  currentTime?: moment$Moment,
) {
  const now = currentTime ? currentTime : moment().locale(locale);
  const intervals = {
    years: {diff: now.diff(date, 'years'), unit: 'y'},
    weeks: {diff: now.diff(date, 'weeks'), unit: 'w'},
    days: {diff: now.diff(date, 'days'), unit: 'd'},
    hours: {diff: now.diff(date, 'hours'), unit: 'h'},
    minutes: {diff: now.diff(date, 'minutes'), unit: 'm'},
    seconds: {diff: now.diff(date, 'seconds'), unit: 's'},
  };
  let intervalType = null;
  if (intervals.years.diff >= 1) {
    intervalType = 'years';
  } else if (intervals.weeks.diff >= 1) {
    intervalType = 'weeks';
  } else if (intervals.days.diff >= 1) {
    intervalType = 'days';
  } else if (intervals.hours.diff >= 1) {
    intervalType = 'hours';
  } else if (intervals.minutes.diff >= 1) {
    intervalType = 'minutes';
  } else if (intervals.seconds.diff >= 1) {
    intervalType = 'seconds';
  }
  if (intervalType === null) {
    return 'now';
  }
  const interval = intervals[intervalType];
  return `${interval.diff}${interval.unit}`;
}