github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/app/utils/format-duration.js (about)

     1  import moment from 'moment';
     2  import { pluralize } from 'ember-inflector';
     3  
     4  /**
     5   * Metadata for all unit types
     6   * name: identifier for the unit. Also maps to moment methods when applicable
     7   * suffix: the preferred suffix for a unit
     8   * inMoment: whether or not moment can be used to compute this unit value
     9   * pluralizable: whether or not this suffix can be pluralized
    10   * longSuffix: the suffix to use instead of suffix when longForm is true
    11   */
    12  const allUnits = [
    13    { name: 'years', suffix: 'year', inMoment: true, pluralizable: true },
    14    { name: 'months', suffix: 'month', inMoment: true, pluralizable: true },
    15    { name: 'days', suffix: 'day', inMoment: true, pluralizable: true },
    16    {
    17      name: 'hours',
    18      suffix: 'h',
    19      longSuffix: 'hour',
    20      inMoment: true,
    21      pluralizable: false,
    22    },
    23    {
    24      name: 'minutes',
    25      suffix: 'm',
    26      longSuffix: 'minute',
    27      inMoment: true,
    28      pluralizable: false,
    29    },
    30    {
    31      name: 'seconds',
    32      suffix: 's',
    33      longSuffix: 'second',
    34      inMoment: true,
    35      pluralizable: false,
    36    },
    37    { name: 'milliseconds', suffix: 'ms', inMoment: true, pluralizable: false },
    38    { name: 'microseconds', suffix: 'µs', inMoment: false, pluralizable: false },
    39    { name: 'nanoseconds', suffix: 'ns', inMoment: false, pluralizable: false },
    40  ];
    41  
    42  const pluralizeUnits = (amount, unit, longForm) => {
    43    let suffix;
    44  
    45    if (longForm && unit.longSuffix) {
    46      // Long form means always using full words (seconds insteand of s) which means
    47      // pluralization is necessary.
    48      suffix = amount === 1 ? unit.longSuffix : pluralize(unit.longSuffix);
    49    } else {
    50      // In the normal case, only pluralize based on the pluralizable flag
    51      suffix =
    52        amount === 1 || !unit.pluralizable ? unit.suffix : pluralize(unit.suffix);
    53    }
    54  
    55    // A space should go between the value and the unit when the unit is a full word
    56    // 300ns vs. 1 hour
    57    const addSpace = unit.pluralizable || (longForm && unit.longSuffix);
    58    return `${amount}${addSpace ? ' ' : ''}${suffix}`;
    59  };
    60  
    61  /**
    62   * Format a Duration at a preferred precision
    63   *
    64   * @param {Number} duration The duration to format
    65   * @param {String} units The units for the duration. Default to nanoseconds.
    66   * @param {Boolean} longForm Whether or not to expand single character suffixes,
    67   *   used to ensure screen readers correctly read units.
    68   */
    69  export default function formatDuration(
    70    duration = 0,
    71    units = 'ns',
    72    longForm = false
    73  ) {
    74    const durationParts = {};
    75  
    76    // Moment only handles up to millisecond precision.
    77    // Microseconds and nanoseconds need to be handled first,
    78    // then Moment can take over for all larger units.
    79    if (units === 'ns') {
    80      durationParts.nanoseconds = duration % 1000;
    81      durationParts.microseconds = Math.floor((duration % 1000000) / 1000);
    82      duration = Math.floor(duration / 1000000);
    83    } else if (units === 'mms') {
    84      durationParts.microseconds = duration % 1000;
    85      duration = Math.floor(duration / 1000);
    86    }
    87  
    88    let momentUnits = units;
    89    if (units === 'ns' || units === 'mms') {
    90      momentUnits = 'ms';
    91    }
    92    const momentDuration = moment.duration(duration, momentUnits);
    93  
    94    // Get the count of each time unit that Moment handles
    95    allUnits
    96      .filterBy('inMoment')
    97      .mapBy('name')
    98      .forEach((unit) => {
    99        durationParts[unit] = momentDuration[unit]();
   100      });
   101  
   102    // Format each time time bucket as a string
   103    // e.g., { years: 5, seconds: 30 } -> [ '5 years', '30s' ]
   104    const displayParts = allUnits.reduce((parts, unitType) => {
   105      if (durationParts[unitType.name]) {
   106        const count = durationParts[unitType.name];
   107        parts.push(pluralizeUnits(count, unitType, longForm));
   108      }
   109      return parts;
   110    }, []);
   111  
   112    if (displayParts.length) {
   113      return displayParts.join(' ');
   114    }
   115  
   116    // When the duration is 0, show 0 in terms of `units`
   117    return pluralizeUnits(0, allUnits.findBy('suffix', units), longForm);
   118  }