Mez
Mez

Reputation: 24953

Date Ordinal Output?

I'm wondering if there is a quick and easy way to output ordinals given a number in python.

For example, given the number 1, I'd like to output "1st", the number 2, "2nd", et cetera, et cetera.

This is for working with dates in a breadcrumb trail

Home >  Venues >  Bar Academy >  2009 >  April >  01 

is what is currently shown

I'd like to have something along the lines of

Home >  Venues >  Bar Academy >  2009 >  April >  1st

Upvotes: 30

Views: 13627

Answers (15)

Dustin Oprea
Dustin Oprea

Reputation: 10266

A transparent solution without any gymnastics:

_DATE_DAY_SUFFIXES = {
    1: 'st',
    2: 'nd',
    3: 'rd',
}

def day_suffix(d):

    if 10 <= d <= 19:
        return 'th'

    d = d % 10

    try:
        return _DATE_DAY_SUFFIXES[d]
    except KeyError:
        return 'th'

Upvotes: 0

Eric
Eric

Reputation: 254

I made a function that seems to work in this case. Just pass in a date object, and it will use the day to figure out the suffix. Hope it helps

from datetime import date
def get_day_ordinal(d):

    sDay = '%dth'
    if d.day <= 10 or d.day >= 21:
        sDay = '%dst' if d.day % 10 == 1 else sDay
        sDay = '%dnd' if d.day % 10 == 2 else sDay
        sDay = '%drd' if d.day % 10 == 3 else sDay

    return sDay % d.day

d = date.today()
print get_day_ordinal(d)

Upvotes: 3

Carl
Carl

Reputation: 853

These days I'd use Arrow http://arrow.readthedocs.io/en/latest/ (which definately wasn't around in '09)

>>> import arrow
>>> from datetime import datetime
>>> arrow.get(datetime.utcnow()).format('Do')
'27th'

Upvotes: 5

Michael Swartz
Michael Swartz

Reputation: 858

Here's a function I wrote as part of a calendar type of program I wrote (I'm not including the whole program). It adds on the correct ordinal for any number greater than 0. I included a loop to demo the output.

def ordinals(num):
    # st, nums ending in '1' except '11'
    if num[-1] == '1' and num[-2:] != '11':
        return num + 'st'
    # nd, nums ending in '2' except '12'
    elif num[-1] == '2' and num[-2:] != '12':
        return num + 'nd'
    # rd, nums ending in '3' except '13'
    elif num[-1] == '3' and num[-2:] != '13':
        return num + 'rd'
    # th, all other nums
    else:
        return num + 'th'

data = ''

# print the first 366 ordinals (for leap year)
for i in range(1, 367):
    data += ordinals(str(i)) + '\n'

# print results to file
with open('ordinals.txt', 'w') as wf:
   wf.write(data)

Upvotes: 0

SwiftsNamesake
SwiftsNamesake

Reputation: 1578

def ordinal(n):
    return ["th", "st", "nd", "rd"][n%10 if n%10<4 and not (10<n%100<14) else 0]

Upvotes: 1

alukach
alukach

Reputation: 6298

Not sure if it existed 5 years ago when you asked this question, but the inflect package has a function to do what you're looking for:

>>> import inflect
>>> p = inflect.engine()
>>> for i in range(1,32):
...     print p.ordinal(i)
...
1st
2nd
3rd
4th
5th
6th
7th
8th
9th
10th
11th
12th
13th
14th
15th
16th
17th
18th
19th
20th
21st
22nd
23rd
24th
25th
26th
27th
28th
29th
30th
31st

Upvotes: 13

Frosty Snowman
Frosty Snowman

Reputation: 525

I had to convert a script over from javascript where I had a useful fn that replicated phps date obj. Very similar

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

this tied in with my date styler:

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

ps -I got here from another thread which was reported as a duplicate but it wasn't entirely since that thread also addressed the date issue

Upvotes: 0

Houngan
Houngan

Reputation: 69

I wanted to use ordinals for a project of mine and after a few prototypes I think this method although not small will work for any positive integer, yes any integer.

It works by determiniting if the number is above or below 20, if the number is below 20 it will turn the int 1 into the string 1st , 2 , 2nd; 3, 3rd; and the rest will have "st" added to it.

