github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/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 { name: 'hours', suffix: 'h', longSuffix: 'hour', inMoment: true, pluralizable: false }, 17 { name: 'minutes', suffix: 'm', longSuffix: 'minute', inMoment: true, pluralizable: false }, 18 { name: 'seconds', suffix: 's', longSuffix: 'second', inMoment: true, pluralizable: false }, 19 { name: 'milliseconds', suffix: 'ms', inMoment: true, pluralizable: false }, 20 { name: 'microseconds', suffix: 'µs', inMoment: false, pluralizable: false }, 21 { name: 'nanoseconds', suffix: 'ns', inMoment: false, pluralizable: false }, 22 ]; 23 24 const pluralizeUnits = (amount, unit, longForm) => { 25 let suffix; 26 27 if (longForm && unit.longSuffix) { 28 // Long form means always using full words (seconds insteand of s) which means 29 // pluralization is necessary. 30 suffix = amount === 1 ? unit.longSuffix : pluralize(unit.longSuffix); 31 } else { 32 // In the normal case, only pluralize based on the pluralizable flag 33 suffix = amount === 1 || !unit.pluralizable ? unit.suffix : pluralize(unit.suffix); 34 } 35 36 // A space should go between the value and the unit when the unit is a full word 37 // 300ns vs. 1 hour 38 const addSpace = unit.pluralizable || (longForm && unit.longSuffix); 39 return `${amount}${addSpace ? ' ' : ''}${suffix}`; 40 }; 41 42 /** 43 * Format a Duration at a preferred precision 44 * 45 * @param {Number} duration The duration to format 46 * @param {String} units The units for the duration. Default to nanoseconds. 47 * @param {Boolean} longForm Whether or not to expand single character suffixes, 48 * used to ensure screen readers correctly read units. 49 */ 50 export default function formatDuration(duration = 0, units = 'ns', longForm = false) { 51 const durationParts = {}; 52 53 // Moment only handles up to millisecond precision. 54 // Microseconds and nanoseconds need to be handled first, 55 // then Moment can take over for all larger units. 56 if (units === 'ns') { 57 durationParts.nanoseconds = duration % 1000; 58 durationParts.microseconds = Math.floor((duration % 1000000) / 1000); 59 duration = Math.floor(duration / 1000000); 60 } else if (units === 'mms') { 61 durationParts.microseconds = duration % 1000; 62 duration = Math.floor(duration / 1000); 63 } 64 65 let momentUnits = units; 66 if (units === 'ns' || units === 'mms') { 67 momentUnits = 'ms'; 68 } 69 const momentDuration = moment.duration(duration, momentUnits); 70 71 // Get the count of each time unit that Moment handles 72 allUnits 73 .filterBy('inMoment') 74 .mapBy('name') 75 .forEach(unit => { 76 durationParts[unit] = momentDuration[unit](); 77 }); 78 79 // Format each time time bucket as a string 80 // e.g., { years: 5, seconds: 30 } -> [ '5 years', '30s' ] 81 const displayParts = allUnits.reduce((parts, unitType) => { 82 if (durationParts[unitType.name]) { 83 const count = durationParts[unitType.name]; 84 parts.push(pluralizeUnits(count, unitType, longForm)); 85 } 86 return parts; 87 }, []); 88 89 if (displayParts.length) { 90 return displayParts.join(' '); 91 } 92 93 // When the duration is 0, show 0 in terms of `units` 94 return pluralizeUnits(0, allUnits.findBy('suffix', units), longForm); 95 }