1717from django .template .loader import render_to_string
1818from django .urls import reverse
1919from django .utils import timezone
20+ from django .utils .formats import date_format
2021from django .utils .formats import number_format as django_number_format
2122from django .utils .html import escape , format_html , format_html_join , linebreaks , urlize
2223from django .utils .safestring import mark_safe
@@ -731,118 +732,39 @@ def show_message(tags, message):
731732 return {"tags" : " " .join (final ), "task_id" : task_id , "message" : message }
732733
733734
734- def naturaltime_past (value , now ) :
735- """Convert past dates to natural time."""
735+ def naturaltime_text (value : datetime , now : datetime ) -> str :
736+ """Convert date to natural time."""
736737 delta = now - value
737738
738- if delta .days >= 365 :
739- count = delta .days // 365
740- if count == 1 :
741- return gettext ("a year ago" )
742- return ngettext ("%(count)s year ago" , "%(count)s years ago" , count ) % {
743- "count" : count
744- }
745- if delta .days >= 30 :
746- count = delta .days // 30
747- if count == 1 :
748- return gettext ("a month ago" )
749- return ngettext ("%(count)s month ago" , "%(count)s months ago" , count ) % {
750- "count" : count
751- }
752- if delta .days >= 14 :
753- count = delta .days // 7
754- return ngettext ("%(count)s week ago" , "%(count)s weeks ago" , count ) % {
755- "count" : count
756- }
757- if delta .days > 0 :
758- if delta .days == 7 :
759- return gettext ("a week ago" )
760- if delta .days == 1 :
761- return gettext ("yesterday" )
762- return ngettext ("%(count)s day ago" , "%(count)s days ago" , delta .days ) % {
763- "count" : delta .days
764- }
765- if delta .seconds == 0 :
766- return gettext ("now" )
767- if delta .seconds < 60 :
768- if delta .seconds == 1 :
769- return gettext ("a second ago" )
770- return ngettext (
771- "%(count)s second ago" , "%(count)s seconds ago" , delta .seconds
772- ) % {"count" : delta .seconds }
773- if delta .seconds // 60 < 60 :
774- count = delta .seconds // 60
739+ if value < now and delta .days < 0 :
740+ if delta .seconds == 0 :
741+ return gettext ("now" )
742+ if delta .seconds < 60 :
743+ if delta .seconds == 1 :
744+ return gettext ("a second ago" )
745+ return ngettext (
746+ "%(count)s second ago" , "%(count)s seconds ago" , delta .seconds
747+ ) % {"count" : delta .seconds }
748+ if delta .seconds // 60 < 60 :
749+ count = delta .seconds // 60
750+ if count == 1 :
751+ return gettext ("a minute ago" )
752+ return ngettext ("%(count)s minute ago" , "%(count)s minutes ago" , count ) % {
753+ "count" : count
754+ }
755+ count = delta .seconds // 60 // 60
775756 if count == 1 :
776- return gettext ("a minute ago" )
777- return ngettext ("%(count)s minute ago" , "%(count)s minutes ago" , count ) % {
757+ return gettext ("an hour ago" )
758+ return ngettext ("%(count)s hour ago" , "%(count)s hours ago" , count ) % {
778759 "count" : count
779760 }
780- count = delta .seconds // 60 // 60
781- if count == 1 :
782- return gettext ("an hour ago" )
783- return ngettext ("%(count)s hour ago" , "%(count)s hours ago" , count ) % {
784- "count" : count
785- }
786-
787-
788- def naturaltime_future (value , now ):
789- """Convert future dates to natural time."""
790- delta = value - now
791-
792- if delta .days >= 365 :
793- count = delta .days // 365
794- if count == 1 :
795- return gettext ("a year from now" )
796- return ngettext (
797- "%(count)s year from now" , "%(count)s years from now" , count
798- ) % {"count" : count }
799- if delta .days >= 30 :
800- count = delta .days // 30
801- if count == 1 :
802- return gettext ("a month from now" )
803- return ngettext (
804- "%(count)s month from now" , "%(count)s months from now" , count
805- ) % {"count" : count }
806- if delta .days >= 14 :
807- count = delta .days // 7
808- return ngettext (
809- "%(count)s week from now" , "%(count)s weeks from now" , count
810- ) % {"count" : count }
811- if delta .days > 0 :
812- if delta .days == 1 :
813- return gettext ("tomorrow" )
814- if delta .days == 7 :
815- return gettext ("a week from now" )
816- return ngettext (
817- "%(count)s day from now" , "%(count)s days from now" , delta .days
818- ) % {"count" : delta .days }
819- if delta .seconds == 0 :
820- return gettext ("now" )
821- if delta .seconds < 60 :
822- if delta .seconds == 1 :
823- return gettext ("a second from now" )
824- return ngettext (
825- "%(count)s second from now" , "%(count)s seconds from now" , delta .seconds
826- ) % {"count" : delta .seconds }
827- if delta .seconds // 60 < 60 :
828- count = delta .seconds // 60
829- if count == 1 :
830- return gettext ("a minute from now" )
831- return ngettext (
832- "%(count)s minute from now" , "%(count)s minutes from now" , count
833- ) % {"count" : count }
834- count = delta .seconds // 60 // 60
835- if count == 1 :
836- return gettext ("an hour from now" )
837- return ngettext ("%(count)s hour from now" , "%(count)s hours from now" , count ) % {
838- "count" : count
839- }
761+ return date_format (value , "SHORT_DATETIME_FORMAT" )
840762
841763
842764@register .filter (is_safe = True )
843765def naturaltime (
844766 value : float | datetime , microseconds : bool = False , * , now : datetime | None = None
845- ):
767+ ) -> SafeString :
846768 """
847769 Heavily based on Django's django.contrib.humanize implementation of naturaltime.
848770
@@ -860,10 +782,7 @@ def naturaltime(
860782 if now is None :
861783 now = timezone .now ()
862784
863- if value < now :
864- text = naturaltime_past (value , now )
865- else :
866- text = naturaltime_future (value , now )
785+ text = naturaltime_text (value , now )
867786
868787 # Strip microseconds
869788 if isinstance (value , datetime ) and not microseconds :
0 commit comments