Your task is to create a program that is to mimic Big Ben (Twitter).


Whenever a new hour has begun (according to your computer's local time or UTC), you have to output BONG repeated hour times (with a space between the words). For example, when it's 3 o' clock, you have to output BONG BONG BONG. The time format follows the 12-hour time format, ie after 12 o' clock, we have 1 and not 13. The program/function must run forever.


don't output stuff inside the brackets

(start: 00:34 for example)
BONG               (01:00)
BONG BONG          (02:00)
BONG               (01:00 again)
(it continues forever)


  • Each series of BONGs must be separated by a newline
  • Leading/trailing newlines are allowed
  • However leading/trailing spaces are not allowed
  • The submission must run forever
  • Your output may be printed ±3 seconds from the beginning of the hour
  • You may not assume the program to be run at any specific hour

This is , so the program with the shortest bytecount wins!

  • 8
    \$\begingroup\$ Testing these submissions is going to be fun... :D \$\endgroup\$
    – FlipTack
    Commented Dec 25, 2016 at 15:16
  • 3
    \$\begingroup\$ for 12/24 do we print 0 bongs or 12 bongs? \$\endgroup\$
    – Maltysen
    Commented Dec 25, 2016 at 22:42
  • 6
    \$\begingroup\$ +1 for a challenge which isn't easily dominated by dedicated code-golfing languages. \$\endgroup\$
    – Philipp
    Commented Dec 25, 2016 at 22:59
  • 2
    \$\begingroup\$ How should the program behave if the system clock is wound back to before 1859? \$\endgroup\$ Commented Dec 26, 2016 at 6:47
  • 3
    \$\begingroup\$ For testing one can use LD_PRELOAD hack overriding time functions: github.com/vi/timeskew . TIMESKEW="60 1" makes minutes flow like seconds. \$\endgroup\$
    – Vi.
    Commented Dec 26, 2016 at 18:46

28 Answers 28


Bash, 71, 70, 69 bytes


  • Optimized the sleep interval computation a bit, -1 byte;
  • Replaced backticks with xargs, -1 byte (Thanks @jrtc27 !).


sleep `date +3600-%s%3600|bc`;yes BONG|sed $(date +%I)q|xargs;exec $0


#Compute the number of seconds left in the current hour and wait.
sleep `date +3600-%s%3600|bc`; 

#Print "hour" (1-12) worth of "BONG" strings, one per line,
#use xargs to merge them into a single space-separated string.
yes BONG|sed $(date +%I)q|xargs

#Re-execute itself (in the same process).
exec $0

Test Version

Works with minutes instead of hours

sleep `date +60-%s%60|bc`;yes BONG|sed $(date +%I)q|xargs;exec $0
  • 2
    \$\begingroup\$ @zeppeIin I joined this community with the primary goal of worshipping you. Your solution is so full of sneaky tricks I'm still reeling from the awesomeness - especially yes BONG|sed 12q \$\endgroup\$
    – neonzeon
    Commented Dec 26, 2016 at 19:21
  • \$\begingroup\$ @neonzeon wow :) \$\endgroup\$
    – zeppelin
    Commented Dec 27, 2016 at 20:03
  • \$\begingroup\$ You can shave 1 byte off the echo by piping to xargs, which calls echo by default. 1 for pipe + 5 for xargs - 2 for backticks - 4 for echo - 1 for space = -1 byte. \$\endgroup\$
    – jrtc27
    Commented Jan 31, 2017 at 13:14
  • \$\begingroup\$ @jrtc27 That's an excellent advice! Thank you ! \$\endgroup\$
    – zeppelin
    Commented Jan 31, 2017 at 18:31

*><>, 48 47 44 bytes

v$o" GNOB"oooo$1-:?!

Try it here! (or this version which does it every minute for testing)

This outputs a number of BONGs separated by spaces based on what hour it is (and 13 is 1, etc). There are no trailing space after the final BONG, and there is a trailing newline.

Technically this doesn't run forever (but it basically does). It leaks ~28 bytes per day (ignoring interpreter overhead ...). It would take ~105062 years for it to leak 1GiB.

Approximating for interpreter overhead, the stack is just a slice of float64s on the Golang interpreter. So I simply did 28*8 to come up with 224 bytes per day. I divided this number by the number of bytes in a gibibyte (1073741824) then 365 to approximate that it would take 13132.85 years to leak 1 GiB.

Note about the interpreters

The online interpreter is in Javascript. The page must be open and visible for it to check the time it currently is and output the BONGs. The Golang interpreter has no such limitation.


Main loop:

s?um?u          O     if seconds == 0 && minutes == 0:
      hc%               push hours % 12 (bongs) to the stack
         :?!c           if bongs is 0, push 12 to the stack
             21.        jump to "output bongs" coords (2, 1)

Output bongs:

