Excel, 212 bytes
=ABS(RIGHT(A1,2))&IF(ABS(ABS(RIGHT(A1,2))-12)<2,"th",SWITCH(RIGHT(A1,1),"1","st","2","nd","3","rd","th"))&TEXT(MID(A1,FIND("-",A1)+1,FIND("-",REPLACE(A1,1,FIND("-",A1),""))-1)*30," mmmm ")&LEFT(A1,FIND("-",A1)-1)
If you break it into chunks at every ampersand, you get these pieces:
ABS()
pulls the day number from the last two characters in the string. Since that may include a hyphen, ABS
converts it to positive.
IF((ABS-12)<2,"th",SWITCH())
adds the ordinal. The -12
bit is because 11, 12, and 13 don't follow the normal rule and they all get th
instead of st
, nd
, and rd
. This corrects for that.
- Note: The
SWITCH
function is only available in Excel 2016 and later. (Source) It's shorter than CHOOSE
in this case because it can return a value if no match is found whereas CHOOSE
requires numeric input and must have a corresponding return for each possible value.
TEXT(MID()*30," mmmm ")
extracts the month name. MID()
pulls out the month number as a string and multiplying by 30 returns a number. Excel sees that number as a date (1900-01-30, 1900-02-29, 1900-03-30, etc.) and TEXT()
formats it as a month name with a space on both ends. 28 and 29 would have also works but 30 looks "nicer".
LEFT()
extracts the year number.
Now, given all that, it would have been way easier if the test cases were all in a date range that Excel can handle as an actual date: 1900-01-01 to 9999-12-31. The big advantage is that the entire date is formatted at once. That solution is 133 bytes:
=TEXT(DATEVALUE(A1),"d""" & IF(ABS(ABS(RIGHT(A1,2))-12)<2,"th",SWITCH(RIGHT(A1,1),"1","st","2","nd","3","rd","th")) & """ mmmm yyyy")
The other big hurdle was having to include the ordinal. Without that, the solution is just 34 bytes:
=TEXT(DATEVALUE(A1),"d mmmm yyyy")
03rd
পরিবর্তে ওরফে3rd