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 }