Begins at `"` because of the jump.

   " GNOB"            push "BONG " to the stack
          oooo        output "BONG"
              $1-     subtract 1 from bongs
v                :?!  if bongs == 0, move to "newline and sleep"
 $o                   output " "

Newline and sleep:

\                     mirror the IP to the right
 ao                   output a newline
   fS                 sleep for 1.6s
\                     mirror to main loop
  • \$\begingroup\$ What is the local timezone for the language's interpreter online? Because when a new hour struck for me, it didn't output anything \$\endgroup\$
    – user41805
    Commented Dec 30, 2016 at 7:53
  • \$\begingroup\$ @KritixiLithos, unfortunately for the online interpreter the page must be open and visible for it to work. I think this is a Javascript/browser limitation. You don't need to worry about it being online or not as the interpreter itself is in Javascript, you could download it yourself if you wanted! The Golang interpreter works regardless of anything though. Sorry for the inconvenience, I'll edit the answer to make that clear. \$\endgroup\$ Commented Dec 30, 2016 at 12:24
  • 1
    \$\begingroup\$ Congratulations on winning this challenge! This is the only golfing-lang to have completed this challenge and that's impressive :) \$\endgroup\$
    – user41805
    Commented Jan 7, 2017 at 12:03
  • \$\begingroup\$ @KritixiLithos thanks!! This is the first challenge I've won at all :D \$\endgroup\$ Commented Jan 7, 2017 at 14:58

JavaScript (ES6), 99 93 bytes

f=_=>setTimeout('alert("BONG ".repeat(new Date/36e5%12|0||12).trim(f()))',36e5-new Date%36e5)

This uses UTC time (which lines up with the actual thing). Due to the untestable nature of the code, you can try the following which does the same thing, but every 60 seconds:

f=_=>setTimeout('alert("BONG ".repeat(new Date/36e5%12|0||12).trim(f()))',6e4-new Date%6e4)


Here's a bonus 99-byte version which uses local time:

f=_=>setTimeout('alert("BONG ".repeat(new Date().getHours()%12||12).trim(f()))',36e5-new Date%36e5)
  • \$\begingroup\$ This (the snippet) alerts every minute for me (but the number of BONGs is correct), but the program is supposed to output every hour only \$\endgroup\$
    – user41805
    Commented Dec 25, 2016 at 19:06
  • \$\begingroup\$ @KritixiLithos "Due to the untestable nature of the code, you can try the following which does the same thing, but every 60 seconds:" ;-) \$\endgroup\$ Commented Dec 25, 2016 at 19:07

JavaScript(ES6), 125 123 117 115 bytes

Thanks to @Flp.Tkc for saving 5 bytes!

Thanks to @BenAston for saving 2 more bytes!

a=eval(b=`(new Date).getHours()`);setInterval(w=>eval(b)!=a?console.log(Array(++a%12+1).join`BONG `.trim()):"",1e3)

Snack Snippet

a=eval(b=`(new Date).getHours()`);setInterval(w=>eval(b)!=a?console.log(Array(++a%12+1).join`BONG `.trim()):"",1e3)

  • 1
    \$\begingroup\$ @BenAston Thanks for noticing that :) \$\endgroup\$
    – user41805
    Commented Dec 25, 2016 at 16:41
  • 1
    \$\begingroup\$ @BenAston It doesn't work without the first semi-colon \$\endgroup\$
    – user41805
    Commented Dec 25, 2016 at 16:43

Batch, 142 bytes

@timeout/t>nul 1
@if not %time:~3,5%==00:00 %0
@set s=............
@call set s=%%s:~%h%%%
@echo %s:.=BONG %

Since the file runs as an infinite loop, I start with a 1s delay, as I need one anyway after the bongs, and this saves CPU cycles. The >nul is positioned carefully to save a byte (1>nul would cause the 1 to be eaten by the redirection). We then loop until both minutes and seconds are zero. The bongs are constructed by taking the negative hour modulo 12, and asking for the last h characters from a 12-character string. When h is zero this actually gives us the whole string, therefore 12 bongs. It then suffices to replace the characters with the word BONG. When run it looks something like this (note that the image does not loop, so you'll need to force-reload to see the animation again):

Sample Output

  • \$\begingroup\$ Could you provide a gif of it running and outputting? \$\endgroup\$
    – user41805
    Commented Dec 26, 2016 at 9:36
  • 1
    \$\begingroup\$ @KritixiLithos Not sure what you're looking for here; I can take screenshots from before and after the hour and add a delay of up to 11 minutes in an animated GIF but I don't see how that proves anything. \$\endgroup\$
    – Neil
    Commented Dec 26, 2016 at 13:58
  • \$\begingroup\$ I am asking for a gif because I can't test it on my computer (it's a mac) \$\endgroup\$
    – user41805
    Commented Dec 26, 2016 at 13:59
  • \$\begingroup\$ @KritixiLithos Something like this OK? \$\endgroup\$
    – Neil
    Commented Dec 26, 2016 at 14:21
  • \$\begingroup\$ Good enough, I'll take your word for it :) \$\endgroup\$
    – user41805
    Commented Dec 26, 2016 at 14:21

