diff --git a/lib/utils/text.py b/lib/utils/text.py index c51d7292c7dde2965b5df07cd630add3b87ed07f..e55baaa9b126d29087b73222552fe65887099be1 100644 --- a/lib/utils/text.py +++ b/lib/utils/text.py @@ -486,3 +486,29 @@ def BuildShellCmd(template, *args): raise errors.ProgrammerError("Shell argument '%s' contains" " invalid characters" % word) return template % args + + +def FormatOrdinal(value): + """Formats a number as an ordinal in the English language. + + E.g. the number 1 becomes "1st", 22 becomes "22nd". + + @type value: integer + @param value: Number + @rtype: string + + """ + tens = value % 10 + + if value > 10 and value < 20: + suffix = "th" + elif tens == 1: + suffix = "st" + elif tens == 2: + suffix = "nd" + elif tens == 3: + suffix = "rd" + else: + suffix = "th" + + return "%s%s" % (value, suffix) diff --git a/test/ganeti.utils.text_unittest.py b/test/ganeti.utils.text_unittest.py index 2bc0c23b4d9ed8dfd0b8a9b59a93e143966e8e59..417a0016591b3f086462fde5c2de63945e9ec69e 100755 --- a/test/ganeti.utils.text_unittest.py +++ b/test/ganeti.utils.text_unittest.py @@ -438,5 +438,21 @@ class TestBuildShellCmd(unittest.TestCase): self.assertEqual(utils.BuildShellCmd("ls %s", "ab"), "ls ab") +class TestOrdinal(unittest.TestCase): + def test(self): + checks = { + 0: "0th", 1: "1st", 2: "2nd", 3: "3rd", 4: "4th", 5: "5th", 6: "6th", + 7: "7th", 8: "8th", 9: "9th", 10: "10th", 11: "11th", 12: "12th", + 13: "13th", 14: "14th", 15: "15th", 16: "16th", 17: "17th", + 18: "18th", 19: "19th", 20: "20th", 21: "21st", 25: "25th", 30: "30th", + 32: "32nd", 40: "40th", 50: "50th", 55: "55th", 60: "60th", 62: "62nd", + 70: "70th", 80: "80th", 83: "83rd", 90: "90th", 91: "91st", + 582: "582nd", 999: "999th", + } + + for value, ordinal in checks.items(): + self.assertEqual(utils.FormatOrdinal(value), ordinal) + + if __name__ == "__main__": testutils.GanetiTestProgram()