Convert the Time to a String

17

1

Problem

One day, you boss walks up to you and tells you he needs to know the time. He still insists after you pointing at the clock directly above you head, and confesses he has a severe case of dyscalculia, which causes him to not even be able to see numbers on a clock. While you're still left wondering how someone unable to see numbers can run a company, he tells you to "do something about it", whatever that is.

Your task is now to create a program or function that, given an input time with hours and minutes (seconds are optional)(hours are 24-based), outputs a readable english sentence, that doesn't contain numbers.

It is not necessary to ouput the seconds.

For example, 08:45:15 should output quarter to nine o'clock AM

Test cases

00:00:00 > twelve night
12:00:00 > twelve noon
06:00:00 > six o'clock AM
18:00:00 > six o'clock PM
06:15:00 > quarter past six o'clock AM
18:45:00 > quarter to seven o'clock PM
11:30:00 > half past eleven o'clock AM
13:22:00 > twentytwo minutes past one o'clock PM
17:43:00 > seventeen minutes to six o'clock PM
00:09:00 > nine minutes past twelve o'clock AM

Rules

Outputting numbers can be both in the form of fortytwo or forty-two, whichever you like best. Standard loopholes are not allowed. Trailing newlines are allowed, but the sentence should be on 1 line.

Input can be in any format you want, for example HH:MM:SS, HH,MM,SS, HHMMSS, HH/MM/SS, or any variant without seconds, but you should make the input format clear in your answer. It's not needed to output one minute instead of one minutes

for minutes ranging from 0 trough 30 (0 and 30 included) you should use past, and for the others you should use to

Because time is relative, shortest code in bytes wins.

Dennis van Gils

Posted 2016-02-05T14:27:26.590

Reputation: 291

1

This looks like a nice challenge, bit I strongly suggest removing the bonuses. Unless you know exactly what you are doing, those are one thing to avoid when writing challenges.

– Denker – 2016-02-05T14:35:31.100

1Two more (minor) points: why does it matter how you write forty-five when the test cases clearly state quarter to as the appropriate input format? (just change it to forty-two ;) ) Also, [tag:kolmogorov-complexity] is not an appropriate tag. – Sanchises – 2016-02-05T14:36:58.653

@sanchises edited. I misunderstood the kolmogorov tag, and thought it had to do with problems in outputting any string, instead of a given string only. – Dennis van Gils – 2016-02-05T14:41:32.963

1@TimmyD The -70% one was a joke, I didn't imagine anyone would try to translate french in code-golf. However, I feel that having negative size is a decent reward for a perfect french-english translator – Dennis van Gils – 2016-02-05T14:43:27.680

That looks much better, but a few more formatting clarifications are needed. Specifically regarding choosing between "past" and "to" -- from the examples, it sounds like you're wanting to only utilize the numbers one to twenty-nine, with quarter replacing fifteen and half representing thirty, but that's not clear. Also, for future questions, I heartily recommend the Sandbox to work out the kinks before posting.

– AdmBorkBork – 2016-02-05T14:43:41.113

@TimmyD edited again. I'd also like to apologize, I didn't know about the sandbox. – Dennis van Gils – 2016-02-05T14:51:20.107

No worries! Again, welcome to PPCG! :) – AdmBorkBork – 2016-02-05T14:54:04.523

All of the inputs lie exactly on 5 minute boundaries. Does this imply all inputs will be like this, or that inputs should all be rounded to the nearest 5 minutes, or should single minutes be handled? – Digital Trauma – 2016-02-05T17:21:50.190

@DigitalTrauma updated the question, single minutes should be handled, and twelve midnight is indeed more consistent, considering that 1 o'clock AM also has no at – Dennis van Gils – 2016-02-05T17:36:56.413

twelve midnight or twelve night? – Digital Trauma – 2016-02-05T17:40:28.587

Just to be sure: twentytwo and not twenty-two or twenty two? – Digital Trauma – 2016-02-05T17:41:29.937

@DigitalTrauma I specified both twentytwo and twenty-two are permitted – Dennis van Gils – 2016-02-05T18:48:30.613

Answers

2

Javascript, 384 381 bytes

(h,m)=>(o='one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir,,fif,,,eigh,'.split`,`,o=o.map((x,i)=>i>11?(x||o[i-10])+'teen':x),(a=m>30,t=12,m?(m-30?m%15?((m=a?59-m:m)>=(b=a?19:20)?'twenty'+((m%=b)?o[a?m:m-1]:''):o[a?m:m-1])+' minutes':'quarter':'half')+(a?' to ':' past '):'')+(h%t|m?o[(a?h:(h?h-1:11))%t]+` o'clock ${h>t?'P':'A'}M`:o[11]+(h-t?' night':' noon')))