Bash + Linux crontab, 90

I was hoping this would be shorter than the other shell answers. Still, I think it's an interesting approach:

for i in {0..11};{
s+=\ BONG
echo "0 $i,$[i+12] * * * echo$s>/proc/$PPID/fd/1"
}|crontab -

The script runs once, populates the crontab, then exits. However, the output from the cronjobs is sent to the terminal from which the script was run. I think this satisfies the submission must run forever requirement.

Warning - this will clear out any existing crontab entries, so make sure you have existing ones backed up.

This works on Ubuntu 16.04, which is using Vixie cron by default.

  • \$\begingroup\$ I ran it and got some "mail". When I checkout out the mail, there was one more BONG than necessary. \$\endgroup\$
    – user41805
    Commented Dec 30, 2016 at 7:03
  • \$\begingroup\$ @KritixiLithos Thats odd. Which Linux distro are you using? Which cron are you using? \$\endgroup\$ Commented Dec 30, 2016 at 16:27
  • \$\begingroup\$ I'm on a mac, wait, that's not Linux \$\endgroup\$
    – user41805
    Commented Dec 30, 2016 at 16:32
  • \$\begingroup\$ @KritixiLithos Yup ;-). This answer relies on Linux /proc/<PID>/fd/<N>. \$\endgroup\$ Commented Dec 30, 2016 at 16:33

Ruby, 112 99 Bytes

loop{sleep 2;n=Time.now;if(n.min==0);puts ('BONG '*n.strftime('%I').to_i).chop;sleep 60-n.sec end}

Old Version

loop{sleep(2);n=Time.now; if(n.min.zero?) then puts ('BONG ' * n.strftime('%I').to_i).chop;sleep(60-n.sec) end}

Thanks to QPaysTaxes for the tips

  • \$\begingroup\$ @Flp.Tkc Oh yes, nice catch! Forgot to delete the last character \$\endgroup\$ Commented Dec 25, 2016 at 16:02
  • \$\begingroup\$ I don't know ruby, but the program must output within 3 seconds of the start of the new hour. I don't think sleep(60) makes that happen \$\endgroup\$
    – user41805
    Commented Dec 25, 2016 at 16:02
  • \$\begingroup\$ @KritixiLithos We can make the program sleep for every 3 seconds and then do the caculation Loop -> Wake every 3 Seconds ; Check time and do stuff ? \$\endgroup\$ Commented Dec 25, 2016 at 16:06
  • \$\begingroup\$ @JatinDhankhar Or you can make it sleep for 2 seconds (just to give some breathing space) \$\endgroup\$
    – user41805
    Commented Dec 25, 2016 at 16:07
  • \$\begingroup\$ @KritixiLithos Yes, making the change to 2 seconds than Thanks \$\endgroup\$ Commented Dec 25, 2016 at 16:12

Cheddar v1.0.5, 162 bytes

Cheddar has no built-in time reader/cmd output reader, so I had to improvise!


var f=->{IO.exec("time/t>c");(String::IO.read("c")).split(":")};var a=f()[0];for(;1;){var b=f();if(b[0]!=a){var c=Number::(a=b[0]);print("BONG "*c).head(5*c-1);}}


var f=->{
var a=f()[0];
    var b=f();
        var c=Number::(a=b[0]);
        print("BONG "*c).head(5*c-1);


Due to Cheddar's limited standard library, I had to use cmd to generate the time. I did this by saving the output of "time /t", which prints the time in 12-hour format, to a file named "c". IO.read returns a buffer which I casted to a string and split by ":" which ensured the hour is always in index zero. I saved that whole operation into a lambda expression which saved me 44 bytes. After that point it goes into the logic of "if stored hour doesn't equal current hour, set previous hour to current and print BONG n times, trim off the trailing space."

Cheddar may not be the least verbose language but it can be fun to find workarounds like this!

Sadly this is a Windows-only solution.

Edit 1: Saved two bytes by replacing "0<1" in the for-condition to "1" I didn't expect 1 to evaluate to true in this language!


Ruby, 82 81 bytes

puts ("BONG "*(l.hour%12+1)).chop if(l+1).hour!=l.hour
sleep 1}

Every second we check whether it's last second of the hour, and BONG accordingly. Could probably be golfed further with some dirty tricks, but I don't know too many. Also it works differently than the other Ruby answer.

