# Daily Challenge #296 - Years to Centuries

The first century spans from the year 1 up to and including the year 100, The second - from the year 101 up to and including the year 200, etc. Return the century of the input year.

### Examples

"1999" --> "20th"
"2011" --> "21st"
"2154" --> "22nd"
"2259" --> "23rd"
"1124" --> "12th"
"2000" --> "21st"
"20000" --> "210th"

### Tests

8120
30200
1601
2020
3030
1900
1776

Good luck!

This challenge comes from Cpt.ManlyPink on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

### Discussion const toCentury = (year) => {
const century = Math.ceil(year / 100);
if (century.toString().length > 2) return year + " --> " + century + "th";
switch(century % 10) {
case 1: return year + " --> " + century + "st";
case 2: return year + " --> " + century + "nd";
case 3: return year + " --> " + century + "rd";
default: return year + " --> " + century + "th";
}
}


Clean and elegant!

"1066 --> 11st" should be 11th
"10266 --> 103th" should be 103rd

[deleted]

But according to the math, 1 - 100 is 1st century. So I thought 1901 - 2000 is 20th century and 2001 - 2100 is 21st century. Is my understanding wrong ?

This question has conflicts.

"20000" --> "210th" (should it be 201st?)

In the question:

"The first century spans from the year 1 up to and including the year 100, The second - from the year 101 up to and including the year 200, etc. Return the century of the input year"

but toCentury(2000) -> 21st?

Good question. I didn't notice that in the test cases.

Here is my golang solution


package main

import (
"fmt"
)

func getSuffix(number int) string {
if number%100 >= 11 && number%100 <= 13 {
return "th"
}
switch number%10 {
case 1:
return "st"
case 2:
return "nd"
case 3:
return "rd"
}

return "th"
}

func yearToCentury(year int) string {
century := year / 100

return fmt.Sprintf("%d%s century", century+1, getSuffix(century+1))
}

func main() {
tests := []int{1999, 2011, 2154, 2259, 1124, 2000, 20000}

for _, year := range tests {
fmt.Printf("%d --> %s\n", year, yearToCentury(year))
}
}



I think, it will be 112nd century, because, current, 2020 year is inside of 21st century :)

It should be 112th not 112nd, because 12 gets a th

ohhhh, it was grammatically mistake, sorry

Here's a typescript implementation, and a ✨verbose-and-pretty✨ reference to check it against.
It's funny, but I take much more care with these little easy tasks than I used to. There's always more nuance than you expect and the implementations end up sitting at the bottom of your library being used for everything.