f=
(h,m)=>(
    o='one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thir,,fif,,,eigh,'.split`,`,
    o=o.map((x,i)=>i>11?(x||o[i-10])+'teen':x),
    (a=m>30,t=12,
    m?
        (m-30?
            m%15?
                ((m=a?59-m:m)>=(b=a?19:20)?
                    'twenty'+((m%=b)?o[a?m:m-1]:'')
                :o[a?m:m-1])+' minutes'
            :'quarter'
        :'half')+(a?' to ':' past ')
    :'')
    +(h%t|m?
        o[(a?h:(h?h-1:11))%t]+` o'clock ${h>t?'P':'A'}M`
    :o[11]+(h-t?' night':' noon'))
)

document.body.innerHTML = '<pre>' +
'f(00,00) = ' + f(00,00) + '\n' +
'f(12,00) = ' + f(12,00) + '\n' +
'f(06,00) = ' + f(06,00) + '\n' +
'f(18,00) = ' + f(18,00) + '\n' +
'f(06,15) = ' + f(06,15) + '\n' +
'f(18,45) = ' + f(18,45) + '\n' +
'f(11,30) = ' + f(11,30) + '\n' +
'f(13,22) = ' + f(13,22) + '\n' +
'f(17,43) = ' + f(17,43) + '\n' +
'f(00,09) = ' + f(00,09) + '\n' +
'f(23,59) = ' + f(23,59) + '\n' +
'</pre>'

removed

Posted 2016-02-05T14:27:26.590

Reputation: 2 785

1Works fine, and even has the Perl one beat by 4 bytes! Nice trick with fif, eigh etc btw. – Dennis van Gils – 2016-02-08T16:25:00.700

4

LaTeX, 466 bytes

\usepackage{fmtcount,etoolbox}\def\x{\the\numexpr}\def\n[#1]{\numberstringnum{#1}}\def\h[#1]{\ifnumequal{#1}{0}{twelve night}{\ifnumequal{#1}{12}{twelve noon}{\ifnumless{#1}{13}{\n[#1] o'clock AM}{\n[\x#1-12\relax] o'clock PM}}}}\def\m[#1]{\ifnumequal{#1}{15}{quarter}{\ifnumequal{#1}{30}{half}{\n[#1] minutes}}}\newcounter{c}\def\f[#1]#2{\ifnumequal{#2}{0}{\h[#1]}{\ifnumless{#2}{31}{\m[#2] past \h[#1]}{\setcounter{c}{\x60-#2\relax}\m[\thec] to \h[\x#1+1\relax]}}}

Just call the macro \f as \f[hour]{minutes}, here some tests:

\begin{document}

\noindent
\textbf{Test cases:} \\ \\
00:00 = \f[00]{00} \\
12:00 = \f[12]{00} \\
06:00 = \f[6]{00} \\
18:00 = \f[18]{00} \\
06:15 = \f[6]{15} \\
18:45 = \f[18]{45} \\
11:30 = \f[11]{30} \\
13:22 = \f[13]{22} \\
17:43 = \f[17]{43} \\

\noindent
\textbf{More test cases:} \\ \\
00:13 = \f[00]{13} \\
12:12 = \f[12]{12} \\
12:15 = \f[12]{15} \\
11:45 = \f[11]{45} \\
11:41 = \f[11]{41} \\

\end{document}

Bob

Posted 2016-02-05T14:27:26.590

Reputation: 957

Do you know how and where I can try this? I tried arachnoid and papeeria but they didn't work.

– Dennis van Gils – 2016-02-05T20:56:07.597

@DennisvanGils I tried this http://pastebin.com/kdpSQHSb in papeeria and it worked.

– Bob – 2016-02-05T22:35:00.360

Tried it with the pastebin code and that worked, guessing it didn't work because I didn't have \documentclass[a4paper,12pt]{article} – Dennis van Gils – 2016-02-05T22:46:13.803

3

Python 2, 498 bytes

Input comes as function argument. First hour and then minute, both as integer. Result gets printed to the screen.

def g(h,m):
 a=lambda x:"twelve one two three four five six seven eigth nine ten eleven".split()[x%12];b=lambda x:a(x)+" o'clock "+["AM","PM"][x>=12]
 if m:
    z=m if m<30else 60-m;print(a(z)if z<13else("twenty"+(a(z-20)if z-20else"")if z>19else"thirteen fourteen fifteen sixteen seventeen eighteen nineteen".split()[z-13])if m%15else"quarter"if m-30else"half")+(" minutes"if m-30and m%15else"")+[" past "+b(h)," to "+b(h+1)][m>30]
 else:print"twelve "+("noon"if h else "night")if h in[0,12]else b(h)

Try it online! (with slightly extended testcases)

That was a pretty fun golf. Although all those nested ternaries drove me a little bit crazy ^^
I was planning on doing this in Pyth after this, but I don't think that I am mentally able to do this at the moment (or ever).

Ungolfed:

def ungolfed(h,m):
    toStr=lambda x:"twelve one two three four five six seven eigth nine ten eleven".split()[x%12]
    hour=lambda x:toStr(x)+" o'clock "+["AM","PM"][x>=12]
    minute=lambda x:"twenty"+(toStr(x-20)if x-20else"")if x>19else"thirteen fourteen fifteen sixteen seventeen eighteen nineteen".split()[x-13]

    if m:
        s=""
        if m==30:
            s+="half"
        else:
            if m%15==0:
                s+="quarter"
            else:
                z=m if m<30 else 60-m
                if z<13:
                    s+=toStr(z)
                else:
                    s+=minute(z)
        print s+(" minutes"if m-30and m%15else "")+[" past "+hour(h)," to "+hour(h+1)][m>30]
    else:
        if h in[0,12]:
            print"twelve "+("noon"if h else "night")
        else:
            print hour(h)

Denker

Posted 2016-02-05T14:27:26.590

Reputation: 6 639

Your [x>12] should be [x>=12], 12:01 is PM, not AM

– Dennis van Gils – 2016-02-05T21:05:17.720

1@DennisvanGils Good catch, thank you! Fixed it. :) We Germans aren't that comfortable with this whole AM/PM-thing I guess :P – Denker – 2016-02-05T21:12:28.857