One byte saved thanks to courtesy of QPaysTaxes.

  • \$\begingroup\$ Need to get into Ruby. It seems a bit less verbose than Python for golfing. \$\endgroup\$
    – ElPedro
    Commented Dec 26, 2016 at 14:50
  • \$\begingroup\$ Do you need the space immediately after if? \$\endgroup\$
    – anon
    Commented Dec 26, 2016 at 16:04
  • \$\begingroup\$ @QPaysTaxes I don't, thank you. I was so mad about space after puts I forgot about that one. \$\endgroup\$
    – Borsunho
    Commented Dec 26, 2016 at 18:03

Python 2, 105 106 bytes

import time
while 1:
 if l[4:6]==(0,0)and h!=c:print('BONG '*c)[:-1];h=c


Added one byte by changing < to != after feedback from @pinkfloydx33. Good spot.

Tested as much as possible locally but doesn't work on TIO as it (obviously) exceeds the 60 second execution limit. Please feel free to test locally :-)

btw, losing that pesky trailing space cost me 7 bytes otherwise this would have been under 100.

In the absence of TIO here is output after waiting an hour. Prog was started at 15:27 with extra debug code to show the time of the print (12 hour format).

python bigben.py
time is 4:0:0
time is 5:0:0

Pretty straightforward but here is an explanation for anyone who is interested.

import time                 #Import the time module
h=0                         #Create a variable to store the hour that has just been printed
while 1:                    #Loop forever
 l=time.localtime()         #Get the local time from the time module
 c=l[3]%12                  #Set a variable to the current hour in 12 hour format
 if l[4:6]==(0,0)and h!=c:   #If minutes=0 and hours=0 and the last hour that was printed is not the current hour
  print "time is "+`c`+":"+`l[4]`+":"+`l[5]`    #Debug code to show hour
  print('BONG '*c)[:-1]     #Print 'BONG '*number of hours and lose the space from the end 
  h=c                       #Update the last hour that was printed
  • 1
    \$\begingroup\$ You can just check if the minutes are 0: l[4]==0and h<c. \$\endgroup\$
    – Carra
    Commented Dec 25, 2016 at 18:51
  • \$\begingroup\$ Now that I think of it, there's the small problem that it doesn't work if you start the timer on 20:00:01. Minutes will be zero, seconds not and it will print the bongs \$\endgroup\$
    – Carra
    Commented Dec 25, 2016 at 19:04
  • \$\begingroup\$ This doesn't output anything when I ran it locally \$\endgroup\$
    – user41805
    Commented Dec 26, 2016 at 11:10
  • \$\begingroup\$ @KritixiLithos No idea why you get no output. I'm on Ubuntu 14 and Python 2.7.9. Want to take this to chat to discuss further? \$\endgroup\$
    – ElPedro
    Commented Dec 26, 2016 at 16:04
  • 2
    \$\begingroup\$ Does this work from 11h->12h. (12%12=0)? Seems that 11>0, so h>c or am I missing something? \$\endgroup\$ Commented Dec 27, 2016 at 10:40

Python 3 - 100 97 92 bytes

from time import*
while 1:x=3600;sleep(x-time()%x);print(('BONG '*int(strftime("%I")))[:-1])[:-1])


import time;
while 1:
 t.sleep(x-t.time()%x);#sleep for the remaining seconds until the next hour
 print(('BONG '*int(t.strftime("%I")))[:-1])#strftime("%")=nr of hours (1-12). Print the bongs and remove the last char
  • \$\begingroup\$ from time import*<NL>while 1:x=3600;sleep(x-time()%x);print(('BONG '*int(strftime("%I")))[:-1]) is 93 bytes \$\endgroup\$ Commented Dec 27, 2016 at 11:32
  • \$\begingroup\$ I don't think you need the semicolon at the end of the first line. \$\endgroup\$
    – anon
    Commented Dec 27, 2016 at 14:20
  • \$\begingroup\$ Removed the trailing ; \$\endgroup\$
    – Carra
    Commented Dec 29, 2016 at 15:43
  • \$\begingroup\$ 92 bytes if you do from time import*, like this \$\endgroup\$
    – FlipTack
    Commented Dec 30, 2016 at 12:30
  • \$\begingroup\$ Thanks for the tip, I've added it. Learning new things about Python every day :) \$\endgroup\$
    – Carra
    Commented Dec 30, 2016 at 14:24

05AB1E, 43 bytes

3600žcžb60*+->Lvw}["BONG "ža<12%>×,5°36*.W]

Try it online! (lol this won't work, it will timeout in 60 seconds. Download the 05AB1E interpreter for this)


3600žcžb60*+->                          # Get amount of seconds (plus one) until next hour
              Lvw}                      # Wait said amount of seconds
                  [                     # Infinite loop start
                   "BONG "ža<12%>×,     # Print "BONG " multiplied by the amount of hours (12-hour clock)
                               5°36*.W  # Wait an hour (3600000 milliseconds)
                                      ] # Infinite loop end  

