Telling time in French

21

Bonjour, PPCG ! Quelle heure est-il ? This means what time is it in French, for that is exactly what this challenge is about.

Telling time in French (at least formally) is a bit different from telling time in English. Telling the time starts out with Il est (It is). Then, you put the hour followed by heures (o'clock). (In case you don't know French numbers, here's a list: http://blogs.transparent.com/french/french-numbers-learn-how-to-count-from-1-to-1000/). If it is 1 o'clock, do une heure for this. For noon, use midi (with no heures), and for midnight use minuit.

Unless the minutes is 00, you then follow it with the number of minutes. There are a few exceptions to this however. For 15 minutes, you want to say et quart, and for 30 minutes you want to say et demi. For anything after 30 minutes, you increase the hour number by one, then add the word moins and 60 - the minutes. So 6:40 P.M is Il est sept heures moins vingt (vingt = 20). 45 minutes would be moins le quart.

Finally, you end it with the time of day. For the morning (1 A.M to 12 P.M), you say du matin. For the afternoon (subjective, but I'll define it as 1 P.M to 5 P.M), you say de l'apres-midi (technically there should be an accent above the e, but eh). And for night (5 P.M to 12 A.M) you say du soir. Note that for midnight and noon (minuit and midi) you don't put any of these afterwards -- the time of day is implied based on which one you use.

As you've probably already ascertained, the challenge here is to print out the current local time in French using these rules. Here's what sample output should look like at assorted times. (The time in the parenthesis does not have to be printed obviously, it's just there so you know what times are):

Il est sept heures du matin. (7:00 A.M)
Il est deux heures de l'apres-midi. (2:00 P.M)
Il est une heure du matin. (1:00 A.M)
Il est huit heures du soir. (8:00 P.M)
Il est midi. (12:00 P.M, Noon)
Il est minuit. (12:00 A.M, Midnight)
Il est cinq heures vingt du soir. (5:20 P.M)
Il est six heures et quart du matin. (6:15 A.M)
Il est neuf heures et demi du matin. (9:30 A.M)
Il est quatre heures moins dix de l'apres-midi. (3:50 P.M, not 4:50!)
Il est midi moins le quart. (11:45 A.M)

This is code-golf, so shortest code wins. Good luck!

EDIT: The period is required.

a spaghetto

Posted 2015-09-25T20:25:50.493

Reputation: 10 647

2

Related: Spell out numbers in French

– NinjaBearMonkey – 2015-09-26T13:52:31.530

What should be the output for 08:41 AM, for instance? Il est huit heures quarante et une du matin (correct) or Il est neuf heures moins dix-neuf du matin (sounds strange)? – Blackhole – 2015-09-26T14:07:59.487

Should we necessarily output the result, or can we just return it? Are internal functions that convert numbers to numerals allowed? – Blackhole – 2015-09-26T14:11:07.253

Should we put an accent in après-midi? Can we? – Blackhole – 2015-09-26T14:22:16.053

If you want. It's not necessary. – a spaghetto – 2015-09-26T19:07:50.993

As far as the 8:41, use Il est neuf heures moins dix-neuf du matin. I think the main part of the challenge comes from the moins which is why I'd like it to be like that. (Plus that's the way I was taught how to tell time in French, and this whole challenge is something of a nostalgia trip for me.) – a spaghetto – 2015-09-26T19:11:31.333

Thanks for clarification :). I personally use "moins" only with round number ("midi moins cinq", "moins dix", "moins le quart", "moins vingt", "moins vingt-cinq"), but usage probably differs between regions, so it's okay ;). – Blackhole – 2015-09-26T20:36:33.607

What should the output be for 16:45? Il est cinq heures moins le quart du soir. or Il est cinq heures moins le quart de l'apres-midi. ? – Tob Ernack – 2015-09-28T04:29:42.603

de l'apres-midi I believe. – a spaghetto – 2015-09-28T13:05:37.020

Fun fact: There is a swiss german "Gelerettli" word for "pocket-watch" coming from rewriting "quelle heure est-il" as it is pronounced. (With li instead of il as a diminuitive.) – flawr – 2016-01-13T13:00:20.850

Answers

4

PHP - 521 473 bytes

I've added some newlines for readability:

$w=split(A,'AuneAdeuxAtroisAquatreAcinqAsixAseptAhuitAneufAdixAonzeAdouzeAtreizeA
quatorzeAAseizeAdix-septAdix-huitAdix-neufAvingtAvingt et une');$h=idate('H');if(
$r=($m=idate('i'))>30){$h=++$h%24;$m=60-$m;}echo'Il est '.($h?$h==12?midi:$w[$h%12]
.' heure'.($h%12<2?'':s):minuit).($r?' moins':'').($m==15?($r?' le ':' et ').quart
:($m==30?' et demi':($m?' '.($m<22?$w[$m]:"$w[20]-".$w[$m%10]):''))).($h%12?($h-=$r
)<12?' du matin':($h<17?" de l'après-midi":' du soir'):'').'.';

The method used to converting a number to its numeral in French is inspired by this answer on an other challenge by edc65.

Here is the ungolfed version:

/** Define numerals **/
$numerals = [
    '', 'une', 'deux', 'trois', 'quatre',
    'cinq', 'six', 'sept', 'huit', 'neuf',
    'dix', 'onze', 'douze', 'treize', 'quatorze',
    '', 'seize', 'dix-sept', 'dix-huit', 'dix-neuf',
    'vingt', 'vingt et une'
];

/** Get current time **/
$hours = idate('H');
$minutes = idate('i');

/** Check if we need to count in reverse **/
$reverse = $minutes > 30;
if ($reverse) {
    $hours = ($hours + 1) % 24;
    $minutes = 60 - $minutes;
}

echo 'Il est ';

/** Print hours **/
if ($hours === 12) {
    echo 'midi';
}
else if ($hours === 0) {
    echo 'minuit';
}
else
{
    echo $numerals[$hours % 12] .' heure';
    if ($hours % 12 !== 1) {
        echo 's';
    }
}

/** Print minutes **/
if ($reverse) {
    echo ' moins';
}

if ($minutes === 15)
{
    if ($reverse) {
        echo ' le ';
    }
    else {
        echo ' et ';
    }

    echo 'quart';
}
else if ($minutes === 30) {
    echo ' et demi';
}
else if ($minutes !== 0)
{
    echo ' ';

    if ($minutes < 22) {
        echo $numerals[$minutes];
    }
    else {
        echo $numerals[20] .'-'. $numerals[$minutes % 10];
    }
}

/** Print daytime **/
if ($hours % 12 !== 0)
{
    if ($reverse) {
        --$hours;
    }

    if ($hours < 12) {
        echo ' du matin';
    }
    else if ($hours < 17) {
        echo " de l'après-midi";
    }
    else {
        echo ' du soir';
    }
}

echo '.';

Blackhole

Posted 2015-09-25T20:25:50.493

Reputation: 2 362

4

Python 3, 586 547 556 506 505 502 498 497 493 Bytes

My first attempt at golfing anything. I’m really not sure about the way I choose, especially the n list. But I wanted to give it a try.

from datetime import*;t=datetime.now()
n='/une/deux/trois/quatre/cinq/six/sept/huit/neuf/dix/onze/douze/treize/quatorze/et quart/seize/dix-sept/dix-huit/dix-neuf/vingt//et demi'.split('/')
n[21:22]=['vingt-'+i for i in['et-une']+n[2:10]]
h,m=t.hour,t.minute;s=h//12;h%=12
e=' d'+('u matin',("e l'après-midi","u soir")[h>4])[s]
try:m=' '[:m]+n[m]
except:m=' moins '+(n[60-m],'le quart')[m==45];h+=1
e,h=('',e,('minuit','midi')[h//12^s],n[h]+' heures'[:h+5])[h%12>0::2]
print('Il est',h+m+e+'.')

Ungolfed:

from datetime import datetime

time = datetime.now()
numbers = [
    '', 'une', 'deux', 'trois', 'quatre',
    'cinq', 'six', 'sept', 'huit', 'neuf',
    'dix', 'onze', 'douze', 'treize', 'quatorze',
    'et quart', 'seize', 'dix-sept', 'dix-huit', 'dix-neuf',
    'vingt', 'vingt-et-une', 'vingt-deux', 'vingt-trois', 'vingt-quatre',
    'vingt-cinq', 'vingt-six', 'vingt-sept', 'vingt-huit', 'vingt-neuf',
    'et demi']

status, hour = divmod(time.hour, 12)
if status:
    ending = " du soir" if h>4 else " de l’après-midi"
else:
    ending = " du matin"

try:
    if not time.minute:
        minutes = ""
    else:
        minutes = " " + numbers[time.minute]
except IndexError:
    hour += 1
    if time.minute == 45:
        minutes = " moins le quart"
    else:
        minutes = " moins " + numbers[60 - time.minute]

if hour%12:    # 'whole' hours
    hours = numbers[hour] + " heures"
    if hour == 1:
        # removing extra 's'
        hours = hours[:-1]
else:          # midnight or noon
    ending = ""
    if (hour == 12 and status) or (hour == 0 and status == 0):
        hours = "minuit"
    else:
        hours = "midi"

print('Il est', hours + minutes + ending + '.')

301_Moved_Permanently

Posted 2015-09-25T20:25:50.493

Reputation: 401

2You can save some 50 bytes with 'minuit#une#deux#...#vingt-neuf#et demi'.split('#'). Might be even shorter to just compress the string somehow. – Martin Ender – 2015-09-26T23:56:05.927

@Martin yeah, just saw it on Blackhole's answer too. But I wanted to try to shorten it using the repetitions involved with "vingt-xxx". But after some sleep since Il est deux heures moins trois du matin. – 301_Moved_Permanently – 2015-09-27T00:00:32.330

@MathiasEttinger a couple corrections, you have 'voingt' instead of vingt, and 21 is 'vingt et un', not 'vingt-et-une' – Brian Tuck – 2015-09-27T04:59:43.503

1Thanks for vingt. For 21 it should be vingt-et-une since minute is feminine, the same way that 1:01 AM is il est une heure une du matin. – 301_Moved_Permanently – 2015-09-27T08:48:46.323

@BrianTuck Also 21 is vingt-et-un or vingt-et-une since 1990 instead of vingt et un or vingt et une: https://fr.wiktionary.org/wiki/vingt_et_une

– 301_Moved_Permanently – 2015-09-27T09:08:05.323

@Blackhole Thanks for that, should be fixed now – 301_Moved_Permanently – 2015-09-27T12:05:10.807

3

Javascript (ES6), 506 495 bytes

Edit: Compressed a to save a few bytes.

a=`
un
j
k
yre
h
six
w
v
p}
onldoultreilyorl
seize}-w}-v}-p~~ et un{j{k{yre{h{six{w{v{p
et demi`,[...`hjklpvwy{}~`].map((x,w)=>a=a.split(x).join(`cinq|deux|trois|ze
|neuf|huit|sept|quat|~-|
dix|
vingt`.split`|`[w])),a=a.split`
`,alert(`Il est ${(e=(d=((b=(z=new Date).getHours())+(y=(c=z.getMinutes())>30))%24)%12)?a[e]+` heure${e-1?"s":""}`:d?'midi':'minuit'} ${y?"moins ":""}${y?c-45?a[60-c]:'le quart':c-15?a[c]:'et quart'}${e?[' du matin'," de l'apres-midi",' du soir'][(b>12)+(b>16)]:""}.`)

Explanation:

a = 'compressed string of french numbers with 'et demi' for 30 and 15 removed';
a = // code that decompresses a

// a,b,c,d,e,y,z are all inlined into the first expression that uses them
z = new Date();
b = z.getHours();
c = z.getMinutes();
y = c > 30; // true if 60 - minutes, false otherwise
d = (b + y) % 24; // the next hour if y
e = d % 12; // is it not noon and not midnight?

alert(
    "Il est " +
    // add the hour
    // if d is not 0 or 12, add d + 'heure(s)'
    (e ? a[e] + ` heure${e-1?"s":""}` : d ? 'midi' : 'minuit') +
    " " +
    (y ? "moins " : "") + // add 'moins' if necessary

    ( // add the minute
      y? // necessary to subtract from 60?
        c-45?
          a[60-c] // add normal number word
          :'le quart' // handle special case for 45
        :c-15?
          a[c] // add normal word
          :'et quart' // handle special case for 15
    ) +
    ( // select appropriate ending
      e? // is it not noon and not midnight?
        // create array of endings
        [" du matin"," de l'apres-midi"," du soir"]
          // selects item 0 if b in [0, 12], item 1 if b in [13, 16] and item 2 if b > 16
          [(b > 12) + (b > 16)]
        :"" // if it's noon or midnight, no ending is necessary
    ) +
    "." // add period
)

DankMemes

Posted 2015-09-25T20:25:50.493

Reputation: 2 769

2

C, 860 835 794 bytes

Absolutely horrendous, but can probably be made even shorter. Many newlines were added for formatting purposes on this site. The actual source code has newlines after the #includes and #defines, but everything starting from char* to the last w(".\n");} are all in one line. I shortened it by removing the values from 22,...,29 in the string array, instead reusing the strings for 2,...,9 and prepending a "vingt-" when appropriate. (I really hope I didn't introduce a bug!)

#include <sys/time.h>
#define w printf
#define q tm_min
#define r tm_hour
char*a[]={"minuit","une","deux","trois","quatre","cinq","six","sept","huit","neuf","dix",
"onze","douze","treize","quatorze","quart","seize","dix-sept","dix-huit","dix-
neuf","vingt","vingt-et-une",0,0,0,0,0,0,0,0,"demi"};
h=1,s=1,m,e,l,t,p,o,v;struct tm j;
main(){struct timeval i;gettimeofday(&i,0);localtime_r(&i.tv_sec,&j);
j.q>30?m=1,++j.r,j.q=60-j.q:j.q==15||j.q==30?e=1:0;j.q>21&&j.q<30?v=1:0;
j.r%12?j.r<12?t=1:j.r-m<17?p=1:(o=1):0;
j.q==15&&m?l=1:0;j.r%12?j.r%12==1?s=0:0:(h=0,s=0);
w("Il est ");j.r==12?w("midi"):w("%s",a[j.r%12]);h?w(" heure"):0;s?w("s"):0;
m?w(" moins"):0;e?w(" et"):0;l?w(" le"):0;
j.q?v?w(" vingt-"):w(" "),w("%s",a[j.q-20*v]):0;
t?w(" du matin"):p?w(" de l'apres-midi"):o?w(" du soir"):0;w(".\n");}

Like this:

#include <sys/time.h>
#define w printf
#define q tm_min
#define r tm_hour
char*a[]={"minuit","une","deux","trois","quatre","cinq","six","sept","huit","neuf","dix","onze","douze","treize","quatorze","quart","seize","dix-sept","dix-huit","dix-neuf","vingt","vingt-et-une",0,0,0,0,0,0,0,0,"demi"};h=1,s=1,m,e,l,t,p,o,v;struct tm j;main(){struct timeval i;gettimeofday(&i,0);localtime_r(&i.tv_sec,&j);j.q>30?m=1,++j.r,j.q=60-j.q:j.q==15||j.q==30?e=1:0;j.q>21&&j.q<30?v=1:0;j.r%12?j.r<12?t=1:j.r-m<17?p=1:(o=1):0;j.q==15&&m?l=1:0;j.r%12?j.r%12==1?s=0:0:(h=0,s=0);w("Il est ");j.r==12?w("midi"):w("%s",a[j.r%12]);h?w(" heure"):0;s?w("s"):0;m?w(" moins"):0;e?w(" et"):0;l?w(" le"):0;j.q?v?w(" vingt-"):w(" "),w("%s",a[j.q-20*v]):0;t?w(" du matin"):p?w(" de l'apres-midi"):o?w(" du soir"):0;w(".\n");}

Ungolfed version, with no "space optimizations" (also pretty ugly):

#include <stdio.h>
#include <string.h>
#include <time.h>

#include <sys/time.h>

int main(int argc, char *argv[])
{
        struct timeval tv;
        struct tm local_time;
        char *nums[] = {"minuit", "une", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf", "dix", "onze", "douze", "treize", "quatorze", "quart", "seize", "dix-sept", "dix-huit", "dix-neuf", "vingt", "vingt-et-une", "vingt-deux", "vingt-trois", "vingt-quatre", "vingt-cinq", "vingt-six", "vingt-sept", "vingt-huit", "vingt-neuf", "demi"};
        int heure = 1;
        int s = 1;
        int moins = 0;
        int et = 0;
        int le = 0;
        int matin = 0, aprem = 0, soir = 0;

        memset(&local_time, 0, sizeof local_time);
        gettimeofday(&tv, NULL);
        localtime_r(&tv.tv_sec, &local_time);

#if 0
        local_time.tm_min = atoi(argv[1]);
        local_time.tm_hour = atoi(argv[2]);
#endif
        if (local_time.tm_min > 30) {
                moins = 1;
                local_time.tm_hour += 1;
                local_time.tm_min = 60 - local_time.tm_min;
        } else if (local_time.tm_min == 15 || local_time.tm_min == 30) {
                et = 1;
        }

        if (local_time.tm_hour % 12) {
                if (local_time.tm_hour < 12)
                        matin = 1;
                else if (local_time.tm_hour < 17)
                        aprem = 1;
                else if (local_time.tm_hour == 17 && moins)
                        aprem = 1;
                else
                        soir = 1;
        }

        if (local_time.tm_min == 15 && moins)
                le = 1;

        if (local_time.tm_hour % 12 == 0) {
                heure = 0;
                s = 0;
        } else if (local_time.tm_hour % 12 == 1) {
                s = 0;
        }

        printf("Il est ");

        if (local_time.tm_hour == 12)
                printf("midi");
        else
                printf("%s", nums[local_time.tm_hour % 12]);

        if (heure)
                printf(" heure");

        if (s)
                printf("s");

        if (moins)
                printf(" moins");

        if (et)
                printf(" et");

        if (le)
                printf(" le");

        if (local_time.tm_min)
                printf(" %s", nums[local_time.tm_min]);

        if (matin)
                printf(" du matin");
        else if (aprem)
                printf(" de l'apres-midi");
        else if (soir)
                printf(" du soir");

        printf(".\n");
        return 0;
}

(The #if 0 stuff was just for testing different time values through the command-line).

Tob Ernack

Posted 2015-09-25T20:25:50.493

Reputation: 211

1Props for attempting a C answer :) Look on the bright side -- it's probably shorter than it would have been in Java! – a spaghetto – 2015-09-28T22:14:01.937