{"version":3,"sources":["../src/duration.ts"],"sourcesContent":["/**\n * Bunch of miscellaneous constants and utility functions related to handling\n * date and time durations.\n *\n * Note that month and year do not have fixed durations, and hence are excluded\n * from this file. Weeks have fixed durations, but are excluded because we\n * use days as the max duration supported.\n */\n\nimport {\n  HOURS_PER_DAY,\n  MINUTES_PER_HOUR,\n  MS_PER_DAY,\n  MS_PER_HOUR,\n  MS_PER_MINUTE,\n  MS_PER_SECOND,\n  SECONDS_PER_MINUTE,\n} from \"./timeConstants\";\n\nexport type Duration = {\n  days?: number;\n  hours?: number;\n  minutes?: number;\n  seconds?: number;\n  milliseconds?: number;\n};\n\n/**\n * One of: days, hours, minutes, seconds, milliseconds\n */\nexport type DurationType = keyof Duration;\n\n/**\n * Order in which the duration type appears in the duration string.\n */\nexport const DURATION_TYPE_SEQUENCE: DurationType[] = [\n  \"days\",\n  \"hours\",\n  \"minutes\",\n  \"seconds\",\n  \"milliseconds\",\n];\n\n/**\n * Follows the same format as Intl.DurationFormat.prototype.format().\n *\n * Short: 1 yr, 2 mths, 3 wks, 3 days, 4 hr, 5 min, 6 sec, 7 ms, 8 μs, 9 ns\n * Long: 1 year, 2 months, 3 weeks, 3 days, 4 hours, 5 minutes, 6 seconds,\n *       7 milliseconds, 8 microseconds, 9 nanoseconds\n * Narrow: 1y 2mo 3w 3d 4h 5m 6s 7ms 8μs 9ns\n */\nexport type DurationStyle = \"short\" | \"long\" | \"narrow\";\n\nexport type DurationSuffixMap = {\n  short: string;\n  shorts: string;\n  long: string;\n  longs: string;\n  narrow: string;\n};\n\nexport type DurationSuffixType = keyof DurationSuffixMap;\n\nexport const DURATION_STYLE_SUFFIX_MAP: Record<\n  DurationType,\n  DurationSuffixMap\n> = {\n  days: {\n    short: \"day\",\n    shorts: \"days\",\n    long: \"day\",\n    longs: \"days\",\n    narrow: \"d\",\n  },\n  hours: {\n    short: \"hr\",\n    shorts: \"hrs\",\n    long: \"hour\",\n    longs: \"hours\",\n    narrow: \"h\",\n  },\n  minutes: {\n    short: \"min\",\n    shorts: \"mins\",\n    long: \"minute\",\n    longs: \"minutes\",\n    narrow: \"m\",\n  },\n  seconds: {\n    short: \"sec\",\n    shorts: \"secs\",\n    long: \"second\",\n    longs: \"seconds\",\n    narrow: \"s\",\n  },\n  milliseconds: {\n    short: \"ms\",\n    shorts: \"ms\",\n    long: \"millisecond\",\n    longs: \"milliseconds\",\n    narrow: \"ms\",\n  },\n};\n\nfunction getDurationStyleForPlural(style: DurationStyle): DurationSuffixType {\n  return style == \"short\" ? \"shorts\" : style === \"long\" ? \"longs\" : style;\n}\n\nfunction getValueAndUnitSeparator(style: DurationStyle): string {\n  return style === \"narrow\" ? \"\" : \" \";\n}\n\nfunction getDurationTypeSeparator(style: DurationStyle): string {\n  return style === \"narrow\" ? \" \" : \", \";\n}\n\n/**\n * Convert a milliseconds duration into a Duration object. If the given ms is\n * zero, then return an object with a single field of zero with duration type\n * of durationTypeForZero.\n *\n * @param durationTypeForZero Defaults to 'milliseconds'\n */\nexport function msToDuration(\n  ms: number,\n  durationTypeForZero?: DurationType,\n): Duration {\n  if (ms === 0) {\n    durationTypeForZero = durationTypeForZero ?? \"milliseconds\";\n    return { [durationTypeForZero]: 0 };\n  }\n\n  const duration: Duration = {};\n\n  for (let i = 0; i < 1; i++) {\n    let seconds = Math.floor(ms / MS_PER_SECOND);\n    const millis = ms - seconds * MS_PER_SECOND;\n\n    if (millis > 0) {\n      duration[\"milliseconds\"] = millis;\n    }\n\n    if (seconds === 0) {\n      break;\n    }\n\n    let minutes = Math.floor(seconds / SECONDS_PER_MINUTE);\n    seconds -= minutes * SECONDS_PER_MINUTE;\n\n    if (seconds > 0) {\n      duration[\"seconds\"] = seconds;\n    }\n\n    if (minutes === 0) {\n      break;\n    }\n\n    let hours = Math.floor(minutes / MINUTES_PER_HOUR);\n    minutes -= hours * MINUTES_PER_HOUR;\n\n    if (minutes > 0) {\n      duration[\"minutes\"] = minutes;\n    }\n\n    if (hours === 0) {\n      break;\n    }\n\n    const days = Math.floor(hours / HOURS_PER_DAY);\n    hours -= days * HOURS_PER_DAY;\n\n    if (hours > 0) {\n      duration[\"hours\"] = hours;\n    }\n\n    if (days > 0) {\n      duration[\"days\"] = days;\n    }\n  }\n\n  return duration;\n}\n\n/**\n * Returns the number of milliseconds for the given duration.\n */\nexport function durationToMs(duration: Duration): number {\n  const daysMs = (duration.days ?? 0) * MS_PER_DAY;\n  const hoursMs = (duration.hours ?? 0) * MS_PER_HOUR;\n  const minsMs = (duration.minutes ?? 0) * MS_PER_MINUTE;\n  const secsMs = (duration.seconds ?? 0) * MS_PER_SECOND;\n  const msMs = duration.milliseconds ?? 0;\n\n  return daysMs + hoursMs + minsMs + secsMs + msMs;\n}\n\n/**\n * Convenience function to return a duration given an ms or Duration.\n */\nexport function durationOrMsToMs(duration: number | Duration): number {\n  return typeof duration === \"number\" ? duration : durationToMs(duration);\n}\n\n/**\n * Format a given Duration object into a string. If the object has no fields,\n * then returns an empty string.\n *\n * @param style Defaults to 'short'\n */\nexport function formatDuration(duration: Duration, style?: DurationStyle) {\n  style = style ?? \"short\";\n  const stylePlural = getDurationStyleForPlural(style);\n\n  const space = getValueAndUnitSeparator(style);\n\n  const a: string[] = [];\n\n  for (const unit of DURATION_TYPE_SEQUENCE) {\n    const value = duration[unit];\n    if (value === undefined) continue;\n\n    const suffixMap = DURATION_STYLE_SUFFIX_MAP[unit];\n    const suffix = value === 1 ? suffixMap[style] : suffixMap[stylePlural];\n    a.push(value + space + suffix);\n  }\n\n  const separator = getDurationTypeSeparator(style);\n  return a.join(separator);\n}\n\n/**\n * Convert a millisecond duration into a human-readable duration string.\n *\n * @param options.durationTypeForZero - Defaults to 'milliseconds'\n * @param options.style - Defaults to 'short'\n */\nexport function readableDuration(\n  ms: number,\n  options?: { durationTypeForZero?: DurationType; style?: DurationStyle },\n): string {\n  const duration = msToDuration(ms, options?.durationTypeForZero);\n\n  return formatDuration(duration, options?.style);\n}\n\n/** A shortened duration string useful for logging timings. */\nexport function elapsed(ms: number): string {\n  // Use long format for 1 minute or over.\n  if (ms > MS_PER_MINUTE) {\n    return readableDuration(ms);\n  }\n\n  // Use seconds format for over 100ms.\n  if (ms > 100) {\n    return `${(ms / 1000).toFixed(3)}s`;\n  }\n\n  // Use milliseconds format.\n  return ms + \"ms\";\n}\n"],"mappings":"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","names":["DURATION_TYPE_SEQUENCE","DURATION_STYLE_SUFFIX_MAP","getDurationStyleForPlural","style","getValueAndUnitSeparator","getDurationTypeSeparator","msToDuration","ms","durationTypeForZero","duration","seconds","millis","minutes","hours","days","durationToMs","daysMs","hoursMs","minsMs","secsMs","msMs","durationOrMsToMs","formatDuration","stylePlural","space","a","unit","value","suffixMap","suffix","separator","readableDuration","options","elapsed"]}