This took me a while to golf! I might be able to golf it a little more, but it beats *><>, so that's cool :)

Quick version:

1Uw["BONG "X<12%>×,wX>U]

Will wait one second on start, and one second between BONGs

  • \$\begingroup\$ Sorry for the delay, I finally got to running your program locally. Well done, this is particularly good for an esolang! \$\endgroup\$
    – user41805
    Commented Apr 28, 2017 at 19:01

C, 238 bytes

i,j;f(){time_t t=time(0);struct tm l=*localtime(&t);for(;;){t=time(0),l=*localtime(&t),j=l.tm_hour;sleep(1);if(!(l.tm_min+l.tm_sec)){j=j%12?j<12?j:j-12:12;for(i=0;i<=j;i++)printf("BONG%c",i^j?32:10);}}}

I'm not sure if this works correctly, and I'm mobile, and my phone doesn't have a C compiler. (Only works on UNIX-like systems)

  • \$\begingroup\$ This produced infinite output (newlines) when I tried it \$\endgroup\$
    – user41805
    Commented Dec 25, 2016 at 19:01
  • \$\begingroup\$ @KritixiLithos yes, I forgot to remove the part that I don't use anymore. Can you test in 7 minutes? :) \$\endgroup\$
    – betseg
    Commented Dec 25, 2016 at 19:53
  • \$\begingroup\$ f instead of main? How is this supposed to work? \$\endgroup\$ Commented Dec 26, 2016 at 13:10
  • 1
    \$\begingroup\$ @ThomasPadron-McCarthy I'm fairly sure that providing a function, as opposed to a full program, is fine. \$\endgroup\$
    – anon
    Commented Dec 26, 2016 at 15:55

sh, 66 bytes

yes 'echo `yes BONG|sed $(date +%I)q`'|sh -s|awk '$0!=a&&a;{a=$0}'


#Pipe a command into a subshell repeatedly
yes 'some command'|sh -s

#Print "hour" (1-12) worth of "BONG" strings, one per line,
#use backticks to merge them into a single space-separated string.
#(stolen from zeppelin's answer)
echo `yes BONG|sed $(date +%I)q`

#Print every time the output changes
awk '$0!=a&&a;{a=$0}
  • \$\begingroup\$ This prints immediately once the program is run, it should not do that. The program must only output when a new hour has began \$\endgroup\$
    – user41805
    Commented Dec 26, 2016 at 17:11
  • \$\begingroup\$ The same problem still appears \$\endgroup\$
    – user41805
    Commented Dec 26, 2016 at 17:22
  • \$\begingroup\$ @KritixiLithos My bad. I had only updated explanation and byte count, not the actual code. \$\endgroup\$
    – Rainer P.
    Commented Dec 26, 2016 at 17:32
  • \$\begingroup\$ Now all that is remaining is for me to test it at the hour \$\endgroup\$
    – user41805
    Commented Dec 26, 2016 at 17:33
  • \$\begingroup\$ @KritixiLithos Replace %I with %M and it works for minutes. \$\endgroup\$
    – Rainer P.
    Commented Dec 26, 2016 at 17:34

PowerShell, 62

for(){if(0-eq(date -f mmss)){''+,'BONG'*(date -f hh)};sleep 1}

Infinite loop, gets the minutes and seconds with -format string mmss and they're cast to ints when compared with 0-eqeuals. Gets the hour in 12 hour format with -format string hh. Implicit spaces come from joining a ,'BONG' array into a string with ''+.

  • \$\begingroup\$ The loop can run several times while mmss == 0 \$\endgroup\$
    – mazzy
    Commented Sep 1, 2020 at 16:41
  • \$\begingroup\$ @mazzy have you met PowerShell before? It isn't all that fast :-p (ok, fixed!) \$\endgroup\$ Commented Sep 1, 2020 at 17:27
  • \$\begingroup\$ you can save som bytes for(){''+,'BONG'*(date -f hh)|?{!(date -f ms)};sleep 1} :) \$\endgroup\$
    – mazzy
    Commented Sep 1, 2020 at 19:41

C, 198 bytes

h,i;f(){time_t t=time(0);struct tm l=*localtime(&t);for(h=l.tm_hour;;t=time(0),l=*localtime(&t))if(h-l.tm_hour%12){h=l.tm_hour%12;for(i=h?h%12:12;--i;)printf("BONG ");puts("BONG");}}

Javascript ES6 87 bytes

Edit: Shamelessly borrowed @ETHProductions' new Date/36e5%12|0||12 code to save 6 bytes

setInterval('Date().match`:00:00`?alert("BONG ".repeat(new Date/36e5%12|0||12)):5',1e3)


R, 104 105 bytes