For numbers over 20 it will take the last and second to last digits, which I have called the tens and unit respectively and test them to see what to add to the number.

This is in python by the way, so I'm not sure if other languages will be able to find the last or second to last digit on a string if they do it should translate pretty easily.

def o(numb):
    if numb < 20: #determining suffix for < 20
        if numb == 1: 
            suffix = 'st'
        elif numb == 2:
            suffix = 'nd'
        elif numb == 3:
            suffix = 'rd'
        else:
            suffix = 'th'  
    else:   #determining suffix for > 20
        tens = str(numb)
        tens = tens[-2]
        unit = str(numb)
        unit = unit[-1]
        if tens == "1":
           suffix = "th"
        else:
            if unit == "1": 
                suffix = 'st'
            elif unit == "2":
                suffix = 'nd'
            elif unit == "3":
                suffix = 'rd'
            else:
                suffix = 'th'
    return str(numb)+ suffix

I called the function "o" for ease of use and can be called by importing the file name which I called "ordinal" by import ordinal then ordinal.o(number).

Let me know what you think :D

P.S. I've posted this answer on another ordinals question but realised this one is more applicable considering it's python.

Upvotes: 0

Abizern
Abizern

Reputation: 150675

Or shorten David's answer with:

if 4 <= day <= 20 or 24 <= day <= 30:
    suffix = "th"
else:
    suffix = ["st", "nd", "rd"][day % 10 - 1]

Upvotes: 48

Vinicius Spader
Vinicius Spader

Reputation: 113

A more general and shorter solution (as a function):

def get_ordinal(num)
    ldig = num % 10
    l2dig = (num // 10) % 10

    if (l2dig == 1) or (ldig > 3):
        return '%d%s' % (num, 'th')
    else:
        return '%d%s' % (num, {1: 'st', 2: 'nd', 3: 'rd'}.get(ldig))

I just combined David's solutions and libraries (as deegeedubs did). You can even replace the variables (ldig, l2dig) for the real math (since l2dig is used only once), then you get four lines of code.

Upvotes: 3

David Z
David Z

Reputation: 131650

Except for 1st, 2nd, and 3rd, I think they all just add th... 4th, 5th, 6th, 11th, 21st ... oh, oops ;-)

I think this might work:

def ordinal(num):
     ldig = num % 10
     l2dig = (num // 10) % 10
     if l2dig == 1:
         suffix = 'th'
     elif ldig == 1:
         suffix = 'st'
     elif ldig == 2:
         suffix = 'nd'
     elif ldig == 3:
         suffix = 'rd'
     else: 
         suffix = 'th'
     return '%d%s' % (num, suffix)

Upvotes: 1

not-just-yeti
not-just-yeti

Reputation: 17933

Fixed for negative-inputs, based on eric.frederich's nice sol'n (just added abs when using %):

def ordinal(num):
    return '%d%s' % (num, { 11: 'th', 12: 'th', 13: 'th'}.get(abs(num) % 100, { 1: 'st',2: 'nd',3: 'rd',}.get(abs(num) % 10, 'th')))

Upvotes: 1

deegeedubb
deegeedubb

Reputation: 1

Here is an even shorter general solution:

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

Although the other solutions above are probably easier to understand at first glance, this works just as well while using a bit less code.

Upvotes: 0

eric.frederich
eric.frederich

Reputation: 1668

Here it is using dictionaries as either a function or as a lambda...

If you look at the dictionaries backwards you can read it as...

Everything ends in 'th'

...unless it ends in 1, 2, or 3 then it ends in 'st', 'nd', or 'rd'

...unless it ends in 11, 12, or 13 then it ends in 'th, 'th', or 'th'

# as a function
def ordinal(num):
    return '%d%s' % (num, { 11: 'th', 12: 'th', 13: 'th' }.get(num % 100, { 1: 'st',2: 'nd',3: 'rd',}.get(num % 10, 'th')))

# as a lambda
ordinal = lambda num : '%d%s' % (num, { 11: 'th', 12: 'th', 13: 'th' }.get(num % 100, { 1: 'st',2: 'nd',3: 'rd',}.get(num % 10, 'th')))

Upvotes: 3

CTT
CTT

Reputation: 17641

Here's a more general solution:

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

Upvotes: 30

Related Questions