I'm dutch, so I had to look it up myself to be sure too. – Dennis van Gils – 2016-02-05T21:14:02.360

1

Perl 5, 367 361 385 Bytes

Garbled

use integer;$_=<>;~/(\d+):(\d+)/;@b=(one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve); @x=(@b,thirteen,(map{/fi/?quarter:$_.teen}@b[3..8]),(map{twenty.$_}'',@b[0..8]),half);@y=map{/^q|h/?$_:$_.' minutes'}@x;$s=1-$2/31;$y=abs((-29,0)[$s]+$2%31)-1;$h=$1-$s;print((+-$2?@y[$y].' '.(to,past)[$s].' ':'').@b[$h++%12]." o' clock ".($h%12?(AM,PM)[$h/12]:(night,noon)[$h/12%2]))

Formatted and test cases:

use integer;
map{
    # capture (implicit $_)
    ~/(\d+):(\d+)/;
    # bare words
    @b=(one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve);
    # construct up to 30
    @x=(@b,thirteen,
       (map{/fi/?quarter:$_.teen}@b[3..8]),
       (map{twenty.$_}'',@b[0..8]),half);
    # quarter/half business
    @y=map{/^q|h/?$_:$_.' minutes'}@x;
    # whether we are to/past
    $s=1-$2/31;
    # num minutes wrapped around
    $y=abs((-29,0)[$s]+$2%31)-1;
    # num hours
    $h=$1-$s;
    #print('$s='.$s."\th=".$h."\th%12=".($h%12)."\n");
    print($_.' > ');
    #minute component
    print((+-$2
          ?@y[$y].' '.(to,past)[$s].' '
          :'')
        # hours
        .@b[$h++%12]
        ." o' clock "
        # Night/Noon
        .($h%12
          ?(AM,PM)[$h/12]
          :(night,noon)[$h/12%2]));
    print "\n"
}
('00:00:00',
 '00:01:00',
 '11:59:00',
 '12:00:00',
 '12:01:00',
 '06:00:00', 
 '18:00:00', 
 '06:15:00', 
 '18:45:00', 
 '11:30:00', 
 '13:22:00', 
 '17:43:00',
 '23:59:59')

walpen

Posted 2016-02-05T14:27:26.590

Reputation: 3 237

This seems to give one minutes to one o' clock night as output for 00:01, instead of one minutes past twelve o'clock AM or one minutes past twelve night – Dennis van Gils – 2016-02-05T23:51:31.420

You're right. I've added test cases around the 12 times. – walpen – 2016-02-06T00:32:15.500

1

C, 478 bytes

*w(i){char*p,*n[]={"","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"};return i>19?asprintf(&p,"twenty%s",n[i%20]),p:n[i];}main(m,h){scanf("%d%d",&h,&m);m>30?h++:0;printf("%s%s%s%s%s %s\n",m%15?m>30?w(60-m):w(m):m^30?m?"quarter":"":"half",m%15?" minutes":"",m?m>30?" to ":" past ":"",w((h+11)%12+1),h%12||m?" o'clock":"",h%12||m?h>11?"PM":"AM":h?"noon":"night");}