Each second, it will (should) test whether we are at the end of an hour, then print that amount of BONGs.

  • \$\begingroup\$ When will this program output when the program is run at 12:00:01? \$\endgroup\$
    – user41805
    Commented Dec 25, 2016 at 15:25
  • \$\begingroup\$ I don't know R, but the program must output within 3 seconds of the start of the new hour. I am not really sure if Sys.sleep(60) makes that happen \$\endgroup\$
    – user41805
    Commented Dec 25, 2016 at 16:04
  • \$\begingroup\$ You can replace while(1) by repeat. \$\endgroup\$
    – plannapus
    Commented Dec 25, 2016 at 18:10
  • \$\begingroup\$ The sleep interval must be shorter than the grace period after the hour for correctness. How about Sys.sleep(2) ? \$\endgroup\$
    – newcoder
    Commented Dec 26, 2016 at 5:35
  • 1
    \$\begingroup\$ @newcoder Each loop it sleeps for 1 second now, because otherwise it would print BONG for 1 second, instead of just once. This is to ensure it only checks once per second. \$\endgroup\$
    – JAD
    Commented Dec 27, 2016 at 12:09

JavaScript ES2015, 100 99 98 96 94 88 bytes

h=_=>new Date/36e5%12|0,p=h();for(;;)h()!=p&&(p=h(),alert('BONG '.repeat(p||12).trim()))


h is a function that gets the 12-hour-based hour of the day using the remainder operator (%12). 36e5 is the number of milliseconds in one hour using the exponential syntax to save characters. The new operator does not require that parentheses are used with functions if there are no arguments, hence new Date. JavaScript only has floating point arithmetic, the | bitwise OR operator forces the number to be an integer because JS bitwise operators work with the integer subset of the numbers represented by IEEE 754 floating point.

The comma delineates sub-expressions. p is initialized to the current hour (p=h()).

for(;;) is used to check repeatedly whether any BONGs should be alerted. Checking is performed as rapidly as the runtime will allow.

If the hour has changed (h()!=p), then we update p and then alert the BONGs. The logical AND operator is used as a guard (it short-circuits if h()===p) to determine if the BONGs are output.

String.prototype.repeat is new in ES2015 and saves some characters over using something like ES5's Array.prototype.join.

h returns zero for exact multiples of 12 (i.e. 12pm, 12am), so we change it to 12 using the logical OR p||12.

With thanks to Kritixi Lithos and ETHProductions for ideas.

  • \$\begingroup\$ I think you can remove the last semi-colon \$\endgroup\$
    – user41805
    Commented Dec 26, 2016 at 9:42

Excel VBA, 97 Bytes

Code Outputs to the VBE Immediates Window

Do:DoEvents:n=Now:[A1]=(Hour(n)-1)Mod 12+1:?IIf(Minute(n),"",Trim([Rept("BONG ",A1)])+vbCr);:Loop

Fun version, 147 Bytes (Non-Competing)

While it would be rather difficult to get excel to go BONG, it is pretty straight forward to get excel to go Beep. The Beep call produces a beeping sound, and the code below uses this to produce beeps indicating the hour, on the hour, separated by 1 second pauses.

Sub b:Set a=Application:Do:n=Now

