formatTimeAgo function

String formatTimeAgo(
  1. DateTime dateTime
)

This function calculates the time difference between the provided dateTime and the current moment (DateTime.now()) and returns a string in an approximate, user-friendly format.

Behavior for Past Times (ago):

  • Less than 1 second: "just now"
  • 1-59 seconds: "1 minute ago" (per specified requirement)
  • 1-59 minutes: "X minutes ago"
  • 1-23 hours: "X hours ago"
  • 1-6 days: "X days ago"
  • 1-4 weeks (approx): "X weeks ago"
  • 1-11 months (approx): "X months ago"
  • 1+ years (approx): "X years ago"

Behavior for Future Times (from now):

  • Less than 1 second: "just now"
  • 1-59 seconds: "in 1 minute"
  • 1-59 minutes: "in X minutes"
  • 1-23 hours: "in X hours"
  • 1-29 days: "in X days"
  • 1-11 months (approx): "in X months"
  • 1+ years (approx): "in X years"

Handles singular/plural forms for all units. Approximations for weeks, months, and years are based on fixed day counts (7 days/week, 30 days/month, 365 days/year).

@param dateTime The specific point in time to format. @return A string representing the relative time difference.

Implementation

String formatTimeAgo(DateTime dateTime) {
  final now = DateTime.now();
  final diff = now.difference(dateTime);

  /// chopLastCharacter
  String chopLast(String text) =>
      text.isEmpty ? '' : text.substring(0, text.length - 1);

  /// format Future Times
  String fmtFutureTimes(int n, TimeUnit unit) => switch (unit) {
        TimeUnit.justnow => TimeUnit.justnow.name,
        TimeUnit.unknown => TimeUnit.unknown.name,
        _ => 'in $n ${(n > 1) ? unit.name : chopLast(unit.name)}'
      };

  /// format Future Times
  String fmtPastTimes(int n, TimeUnit unit) => switch (unit) {
        TimeUnit.justnow => TimeUnit.justnow.name,
        TimeUnit.unknown => TimeUnit.unknown.name,
        _ => '$n ${(n > 1) ? unit.name : chopLast(unit.name)} ago'
      };

  if (diff.isNegative) {
    // Handling future times
    final fDiff = dateTime.difference(now);

    if (fDiff.inSeconds == 0) {
      return fmtFutureTimes(0, TimeUnit.justnow);
    } else if (fDiff.inMinutes == 0) {
      return fmtFutureTimes(1, TimeUnit.minutes);
    } else if (fDiff.inMinutes < 60) {
      return fmtFutureTimes(fDiff.inMinutes, TimeUnit.minutes);
    } else if (fDiff.inHours < 24) {
      return fmtFutureTimes(fDiff.inHours, TimeUnit.hours);
    } else if (diff.inDays < 7) {
      return fmtFutureTimes(diff.inDays, TimeUnit.days);
    } else if (fDiff.inDays < 30) {
      int weeks = (diff.inDays / 7).round();
      if (weeks == 0) weeks = 1;
      return fmtFutureTimes(weeks, TimeUnit.weeks);
    } else if (fDiff.inDays < 365) {
      int months = (fDiff.inDays / 30).round();
      if (months == 0) months = 1;
      return fmtFutureTimes(months, TimeUnit.months);
    } else {
      int years = (fDiff.inDays / 365).round();
      if (years == 0) years = 1;
      return fmtFutureTimes(years, TimeUnit.years);
    }
  }

  // Handling past times
  if (diff.inMinutes == 0) {
    return (diff.inSeconds == 0)
        ? fmtPastTimes(0, TimeUnit.justnow)
        : fmtPastTimes(1, TimeUnit.minutes);
  } else if (diff.inMinutes < 60) {
    return fmtPastTimes(diff.inMinutes, TimeUnit.minutes);
  } else if (diff.inHours < 24) {
    return fmtPastTimes(diff.inHours, TimeUnit.hours);
  } else if (diff.inDays < 7) {
    return fmtPastTimes(diff.inDays, TimeUnit.days);
  } else if (diff.inDays < 30) {
    int weeks = (diff.inDays / 7).round();
    if (weeks == 0) weeks = 1;
    return fmtPastTimes(weeks, TimeUnit.weeks);
  } else if (diff.inDays < 365) {
    int months = (diff.inDays / 30).round();
    if (months == 0) months = 1;
    return fmtPastTimes(months, TimeUnit.months);
  } else {
    int years = (diff.inDays / 365).round();
    if (years == 0) years = 1;
    return fmtPastTimes(years, TimeUnit.years);
  }
}