Test Cases

$ echo "0 0" | ./a.out
twelve night
$ echo "12 0" | ./a.out
twelve noon
$ echo "6 0" | ./a.out
six o'clock AM
$ echo "18 0" | ./a.out
six o'clock PM
$ echo "6 15" | ./a.out
quarter past six o'clock AM
$ echo "18 45" | ./a.out
quarter to seven o'clock PM
$ echo "11 30" | ./a.out
half past eleven o'clock AM
$ echo "13 22" | ./a.out
twentytwo minutes past one o'clock PM
$ echo "17 43" | ./a.out
seventeen minutes to six o'clock PM
$ echo "0 9" | ./a.out
nine minutes past twelve o'clock AM

Try it here.

Cole Cameron

Posted 2016-02-05T14:27:26.590

Reputation: 1 013

Looks fine. Also interesting how 00 00 gives the correct output, while 00:00 gives one minutes past twelve o'clock AM, although I'm sure that has something to do with how you parse input. – Dennis van Gils – 2016-02-08T16:22:24.663

Yes, it expects two integers (hours and minutes). scanf probably doesn't parse '00:00' as one might hope :) – Cole Cameron – 2016-02-08T16:53:15.307

0

Batch, 779 774 752 749 bytes

@echo off
set t=%1
set/ah=%t:~0,2%,m=%t:~3,2%
set p=past
if %m% gtr 30 set p=to&set/am=60-m,h+=1
for %%a in ("one minute.1" quarter.15 half.30)do if %%~xa==.%m% set o=%%~na&goto g
set o=
if %m% gtr 20 set o=twenty-&set/am-=20
for %%a in (one.1 two.2 three.3 four.4 five.5 six.6 seven.7 eight.8 nine.9 ten.10 eleven.11 twelve.12 thirten.13 fourteen.14 sixteen.16 seventeen.17 eighteen.18 nineteen.19 twenty.20)do if %%~xa==.%m% set o=%o%%%~na minutes
:g
if not %m%==0 set o=%o% %p% 
set a= AM
if %h% gtr 12 set a= PM&set/ah%%=12
if %h%==0 (echo %o%twelve night)else if %h%==12 (echo %o%twelve noon)else for %%a in (one.1 two.2 three.3 four.4 five.5 six.6 seven.7 eight.8 nine.9 ten.10 eleven.11)do if %%~xa==.%h% echo %o%%%~na o'clock%a%

Change the second line to set t=%1%time% to default to saying the current time if no time is provided.

Edit: Saved 22 bytes by optimising my set/a statements. Saved 3 bytes thanks to @EʀɪᴋᴛʜᴇGᴏʟғᴇʀ.

When I wrote my original version I made the mistake of saying the time as I would actually say it, i.e. o'clock only on exact hours, and midnight and midday instead of twelve night and twelve noon:

@echo off
set t=%1
set/a h=%t:~0,2%
set/a m=%t:~3,2%
set p=past
if %m% gtr 30 set p=to&set/a m=60-m&set/a h=h+1
for %%a in ("one minute.1" quarter.15 half.30) do if %%~xa==.%m% set o=%%~na&goto g
set o=
if %m% gtr 20 set o=twenty-&set/a m=%m%-20
for %%a in (one.1 two.2 three.3 four.4 five.5 six.6 seven.7 eight.8 nine.9 ten.10 eleven.11 twelve.12 thirten.13 fourteen.14 sixteen.16 seventeen.17 eighteen.18 nineteen.19 twenty.20) do if %%~xa==.%m% set o=%o%%%~na minutes
:g
set o=%o% %p% 
set a= AM
if %h% gtr 12 set a= PM&set/a h=h%%12
if %m%==0 set a= o'clock%a%&set o=
if %h%==0 (echo %o%midnight)else if %h%==12 (echo %o%midday)else for %%a in (one.1 two.2 three.3 four.4 five.5 six.6 seven.7 eight.8 nine.9 ten.10 eleven.11) do if %%~xa==.%h% echo %o%%%~na%a%

Neil

Posted 2016-02-05T14:27:26.590

Reputation: 95 035

Your 12:00 and 00:00 tests don't work, they only echo midnight and midday instead of twelve night and twelve noon. I really like how you use fake extensions and names in your for loop btw. – Dennis van Gils – 2016-02-05T20:54:07.197

2@DennisvanGils There are probably other tests it fails; I'll fix it up later. – Neil – 2016-02-05T21:04:49.057

@DennisvanGils I think it's working now, and conveniently it's also shorter! – Neil – 2016-02-06T18:52:03.217