If Minute(n)=0 Then:For i=1To(Hour(n)-1)Mod 12+1:Beep:a.Wait(Now+#0:0:1#):Next:a.Wait(n+#0:1#):End If:Loop:End Sub

Ungolfed Version

Public Sub BigBen()
    Dim i As Byte
    Dim n As Date
    Dim w As Worksheet
    Dim a As Excel.Application
    Set a = Application
    Set w = a.ThisWorkbook.Sheets(1)
    Let w.Name = "Big Ben"

    Let w.[A1] = Now

        Let n = Now
        If Minute(n) = 0 Then

            ''  Print BONG
            Let s = ""
            For i = 1 To Hour(n) Mod 12 Step 1
                Let s = s & "BONG "
            Next i
            Debug.Print Trim(s)

            ''  Go Beep
            For i = 1 To Hour(n) Mod 12 Step 1
                a.Wait (Now + #12:00:01 AM#) ''  <- #0:0:1# resolves to #12:00:01 AM#
            Next i

            ''  Keep Ticking After Going BONG
            While Now < n + #12:01:00 AM#    ''  <- #0:1# resolves to #12:01:00 AM#
                Let w.[A1] = Now
                Let a.StatusBar = IIf(Second(Now) Mod 2, "Tick", "Tock")
        End If

        ''  Tick Tock until its time to Go BONG again
        Let a.StatusBar = IIf(Second(n) Mod 2, "Tick", "Tock")
        Let w.[A1] = Now

End Sub
  • \$\begingroup\$ Is it possible to test this on a non-Windows computer? If not, could you provide a gif of the output when a new hour begins? \$\endgroup\$
    – user41805
    Commented Dec 27, 2016 at 14:21
  • \$\begingroup\$ To be entirely honest, I am not immediately sure. It will not be possible to test this code on a linux machine, but it should function properly on a Mac. However, it may be that the Beep or DoEvents Calls do not function properly on mac machines. \$\endgroup\$ Commented Dec 27, 2016 at 14:24

C# 234 Bytes

I'm not planning on winning any prizes here, but a C# implementation is compulsory.

using System;
using System.Linq;namespace B{class P{static void Main(){Func<int> h=()=>DateTime.Now.Hour % 12;var p=h();while (true){var t=h();if (t!=p)Console.WriteLine(string.Concat(Enumerable.Repeat("BONG",t== 0?12:t)));p=t;}}}}

Ungolfed with comments:

using System;
using System.Linq;

namespace B
    class P
        static void Main()
            Func<int> h = () => DateTime.Now.Hour % 12; // h(): the hour in the range [0, 11], making this a lambda saves a few chars
            var p = h(); // p: Previous time
            while (true)
                var t = h(); // t: Current time
                if (t != p) // If current hour is different to previous hour
                    Console.WriteLine(string.Concat(Enumerable.Repeat("BONG", t == 0 ? 12 : t))); // Print "BONG" t times (also correcting t = 0 to 12)
                p = t; // Current time is now previous time
            } // Repeat ad nauseum
  • 1
    \$\begingroup\$ Use for(;;), change h=()=>1+(DateTime.Now.Hour-1)%12; (note no whitespace either) and then Enumerable.Repeat becomes ("BONG",t) (saves you either two or three) then get rid of extra whitespace ie if(...) Also note this will print all the bongs concatenated, probably take those byte savings to turn concat into join with a space as its first argument. \$\endgroup\$ Commented Dec 27, 2016 at 11:16

Groovy, 72 bytes

{x={new Date().getHours()};y=x();while(1){if(y!=(y==x()){print "BONG "*y}}​}​​​


Store a method to get current hours.

x={new Date().getHours()};

Store initial hours.


While true, if current hour not equal previous hour, output current hour multiplied by "BONG " to output current hour of bongs.

while(1){if(y!=(y==x()){print "BONG "*y}}

+3 bytes %12 for non-military bongs.


perl, 60 bytes


Replaced " " with $", removed CORE::, corrected count.


say join$",(BONG)x(time/3600%12||12)while sleep -time%3600+1

This needs to be run with perl -E.


  • In perl, x while y is equivalent to while(y){x} (where x is a single statement) but does not need the brackets. sleep is executed the first time before anything is printed.
  • time uses UTC. The original Big Ben is on summer time (British Summer Time, BST) from the end of March until the end of October.
  • One second is added to the wait time in order to ensure that the program waits for at least one second. This means that the BONGs will always be printed one second late, which is legal according to the rules. Let's say you're standing on Westminster Bridge, ca. 300 m away from Big Ben. On the plus side, this also means that the program will print the correct amount of BONGs if it is started at exactly the beginning of an hour (instead of waiting 3600 seconds).
  • sleep returns the number of seconds waited. This will always be true.
  • 1
    \$\begingroup\$ 2 things. 1, I'm pretty sure the -E flag is +1 byte (there's a page somewhere about measuring flags...). 2, I'm not sure how to run this as perl -E golf.pl appears to terminate immediately. \$\endgroup\$ Commented Dec 30, 2016 at 16:44

QBIC, 82 bytes

X=$left$|(_d,2){Y=left$$|(_d,2)~Y<>X|x=!Y!%12~x=0|x=12]B=C[x|B=B+@BONG |]?_tB|]X=Y

Really need to change the token for code literals ($) and implement a substring feature (left$(x,y) can be shorter).

The inner workings:

In the first part, we want to set X$ to the hour-component
of our system's time. The DATE is implemented in QBIC, but
Substring (LEFT$, RIGHT$ and MID$ in QBasic) is not (yet).
We need to use the QBasic LEFT$ function, and QBIC can do 
that using a 'code literal': everything from '$' to '|'
is not parsed by QBIC but passed on to QBasic.
X=               Set X$ to
$left$|(         the leftmost (note the '$' and '|' for the code literal)
_d,2)            2 characters of TIME$ (hh:mm format)
{                DO - infinite loop
Y=left$$|(_d,2)  Set Y$ in the same way
~Y<>X            If Y$ is not equal to X$ the hour has changed
|x=!Y!%12        THEN set x to the modulo 12 of Y$ cast to number
~x=0|x=12]       If Y% happens to be divisible by 12, set x to 12
B=C              Clear B$ (c$ never gets assiged a value)
[x|B=B+@BONG |]  For the given number of hours, add "BONG " to B$
?_tB|            Print B$, trim the trailing space
]                end if
X=Y              Update X$
<DO LOOP is implicitly closed>

