[Django]-Python format datetime with "st", "nd", "rd", "th" (english ordinal suffix) like PHP's "S"

34👍

The django.utils.dateformat has a function format that takes two arguments, the first one being the date (a datetime.date [[or datetime.datetime]] instance, where datetime is the module in Python’s standard library), the second one being the format string, and returns the resulting formatted string. The uppercase-S format item (if part of the format string, of course) is the one that expands to the proper one of ‘st’, ‘nd’, ‘rd’ or ‘th’, depending on the day-of-month of the date in question.

27👍

dont know about built in but I used this…

def ordinal(n):
    return str(n)+("th" if 4<=n%100<=20 else {1:"st",2:"nd",3:"rd"}.get(n%10, "th"))

and:

def dtStylish(dt,f):
    return dt.strftime(f).replace("{th}", ordinal(dt.day))

dtStylish can be called as follows to get Thu the 2nd at 4:30. Use {th} where you want to put the day of the month ("%d" python format code)

dtStylish(datetime(2019, 5, 2, 16, 30), '%a the {th} at %I:%M')

13👍

You can do this simply by using the humanize library

from django.contrib.humanize.templatetags.humanize import ordinal

You can then just give ordinal any integer, ie

ordinal(2) will return 2nd

10👍

I’ve just written a small function to solve the same problem within my own code:

def foo(myDate):
    date_suffix = ["th", "st", "nd", "rd"]

    if myDate % 10 in [1, 2, 3] and myDate not in [11, 12, 13]:
        return date_suffix[myDate % 10]
    else:
        return date_suffix[0]
👤Edster

1👍

My own version. Use python’s strftime’s format codes, substituting {th} where you want to see the ordinal suffix.

def format_date_with_ordinal(d, format_string):
    ordinal = {'1':'st', '2':'nd', '3':'rd'}.get(str(d.day)[-1:], 'th')
    return d.strftime(format_string).replace('{th}', ordinal)

or

format_date_with_ordinal = lambda d,f: d.strftime(f).replace('{th}', {'1':'st', '2':'nd', '3':'rd'}.get(str(d.day)[-1:], 'th'))

1👍

Here’s something that I use:

def get_ordinal_suffix(day: int) -> str:
    return {1: 'st', 2: 'nd', 3: 'rd'}.get(day % 10, 'th') if day not in (11, 12, 13) else 'th'

0👍

Implementing @Frosty Snomwan’s Method And An Expansion Of It

When I first tried to implement Frosty Snowman’s outstanding answer, I misapplied it in my haste. His is the ord2 function below. My "not as good function" is ord1. He passes in a number. Mine takes a string. Both could be easily edited to receive different input types. I will be using his function, but I thought some codes might find the full "experimental" implementation of both helpful.

from datetime import datetime


def ord1(n):
    if 4 <= int(n) <= 20 or int(n[-1]) >= 4 or int(n[-1]) == 0:
        return f"{n}th"
    elif int(n[-1]) == 1:
        return f"{n}st"
    elif int(n[-1]) == 2:
        return f"{n}nd"
    elif int(n[-1]) == 3:
        return f"{n}rd"


def ord2(n):
    return str(n) + (
        "th" if 4 <= n % 100 <= 20 else {1: "st", 2: "nd", 3: "rd"}.get(n % 10, "th")
    )


today = datetime.now()
date = today.strftime("%d")
date = ord2(int(date))
full_date_time = today.strftime(f"%A, {date} %B %Y %I:%M:%S %p")
print(full_date_time)

for date in range(1, 32, 1):
    date_ord1 = ord1(str(date))
    date_ord2 = ord2(date)
    print(date_ord1, date_ord2)

Output is

Monday, 21st August 2023 01:33:11 PM
1st 1st
2nd 2nd
3rd 3rd
4th 4th
5th 5th
... all th's ...
20th 20th
21st 21st
22nd 22nd
23rd 23rd
24th 24th
... all th's ...
30th 30th
31st 31st

I final functional form that might be more overall useful would be …

def format_date_time(a_date_time):
    date = a_date_time.strftime("%d")
    d = int(date)
    date = date + (
        "th" if 4 <= d % 100 <= 20 else {1: "st", 2: "nd", 3: "rd"}.get(d % 10, "th")
    )
    full_date_time = a_date_time.strftime(f"%A, {date} %B %Y %I:%M:%S %p")
    
    return full_date_time

-2👍

Following solution I got for above problem:

datetime.strptime(mydate, '%dnd %B %Y')
datetime.strptime(mydate, '%dst %B %Y')
datetime.strptime(mydate, '%dth %B %Y')
datetime.strptime(mydate, '%drd %B %Y')
👤eegloo

Leave a comment