Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions src/humanize/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,14 +319,20 @@ def naturalday(value: dt.date | dt.datetime, format: str = "%b %d") -> str:
import datetime as dt

try:
# When value is a tz-aware datetime, compute "today" in that timezone
# so the comparison uses the correct local date.
if isinstance(value, dt.datetime) and value.tzinfo is not None:
today = dt.datetime.now(value.tzinfo).date()
else:
today = dt.date.today()
value = dt.date(value.year, value.month, value.day)
except AttributeError:
# Passed value wasn't date-ish
return str(value)
except (OverflowError, ValueError):
# Date arguments out of range
return str(value)
delta = value - dt.date.today()
delta = value - today

if delta.days == 0:
return _("today")
Expand All @@ -344,18 +350,23 @@ def naturaldate(value: dt.date | dt.datetime) -> str:
"""Like `naturalday`, but append a year for dates more than ~five months away."""
import datetime as dt

original_value = value
try:
if isinstance(value, dt.datetime) and value.tzinfo is not None:
today = dt.datetime.now(value.tzinfo).date()
else:
today = dt.date.today()
value = dt.date(value.year, value.month, value.day)
except AttributeError:
# Passed value wasn't date-ish
return str(value)
except (OverflowError, ValueError):
# Date arguments out of range
return str(value)
delta = _abs_timedelta(value - dt.date.today())
delta = _abs_timedelta(value - today)
if delta.days >= 5 * 365 / 12:
return naturalday(value, "%b %d %Y")
return naturalday(value)
return naturalday(original_value, "%b %d %Y")
return naturalday(original_value)


def _quotient_and_remainder(
Expand Down
26 changes: 26 additions & 0 deletions tests/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,32 @@ def test_naturaldate(test_input: dt.date, expected: str) -> None:
assert humanize.naturaldate(test_input) == expected


@freeze_time("2023-10-15 23:00:00+00:00")
def test_naturaldate_tz_aware() -> None:
"""naturaldate should compare dates in the timezone of the given value."""
utc = dt.timezone.utc
aedt = dt.timezone(dt.timedelta(hours=11))
cest = dt.timezone(dt.timedelta(hours=2))
edt = dt.timezone(dt.timedelta(hours=-4))
pdt = dt.timezone(dt.timedelta(hours=-7))
future = dt.datetime(2023, 10, 16, hour=6, tzinfo=utc)

# UTC: now is Oct 15, future is Oct 16 => tomorrow
assert humanize.naturaldate(future) == "tomorrow"

# AEDT (+11): now is Oct 16 10:00, future is Oct 16 17:00 => today
assert humanize.naturaldate(future.astimezone(aedt)) == "today"

# CEST (+2): now is Oct 16 01:00, future is Oct 16 08:00 => today
assert humanize.naturaldate(future.astimezone(cest)) == "today"

# EDT (-4): now is Oct 15 19:00, future is Oct 16 02:00 => tomorrow
assert humanize.naturaldate(future.astimezone(edt)) == "tomorrow"

# PDT (-7): now is Oct 15 16:00, future is Oct 15 23:00 => today
assert humanize.naturaldate(future.astimezone(pdt)) == "today"


@pytest.mark.parametrize(
"seconds, expected",
[
Expand Down
Loading