Update (NC): The $ is no longer used in QBICs instruction set, so it can now be used freely as code for QBasic without the need for code literals. In this case, it saves 4 bytes, bringing QBIC to 78 bytes:

X=left$(_d,2){Y=left$(_d,2)~Y<>X|x=!Y!%12~x=0|x=12]B=C[x|B=B+@BONG `]?_tB|]X=Y

SmileBASIC, 74 67 bytes


Outputs large amounts of "trailing" line breaks ;)

Edit: saved 7 bytes with a better 24->12 hour algorithm.


PHP, 63 bytes

I could save two more bytes with extended ASCII. But I am currently too lazy for that.

for(;;sleep(1))+date(is)?:print str_pad("
",5*date(h),"BONG ");

prints the BONGs with a leading linebreak precisely at the full hour. Run with -nr.

  • \$\begingroup\$ You have to include the flags in your bytecount \$\endgroup\$
    – user41805
    Commented Jan 31, 2017 at 7:28
  • \$\begingroup\$ @KritixiLithos No I don´t. -n is kind of implicit (ignore php.and fall back to default config values); -r tells PHP to run code from a command line parameter instead of from a file. \$\endgroup\$
    – Titus
    Commented Jan 31, 2017 at 7:36
  • \$\begingroup\$ Ah, my bad, I don't know PHP. \$\endgroup\$
    – user41805
    Commented Jan 31, 2017 at 9:15

C, 152

int a=0,i,L=25;main(){char s[9];for(i=-1;++i<48;){sprintf(s,"%02i:00:00",i);if(!strcmp(s,__TIME__)&&i!=L)a=L=i,i=-1;printf(a-->0?"BONG ":"\n");}main();}


int a=0,i,L=25;

    char s[9];
        printf(a-->0?"BONG ":"\n");

x86-16 machine code, IBM PC DOS, 62 61 bytes


00000000: ba0b 01b8 1c25 cd21 f4eb fdb8 092c cd21  .....%.!.....,.!
00000010: 3834 741f 8834 86ca 85d2 7517 86c5 d40c  84t..4....u.....
00000020: 7502 b00c 91b5 00ba 3401 cd21 e2fc ba3a  u.......4..!...:
00000030: 01cd 21cf 424f 4e47 2024 0d0a 24         ..!.BONG $..$


BA 010B     MOV  DX, OFFSET INT_BONG    ; interrupt vector of bong proc 
B8 251C     MOV  AX, 0251CH             ; AL = 1CH (timer tick), AH = 25H (set vector)
CD 21       INT  21H                    ; set new interrupt vector 
0108    INF_LOOP: 
F4          HLT                         ; wait for interrupt 
EB FD       JMP  INF_LOOP               ; loop forever 
        INT_BONG:                       ; interrupt handler for BONG program 
B8 092C     MOV  AX, 2C09H              ; AH = get system time, AL = DOS write string 
CD 21       INT  21H                    ; CH = hour, CL = min, DH = sec
38 34       CMP  BYTE PTR[SI], DH       ; compare to previous second 
74 21       JZ   DONE                   ; if same second, do nothing 
88 34       MOV  BYTE PTR[SI], DH       ; otherwise save new second 
86 CA       XCHG CL, DL                 ; DL = min, DH = sec 
85 D2       TEST DX, DX                 ; are min and sec 0? 
75 19       JNZ  DONE                   ; if so, do nothing 
86 C5       XCHG AL, CH                 ; AL = hour, CH = DOS write string
D4 0C       AAM  12                     ; AL = AL % 12, ZF if 0 
75 02       JNZ  NOT_MID                ; if not midnight or noon, skip 
B0 0C       MOV  AL, 12                 ; if 0, set to 12 
91          XCHG AX, CX                 ; CL = hour counter, AH = DOS write string
B5 00       MOV  CH, 0                  ; clear high byte of CX 
BA 0139     MOV  DX, OFFSET BONG        ; pointer to BONG string 
CD 21       INT  21H                    ; write BONG 
E2 FC       LOOP BONG_LOOP              ; keep looping 
BA 013F     MOV  DX, OFFSET CRLF        ; display CRLF 
CD 21       INT  21H                    ; write to stdout 
CF          IRET                        ; return from interrupt
            DB   'BONG $'
            DB   0DH, 0AH,'$'

Standalone PC DOS executable COM program. This program "hooks" the INT 1CH Timer Tick interrupt which is called every 18.2 times per second (oh really?) by the hardware timer, and then runs our new program in memory. Typically you'd be considerate and set this back to original handler when done but since we don't really care about the system once we start the program, we're not really worrying about that.

Yes, this is more bytes than just a big loop, but hopefully a little bit more "interesting"!


enter image description here

enter image description here

The next day...

enter image description here


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.