(btw, I tend to use ~~ as an alternative to of Math.floor because it's more succinct, and most often a little quicker)

function suffixForOrdinal(ordinal: number): string {
return (~~(ordinal / 10) % 10 !== 1 && ['th', 'st', 'nd', 'rd'][ordinal % 10]) || 'th';
}

function nameOfCentury(yearOrdinal: string | number): string {
const centuryOrdinal = ~~((+yearOrdinal + 99) / 100);
return ${centuryOrdinal}${suffixForOrdinal(centuryOrdinal)};
}


I'll check my working by comparing with a naive implementation that's more readable and hopefully reliable out of the gate...

// Stringifying the ordinal is an easier way to get individual the parts of the year...
function suffixForOrdinal_slowButSure(ordinal: number): string {
const ordinalString = String(ordinal),
tens = +ordinalString.slice(-2, -1),
ones = +ordinalString.slice(-1);
if (tens == 1) return 'th'; // i.e. 11th, not 11st
if (ones == 1) return 'st'; // 81st
if (ones == 2) return 'nd'; // 82nd
if (ones == 3) return 'rd'; // 83rd
return 'th'; // anything else is 'th'. 45th
}

function nameOfCentury_slowButSure(yearOrdinal: string | number): string {
// When extracting the century we need to be working with the index, not ordinal.
// That's why the weirdness about 2000 -> 20th, 2001 -> 21st
//    (The year 2000 as an ordinal has index 1999)
const yearIndex = +yearOrdinal - 1,
yearIndexString = String(yearIndex),
centuryIndex = +yearIndexString.slice(0, -2) || 0,
centuryOrdinal = centuryIndex + 1;
return ${centuryOrdinal}${suffixForOrdinal_slowButSure(centuryOrdinal)};
}

// Now do some 'testing' by comparing the implementations
// This ensures that either both are right or both are wrong,
//   I'm pretty sure that the verbose one is as right as any static fixtures I could make.
(function hareVsTortoise(startYearOrdinal = 1, endYearOrdinal = 100000) {
for (let yearOrdinal = startYearOrdinal; yearOrdinal <= endYearOrdinal; yearOrdinal++) {
if (nameOfCentury(yearOrdinal) !== nameOfCentury_slowButSure(yearOrdinal)) {
console.error(
Conflicting answers for year ${yearOrdinal}:\n Hare: "${nameOfCentury(
yearOrdinal
)}"\n  Tortoise: "${nameOfCentury_slowButSure(yearOrdinal)}" ); return; } } console.log(Checked${endYearOrdinal + 1 - startYearOrdinal} years, all seems good);
})();

/*-->
Checked 100000 years, all seems good

[1, 99, 100, 101, 200, 300, 400, 1000, 1100, 1200, 1300, 1400, 1900, 2000, 2001, 2020, 10000, 10100].forEach(year => {
console.log(Year ${year} -->${nameOfCentury(year)});
});

/*-->
Year 1 --> 1st
Year 99 --> 1st
Year 100 --> 1st
Year 101 --> 2nd
Year 200 --> 2nd
Year 300 --> 3rd
Year 400 --> 4th
Year 1000 --> 10th
Year 1100 --> 11th
Year 1200 --> 12th
Year 1300 --> 13th
Year 1400 --> 14th
Year 1900 --> 19th
Year 2000 --> 20th
Year 2001 --> 21st
Year 2020 --> 21st
Year 10000 --> 100th
Year 10100 --> 101st


import Numeric.Natural (Natural)

toCentury :: Natural -> String
toCentury = suffix . ceiling . (/ 100) . (+ 1) . fromIntegral
where
suffix x
| x mod 10 == 1 = show x <> "st"
| x mod 10 == 2 = show x <> "nd"
| x mod 10 == 3 = show x <> "rd"
| otherwise       = show x <> "th"


The ruby example

def ordinalize(number)
case number % 10
when 1
"st"
when 2
"nd"
when 3
"rd"
else
"th"
end
end

def test_years(years_array)
years_array.each do |year|
correction = 0
if year % 100 == 0
correction = 1
end
result = (year/100.0).ceil + correction
puts "#{year} --> #{result}#{ordinalize(result)}"
end
end

puts "Example scope:"
test_years([1999, 2011, 2154, 2259, 1124, 2000, 20000])
puts "Test scope:"
test_years([8120, 30200, 1601, 2020, 3030, 1900, 1776])


And one-line style with activesupport gem installed

 [{name: "Example", years: [1999, 2011, 2154, 2259, 1124, 2000, 20000]},
{name: "Test", years: [8120, 30200, 1601, 2020, 3030, 1900, 1776]}].
each{ |scope| puts "#{scope[:name]} scope:"; scope[:years].
each{ |year| year % 100 == 0 ? correction = 1 : correction = 0;
result = (year/100.0).ceil + correction;
puts "#{year} --> #{result.ordinalize}" }}


defmodule Year do
@doc """
Returns the stringified, suffixed form of a numeric year.

Use to_century/1 if you need to do further numeric work on the
century number before (or in lieu of) using it as a string.

## Examples

iex> Year.centurify(8120)
"82nd"
iex> Year.centurify(30200)
"303rd"
iex> Year.centurify(1601)
"17th"
iex> Year.centurify(2020)
"21st"
iex> Year.centurify(3030)
"31st"
iex> Year.centurify(1900)
"20th"
iex> Year.centurify(1776)
"18th"
"""
def centurify(year) do
century = to_century(year)
"#{century}#{suffix(century)}"
end

def to_century(year), do: div(year, 100) + 1

defp suffix(number) when number >= 100,
do: number |> rem(100) |> suffix
defp suffix(number) when number in 11..13, do: "th"
defp suffix(number) do
case rem(number, 10) do
1 -> "st"
2 -> "nd"
3 -> "rd"
_ -> "th"
end
end
end

defmodule YearTest do
import ExUnit.Case
doctest Year
end


This might be a bit over-engineered, but here is another Ruby solution:

def to_century(year)
(year.to_i / 100 + 1).english.ordinal
end

class Integer
def english
English::Integer.new(self)
end
end

module English
class Integer
def initialize(integer)
@value = integer.to_i
end

##
# Returns ordinal notation of the current integer ("-2nd", "1st", "312th").
def ordinal
"#{@value}#{ordinal_suffix}"
end

##
# Returns the ordinal suffix of the current integer ("st", "nd", "rd", "th").
def ordinal_suffix
case @value.abs % 100
when 1, 21, 31, 41, 51, 61, 71, 81, 91 then 'st'
when 2, 22, 32, 42, 52, 62, 72, 82, 92 then 'nd'
when 3, 23, 33, 43, 53, 63, 73, 83, 93 then 'rd'
else 'th'
end
end
end
end


Which produces the following output:

years = %w[8120 30200 1601 2020 3030 1900 1776]
years.to_h { |year| [year, to_century(year)] }
#=> {"8120"=>"82nd", "30200"=>"303rd", "1601"=>"17th", "2020"=>"21st", "3030"=>"31st", "1900"=>"20th", "1776"=>"18th"}


function thuffix(n)
{
let ending = 'th';
if(n%100 != 11 && n%100 != 12 && n%100 != 13)
{
if(n%10 == 1)
{
ending = 'st';
}
else if(n%10 == 2)
{
ending = 'nd';
}
else if(n%10 == 3)
{
ending = 'rd';
}
}
return ending;
}

function getCentury(year)
{
let c = Math.floor(year/100);
if(year%100 != 0)
{
c++;
}
return ${c}${thuffix(c)};
}  