All files / app/utils timeAgo.ts

84% Statements 42/50
77.77% Branches 14/18
66.66% Functions 4/6
85.71% Lines 36/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116    27x 27x 30x 27x 27x 27x 27x             34x                     14x   547x 547x       540x 2x   538x 1x         537x 2x         535x 1x   534x 1x         533x 26x         507x                         533x   1x       1x           25x   506x         534x                 534x 534x 534x   534x   1x     533x    
import { TFunction } from "i18next";
 
export const secondMillis = 1000;
export const minuteMillis = 60 * secondMillis;
export const hourMillis = 60 * minuteMillis;
export const dayMillis = 24 * hourMillis;
export const weekMillis = 7 * dayMillis;
export const monthMillis = 30 * dayMillis;
export const yearMillis = 365 * dayMillis + 6 * hourMillis; // 365.25;
 
interface FuzzySpecT {
  millis: number;
  translationKey: Parameters<TFunction<"global", undefined>>[0];
}
 
export enum TimeUnit {
  Seconds,
  Minutes,
  Hours,
  Days,
  Weeks,
  Months,
  Years,
}
 
/// A time span represented in human-friendly units, e.g. "5 days".
export class FriendlyTimeSpan {
  constructor(
    public value: number,
    public unit: TimeUnit,
  ) {}
 
  static fromMillis(value: number): FriendlyTimeSpan {
    if (value < minuteMillis) {
      return new FriendlyTimeSpan(Math.floor(value / 1000), TimeUnit.Seconds);
    }
    if (value < hourMillis) {
      return new FriendlyTimeSpan(
        Math.floor(value / minuteMillis),
        TimeUnit.Minutes,
      );
    }
    if (value < dayMillis) {
      return new FriendlyTimeSpan(
        Math.floor(value / hourMillis),
        TimeUnit.Hours,
      );
    }
    if (value < weekMillis) {
      return new FriendlyTimeSpan(Math.floor(value / dayMillis), TimeUnit.Days);
    }
    if (value < monthMillis) {
      return new FriendlyTimeSpan(
        Math.floor(value / weekMillis),
        TimeUnit.Weeks,
      );
    }
    if (value < yearMillis) {
      return new FriendlyTimeSpan(
        Math.floor(value / monthMillis),
        TimeUnit.Months,
      );
    }
    return new FriendlyTimeSpan(Math.floor(value / yearMillis), TimeUnit.Years);
  }
 
  static between(start: Date, end: Date): FriendlyTimeSpan {
    const diffMillis = end.getTime() - start.getTime();
    return FriendlyTimeSpan.fromMillis(diffMillis);
  }
 
  static since(date: Date): FriendlyTimeSpan {
    return this.between(date, new Date());
  }
 
  toLocalizedAgoText(t: TFunction<"global", undefined>): string {
    switch (this.unit) {
      case TimeUnit.Seconds:
        return t("relative_time.less_than_a_minute_ago");
      case TimeUnit.Minutes:
        return t("relative_time.n_minutes_ago", { count: this.value });
      case TimeUnit.Hours:
        return t("relative_time.n_hours_ago", { count: this.value });
      case TimeUnit.Days:
        return t("relative_time.n_days_ago", { count: this.value });
      case TimeUnit.Weeks:
        return t("relative_time.n_weeks_ago", { count: this.value });
      case TimeUnit.Months:
        return t("relative_time.n_months_ago", { count: this.value });
      case TimeUnit.Years:
        return t("relative_time.n_years_ago", { count: this.value });
    }
  }
}
 
export function timeAgoI18n({
  input,
  t,
  fuzzy = undefined,
}: {
  input: Date | string;
  t: TFunction<"global", undefined>;
  fuzzy?: FuzzySpecT;
}) {
  Iif (input === undefined) return "";
  const date = new Date(input);
  const diffMillis = Date.now() - date.getTime();
 
  if (fuzzy && diffMillis < fuzzy.millis) {
    // if fuzzyMillis and fuzzyText are both set, then for times less than fuzzyMillis, we return fuzzyText
    return t(fuzzy.translationKey) as string;
  }
 
  return FriendlyTimeSpan.fromMillis(diffMillis).toLocalizedAgoText(t);
}