github.com/hernad/nomad@v1.6.112/ui/app/utils/format-duration.js (about)

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