Repository: locustio/locust
File: locust/util/date.py (Python)

Code before:
import decimal
import numbers
import re
from datetime import datetime, timedelta, timezone


def format_utc_timestamp(unix_timestamp):
    return datetime.fromtimestamp(unix_timestamp, timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")


def format_safe_timestamp(unix_timestamp):
    return datetime.fromtimestamp(unix_timestamp).strftime("%Y-%m-%d-%Hh%M")


def format_duration(start_unix_timestamp, end_unix_timestamp):
    """
    Format a timespan between two timestamps as a human readable string.
    Taken from xolox/python-humanfriendly

    :param start_unix_timestamp: Start timestamp.
    :param end_unix_timestamp: End timestamp.

    """
    # Common time units, used for formatting of time spans.
    time_units = (
        dict(divider=1e-9, singular="nanosecond", plural="nanoseconds", abbreviations=["ns"]),
        dict(divider=1e-6, singular="microsecond", plural="microseconds", abbreviations=["us"]),
        dict(divider=1e-3, singular="millisecond", plural="milliseconds", abbreviations=["ms"]),
        dict(divider=1, singular="second", plural="seconds", abbreviations=["s", "sec", "secs"]),
        dict(divider=60, singular="minute", plural="minutes", abbreviations=["m", "min", "mins"]),
        dict(divider=60 * 60, singular="hour", plural="hours", abbreviations=["h"]),
        dict(divider=60 * 60 * 24, singular="day", plural="days", abbreviations=["d"]),
        dict(divider=60 * 60 * 24 * 7, singular="week", plural="weeks", abbreviations=["w"]),
        dict(divider=60 * 60 * 24 * 7 * 52, singular="year", plural="years", abbreviations=["y"]),
    )

    num_seconds = coerce_seconds(
        end_unix_timestamp - start_unix_timestamp,
    )
    if num_seconds < 60:
        # Fast path.
        return pluralize(round_number(num_seconds), "second")
    else:
        # Slow path.
        result = []
        num_seconds = decimal.Decimal(str(num_seconds))
        relevant_units = list(reversed(time_units[3:]))
        for unit in relevant_units:
            # Extract the unit count from the remaining time.
            divider = decimal.Decimal(str(unit["divider"]))
            count = num_seconds / divider

Review comment (suggestion):
Sorry maybe it wasn't clear, but I think an argument for using our own solution, rather than the library, is because as you can probably see, the library handles a lot more cases than we probably need. In Locust's case, we probably never need nanoseconds, microseconds, weeks, or years. I think we could go with a simpler approach, for example:
```
def format_duration(start_time, end_time):
    time_diff = end_time - start_time

    days = time_diff.days
    seconds = time_diff.seconds
    hours = seconds // 3600
    minutes = (seconds % 3600) // 60
    seconds = seconds % 60

    return f"{days} days, {hours} hours, {minutes} minutes, {seconds} seconds"
```
(disclaimer: ChatGPT)

Code after:
from datetime import datetime, timezone


def format_utc_timestamp(unix_timestamp):
    return datetime.fromtimestamp(int(unix_timestamp), timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")


def format_safe_timestamp(unix_timestamp):
    return datetime.fromtimestamp(int(unix_timestamp)).strftime("%Y-%m-%d-%Hh%M")


def format_duration(start_time, end_time):
    seconds = int(end_time) - int(start_time)
    days = seconds // 86400
    hours = (seconds % 86400) // 3600
    minutes = (seconds % 3600) // 60
    seconds = seconds % 60

    time_parts = [(days, "day"), (hours, "hour"), (minutes, "minute"), (seconds, "second")]

    parts = [f"{value} {label}{'s' if value != 1 else ''}" for value, label in time_parts if value > 0]

    return " and ".join(filter(None, [", ".join(parts[:-1])] + parts[-1:])) if parts else "0 seconds"