Antonio Bonifati's Home Page

Farmer, Italian language teacher, Lisp functional programmer, sysadmin and free-software fellow

/*
Prolog rules to tell the time in English, with intended profile what_time(+,-).

Input: 24 hour format (0 through 23), with or without leading zeros
Output: 12 hour format (1 through 12) with a.m. and p.m. suffixes

Reference:
http://en.wikipedia.org/wiki/12-hour_clock

Copyright 2010 Antonio Bonifati 
This software comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to modify and redistribute it under the GPL license
*/

:- include('in_words.pl').

what_time(H,T) :- what_time(H,0,T).

% one can escape ' as \' or ''
what_time(H,0,T) :- hours_in_word(H,W),
  (divisible(H,12) -> T = W ; am_pm(H,A), concat_atom([W,' o\'clock',A],T)), !.

what_time(H,M,T) :- M =< 30, time_atom(H,M,' past',T), !.

what_time(H,M,T) :- /* M > 30, */ N is 60 - M, I is H + 1,
  time_atom(I,N,' to',T).

time_atom(H,M,P,T) :- minutes_in_word(M,MW), hours_in_word(H,HW),
  (divisible(H,12) -> A = '' ; am_pm(H,A)), concat_atom([MW,P,' ',HW,A],T).

/*
this is the same as two nested ternary implication
operators, just a bit more readable.
*/
minutes_in_word(30,half) :- !.
minutes_in_word(15,'a quarter') :- !.
minutes_in_word(M,W) :- in_words(M,MW),
  (divisible(M,5) -> S = '' ; M == 1 -> S = ' minute' ; S = ' minutes'),
  atom_concat(MW,S,W).

hours_in_word(0,midnight) :- !.
hours_in_word(12,noon) :- !.  % or midday
/*
Here we actually mean midnight at the end of the day, that is the next day is starting.
But, as in the informal spoken language, we omit to make this distinction
*/
hours_in_word(24,midnight) :- !.
hours_in_word(H,W) :- I is H mod 12, in_words(I,W).

am_pm(H,A) :- H < 12 -> A = ' am' ; A = ' pm'.

divisible(A,B) :- R is A mod B, R == 0.