25
\$\begingroup\$

Challenge

Your task is to write a program which, once a second (including immediately when your program is started), prints the elapsed time from the time your program was started.

Rules

  • Time must be printed in hh:mm:ss format. (leading zeros for single-digit values)
  • The time stamps must be separated by CR, LF, or CRLF. (no leading whitespace)
  • A new time must appear every second. (stdout cannot be buffered for a second)
  • The behavior of the program if it is run past 23:59:59 is undefined.
  • You may use sleep(1) even if a specific second may be skipped whenever the overhead to print, calculate, loop, etc. accumulates to a second.

Example output:

00:00:00
00:00:01
00:00:02
00:00:04
00:00:05
⋮

Note that 00:00:03 is missing here due to processing overhead. The actual skipped values (if any) are of course dependent on implementation and/or system.

Reference implementation in C: (POSIX-compatible systems only)

#include <unistd.h> // sleep()
#include <tgmath.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#ifndef __STDC_IEC_559__
#error "unsupported double"
#endif
static_assert(sizeof(double) == 8, "double must have double precision");
#define MAX_PRECISE_DOUBLE ((double)(1ULL << 52))

int main(void) {
    time_t start = time(NULL);
    if (start == (time_t)-1) return EXIT_FAILURE;
    while (1) {
        time_t now = time(NULL);
        if (now == (time_t)-1) return EXIT_FAILURE;

        double diff = difftime(now, start);
        if (isnan(diff) || diff < 0) return EXIT_FAILURE;
        if (diff > MAX_PRECISE_DOUBLE) return EXIT_FAILURE;

        unsigned long long seconds = diff;
        unsigned long long h = seconds / 3600;
        seconds %= 3600;
        unsigned long long m = seconds / 60;
        seconds %= 60;
        unsigned long long s = seconds;

        (void)printf("\r%02llu:%02llu:%02llu", h, m, s);
        (void)fflush(stdout);

        (void)sleep(1);
    }
}

Winning criteria

This is , shortest code in bytes win!

\$\endgroup\$
  • \$\begingroup\$ Note for later challenges, clarification in the comments is a bad thing to do. reference \$\endgroup\$ – user202729 Dec 27 '17 at 3:56

35 Answers 35

9
\$\begingroup\$

MATL, 17 16 bytes

`Z`12L/13XOD1Y.T

Try it at MATL Online!

How it works

`         % Do...while loop
  Z`      %   Push seconds elapsed since start of program
  12L     %   Push 86400 (predefined literal)
  /       %   Divide. This transforms seconds into days
  13XO    %   Convert to date string with format 13, which is 'HH:MM:SS'
  D       %   Display
  1Y.     %   Pause for 1 second
  T       %   True. Used as loop condition for infinite loop
          % End loop (implicit)
\$\endgroup\$
  • 4
    \$\begingroup\$ How in the world did you answer this 37 minutes after it has been closed? o_O blames caching \$\endgroup\$ – Mr. Xcoder Dec 26 '17 at 19:10
  • 9
    \$\begingroup\$ @Mr.Xcoder I recently learned to use the Force \$\endgroup\$ – Luis Mendo Dec 26 '17 at 19:14
29
\$\begingroup\$

Operation Flashpoint scripting language,  174  171 bytes

s=""
#l
t=_time
t=t-t%1
a=t%60
c=(t-a)/60
b=c%60
c=(c-b)/60
d=""
e=d
f=d
?a<10:d=0
?b<10:e=0
?c<10:f=0
s=s+format["%1%2:%3%4:%5%6\n",f,c,e,b,d,a]
hint s
@t+1<_time
goto"l"

In action:

158 bytes, if the previous time is overwritten by the next time:

#l
t=_time
t=t-t%1
a=t%60
c=(t-a)/60
b=c%60
c=(c-b)/60
d=""
e=d
f=d
?a<10:d=0
?b<10:e=0
?c<10:f=0
hint format["%1%2:%3%4:%5%6",f,c,e,b,d,a]
@t+1<_time
goto"l"

Technically, no carriage return is used, so I'm not sure if this version confines to the rules.

\$\endgroup\$
  • 5
    \$\begingroup\$ I wasn't expecting operation flashpoint. \$\endgroup\$ – Polyducks Dec 27 '17 at 3:39
  • 10
    \$\begingroup\$ @Polyducks nobody expects operation flashpoint \$\endgroup\$ – Pureferret Dec 28 '17 at 12:49
  • 1
    \$\begingroup\$ @Pureferret "If you see the flash, it is already too late." \$\endgroup\$ – Steadybox Dec 28 '17 at 19:22
  • \$\begingroup\$ Since in Unix, a CR will overwrite the line, i think the second answer is validated by ‘either CR, LF, or CRLF are allowed’ \$\endgroup\$ – Stan Strum Feb 22 '18 at 20:23
  • 1
    \$\begingroup\$ @StanStrum At least on my Ubuntu CR will not overwrite the line. In fact, CRLF, LFCR and LF are all semantically equivalent. \$\endgroup\$ – user77406 Mar 6 at 7:42
13
\$\begingroup\$

Bash + coreutils, 28 26 bytes

date -s0|yes date +c%T|sh

The unprintable character between + and % is an ESC byte.

This sets the system time to 00:00:00 and thus requires root privileges. It also assumes that the timezone is UTC and that no other processes will interfere with the system clock.

Each new timing resets the terminal, thus overwriting the previous one.


Bash + coreutils, 38 29 bytes

date -s0|yes date +%T|sh|uniq

The same restrictions as before apply. Each new timing is shown on a new line.

\$\endgroup\$
  • \$\begingroup\$ Since it doesn't change the bytecount I'd separate the first date from the rest with a nice little linefeed. But it might be too nice for someone able to come up with something like your second solution >:-( \$\endgroup\$ – Aaron Dec 28 '17 at 17:03
  • \$\begingroup\$ date -s0 prints the new time to STDOUT; I'm using the pipe to silence that output. \$\endgroup\$ – Dennis Dec 28 '17 at 17:05
  • \$\begingroup\$ Oh right, thanks for the explanation ! \$\endgroup\$ – Aaron Dec 28 '17 at 17:07
5
\$\begingroup\$

APL (Dyalog Unicode), 51 bytes

Full program body.

s←⎕AI
1↓∊':'@1∘⍕¨100+3↑0 60 60 1E3⊤3⊃⎕AI-s
⎕DL 1
→2

Try it online! (Press Ctrl+Enter to start, and again to stop.)

⎕AIAccount Information (user ID, compute time, connect time, keying time)

s← assign to s (for start time)
⎕AI-s subtract s from ⎕AI

3⊃ pick the third element (connect time in milliseconds)
0 60 60 1E3⊤ convert to this mixed-radix
3↑ take the first 3 (drops the milliseconds)
100+ one hundred added to each (to pad zeros)
':'@1∘⍕¨ amend with a colon at the first character of the string representation of each
ϵnlist (flatten)
1↓ drop the first colon (and implicitly print to stdout)

⎕DL 1Delay one second

→2 go to line number two

\$\endgroup\$
5
\$\begingroup\$

R, 59 44 bytes

F in R defaults to FALSE, but it's a regular variable and can be redefined. When used in arithmetic, FALSE is coerced to 0. Asking for F+1 therefore returns 1. We assign F to be F+1, format it nicely, print, and wait for one second. Continues indefinitely.

repeat{print(hms::hms(F<-F+1))
Sys.sleep(1)}

Doesn't work on TIO (due to lack of the hms package), but here's a sample output from my machine:

00:00:00
00:00:01
00:00:02
00:00:03
00:00:04
00:00:05
00:00:06
00:00:07
00:00:08
00:00:09
00:00:10
00:00:11
00:00:12
00:00:13
\$\endgroup\$
5
\$\begingroup\$

bash + sleep + date, also 50 49 47 46 45 41 bytes

while date -ud@$[s++] +%T;do sleep 1;done

To take a lap time, quickly hit ^C, run this and then rerun the above:

laps=("${laps[@]}" $s) ; echo ${laps[-1]}

To reset:

s=0; unset laps

The $[s++] syntax appears to still work, but is no longer (AFAICS) documented in the bash man page. And it's still a byte shorter than using the for((...)) loop, once I removed the quotes around it.

\$\endgroup\$
  • \$\begingroup\$ AFAICT, $[] is a deprecated/undocumented but still supported form of $(()). I'm not sure if it's commonly used in code-golf answers, but the general rule is that your code only has to work on at least one version of the interpreter for your language. IMO it's fine. \$\endgroup\$ – Peter Cordes Dec 30 '17 at 6:39
  • \$\begingroup\$ s=0 isn't required, as arithmetic substitution will treat an unset variable as 0. -u also isn't needed if you just assume the default timezone (UTC). \$\endgroup\$ – Dennis Dec 30 '17 at 15:57
  • \$\begingroup\$ -u is needed on my machine :) \$\endgroup\$ – Will Crawford Dec 30 '17 at 18:13
4
\$\begingroup\$

Swift, 144 bytes

import Foundation
let s=Date()
while 1>0{let d=Int(-s.timeIntervalSinceNow)
print(String(format:"%02d:%02d:%02d",d/3600,d/60%60,d%60))
sleep(1)}

Explanation

import Foundation                       // Import `Date` and `sleep()`
let s = Date()                          // Get the time at the start of the program
while 1 > 0 {                           // While 1 > 0 (forever):
  let d = Int(-s.timeIntervalSinceNow)  //   Calculate time difference
  print(String(format:"%02d:%02d:%02d", //   Print the time
      d/3600,d/60%60,d%60))
  sleep(1)                              //   Sleep one second
}
\$\endgroup\$
4
\$\begingroup\$

JavaScript (ES6), 99 bytes

f=_=>console.log(new Date(new Date-d).toUTCString().slice(17,25))
f(d=Date.now(setInterval(f,1e3)))

\$\endgroup\$
  • 2
    \$\begingroup\$ The hours do not start at 0 for me. The offset changes depending on the system clock timezone. (Win10) \$\endgroup\$ – LukeS Dec 26 '17 at 21:21
  • \$\begingroup\$ @LukeS Whoops, fixed! \$\endgroup\$ – darrylyeo Dec 27 '17 at 1:41
4
\$\begingroup\$

Matlab (R2016b), 50 bytes

t=now;while 1,disp(datestr(now-t,13)),pause(1),end

Explanation:

t=now; % Stores the current time
while 1 % Loops forever
    disp(datestr(now-t,13)) % Computes the difference since the program started
    % And prints with format 13 ('HH:MM:SS') - this may change between versions
    pause(1) % Waits one second
end

Alternate version (50 bytes too :P):

now;while 1,disp(datestr(now-ans,13)),pause(1),end
\$\endgroup\$
  • \$\begingroup\$ Welcome to the site! :) \$\endgroup\$ – DJMcMayhem Dec 27 '17 at 16:46
  • \$\begingroup\$ Thanks mate :) \$\endgroup\$ – Thiago Oleinik Dec 27 '17 at 17:37
  • \$\begingroup\$ @LuisMendo Thanks for the suggestion, but I didn't understand... In your example, what is the variable t? Also, the input to datestr is in days, so I would have to divide by 86400, which would increase the byte count by two... \$\endgroup\$ – Thiago Oleinik Dec 27 '17 at 20:11
3
\$\begingroup\$

Julia 0.6, 75 68 bytes

for h=0:23,m=0:59,s=0:59;@printf "%02i:%02i:%02i
" h m s;sleep(1)end

Try it online!

With sleep(1) allowed, simple nested for-loops are shorter than using Julias built-in time handling methods.

Old solution without sleep(1) using DateTime

t=now()-DateTime(0);Timer(x->println(Dates.format(now()-t,"HH:MM:SS")),0,1)

t is the amount of time passed from 'day 0' to when the program is started. now()-t is a moment in time, which is then formatted using Dates.format().

t0=now(); ...; now()-t0 would yield a time difference, that cannot be used with Dates.format().

The timing itself is trivial with the build-in Timer.

\$\endgroup\$
3
\$\begingroup\$

Python 2, 85 bytes

import time
t=0
while 1:print(":%02d"*3)[1:]%(t/3600,t/60%60,t%60);time.sleep(1);t+=1

Credits

\$\endgroup\$
  • \$\begingroup\$ You can save one byte by replacing "%02d:%02d:%02d" with (":%02d"*3)[1:] \$\endgroup\$ – wnnmaw Dec 27 '17 at 20:33
  • 1
    \$\begingroup\$ You don't need %24, behavior is undefined after 23:59:59. \$\endgroup\$ – Erik the Outgolfer Dec 28 '17 at 12:48
  • \$\begingroup\$ @EriktheOutgolfer Good point, updated. \$\endgroup\$ – Neil Dec 28 '17 at 20:42
3
\$\begingroup\$

JavaScript (ES6), 88 bytes

f=_=>console.log(new Date(i++*1e3).toUTCString().slice(17,25))
f(i=0,setInterval(f,1e3))

Essentially the same approach as @darrylyeo's answer, but works for all timezones and uses a slightly different way to get to 0.

[Edit] Darryl's answer has been fixed. This is still shorter, though.

\$\endgroup\$
3
\$\begingroup\$

><>, 82 + 7 = 89 bytes

0\!
:/+1oan~?=3ln?$0(a:o":"n~?=4ln?$0(a:ro":"n~?=5ln?$0(a:,*a6-}:%*a6:,*a6-}:%*a6:

Try it online!

+7 bytes for using the flag -t.0125 to make the each instruction take 1/80th of a second. Each loop has 80 instructions, making each loop one second long. Because of computation time, this is actually longer in practice.

I actually had to buffer this all the way up to 100 until I saw @Not A Tree's answer which had 7 byte better way than mine to generate the hours and minutes, trimming it below 80. They also inspired the use of \/ which are executed twice per loop.

How It Works

0\...
./...
Initialises the stack with a 0 to represent the time

0\!
:/....................................................,*a6-}:%*a6:,*a6-}:%*a6:
Puts the hours, minutes and seconds in the stack

0\!
:/....n~?=3ln?$0(a:o":"n~?=4ln?$0(a:ro":"n~?=5ln?$0(a:...
Print out the hours, minutes, seconds separated by colons. 
If the number is below 0, print a leading 0. 
If the number is not, then there is an extra 0 on the stack, which is popped.

0\!
./+1oa...
Print a newline and increment the counter
And restart the loop

Bonus:

A one line version of the same size, 80 + 9 bytes:

0::6a*%:}-6a*,:6a*%:}-6a*,:a(0$?nl5=?~n":"or:a(0$?nl4=?~n":"o:a(0$?nl3=?~nao1+>!

This uses the -a flag to add ticks for skipped instructions.

\$\endgroup\$
3
\$\begingroup\$

PHP 4+, 70 64 bytes

$x=time();while(1){sleep(1);echo date('H:i:s',time()-$x)."\n";}

PHP 5.3+, 69 63 bytes

$x=time();a:sleep(1);echo date('H:i:s',time()-$x)."\n";goto a;
\$\endgroup\$
  • \$\begingroup\$ PHP open tags can be omitted in the answer saving you 6 bytes. \$\endgroup\$ – Daniel W. Dec 28 '17 at 12:23
2
\$\begingroup\$

Python 3, 112 bytes

Assuming using 1-second delays is ok, even if it (rarely) might skip a second.

from time import*;a=0
while 1:d=divmod;m,s=d(a,60);print(":".join(f"{k:02d}"for k in(*d(m,60),s)));a+=1;sleep(1)
\$\endgroup\$
2
\$\begingroup\$

VBA, 90

t=0:while(1):?format(t,"hh:mm:ss"):t=t+timeserial(0,0,1):q=timer:while q-timer<1:wend:wend

run in immediate window:expected failure point somewhere around 23 million years (floating point resolution fails ~8.5e9 days)

\$\endgroup\$
2
\$\begingroup\$

Jelly, 23 bytes

:⁽½c,60;%60d⁵j”:ṄœS1ṛ‘ß

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Does it work with times above 1 minute? \$\endgroup\$ – H.PWiz Dec 27 '17 at 16:58
  • \$\begingroup\$ @H.PWiz It should, running some tests. EDIT: Looks like a dividend is wrong for the hours...fixed for a little save! \$\endgroup\$ – Erik the Outgolfer Dec 27 '17 at 17:00
2
\$\begingroup\$

AWK, 110 87 86 bytes

BEGIN{for(;;i++){printf("%02d:%02d:%02d\n",i/3600%60,i/60%60,i%60);system("sleep 1")}}

Does not work in TIO.

\$\endgroup\$
  • \$\begingroup\$ Your program doesn't seem to print 00:00:00 at the moment it's started. \$\endgroup\$ – user202729 Dec 27 '17 at 16:13
  • \$\begingroup\$ Fixed it. Thanks \$\endgroup\$ – Noskcaj Dec 27 '17 at 16:28
2
\$\begingroup\$

APL (Dyalog), 37 bytes

{∇⍵+×⎕DL 1⊣⎕←1↓∊':'@1∘⍕¨100+⍵⊤⍨3⌿60}0

Try it online!

Full program.

Pretty similar to Adám's answer, however independently written and uses a non-⎕AI-based approach.

\$\endgroup\$
2
\$\begingroup\$

Bash + coreutils + GNU date, 50 bytes

o=`date +"%s"`;yes date +%X -ud\"-$o sec\"|sh|uniq

Inspired by @Dennis, this solution doesn't require the time to be changed. It store stores the initial offset from now to the UNIX epoch (1 Jan 1970 00:00:00 UTC), in 'o', and then displays [-ud options] (the current time - offset), in UTC date, but only [+%X option] HH:MM:SS. This should work in countries where the current time-zone isn't UTC.

\$\endgroup\$
2
\$\begingroup\$

Clean, 173 172 168 bytes

import StdEnv,System.Time
$n i#i=(i/60^n)rem 60
=(i/10,i rem 10)
f i w#(Clock j,w)=clock w
#j=j/1000
|j>i=[j:f j w]=f i w
Start w=[($2i,':',$1i,':',$0i,'
')\\i<-f -1 w]

This one only works under the Windows Clean bundles.

Add 3 bytes if you want it to work under Linux, as Clean's CLK_PER_TICK :== 1000000 on *nix. If you want it to be cross-platform, add 8 bytes instead, as you need to use CLK_PER_TICK instead of the value it's set to. (TIO link is larger due to above)

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Python 2, 69 + 3 (TZ=) = 72 bytes

from time import*;s=time()
while 1:print ctime(time()-s)[11:19]+'\r',

This runs in a continuous loop, without sleeping, updating the time on the same line rather than printing a new line each second. (Still allowed by the rules, I hope.)

This slightly longer version (72+3=75 bytes) prints on a new line every second instead:

from time import*;s=time()
while 1:print ctime(time()-s)[11:19];sleep(1)

Both of these require you to be in the UTC timezone. On Linux you can achieve this by setting the TZ environment variable. E.g. TZ= python.

\$\endgroup\$
2
\$\begingroup\$

><>, 106 bytes 82 + 9 = 91 bytes

Thanks to Jo King for suggesting the -a flag! Check out their answer too.

0v+1oan<n0/
:/<</?(a:,*a6-}:%*a6:,*a6-}:%*a6:\\
n<n0/<</?(a:ro":"
":"n<n0/<</?(a:o

Try it online! (but you'll have to wait for the 60 second timeout).

I got to use a feature of ><> that I've never needed before: this code requires the flag -t.0125, which sets the execution speed to 0.0125 seconds per tick, or 80 ticks per second. There's also the -a flag, which makes whitespace count as a tick (in some cases — the interpreter is a bit weird about this).

Basically, the code keeps a counter that's incremented each time the fish goes through the loop, and the rest of the loop converts the counter to hh:mm:ss format and prints it. The loop takes exactly 80 ticks.

This should work in theory, but in practice, each tick is slightly longer than 0.0125 seconds, because of computation time. Changing the \\ on the second line to << gives more accurate timings on TIO.

You can also watch the code in action at the fish playground, except that this interpreter treats whitespace slightly differently from the official interpreter. Alternatively, you can remove the flags on TIO to make the code run at top speed, to verify the behaviour for times after one minute.

\$\endgroup\$
  • \$\begingroup\$ -1 byte by replacing the v in the first line with \! and removing two of the extra <. Another couple of bytes if you use the -a flag, which counts whitespace and skipped instructions as ticks \$\endgroup\$ – Jo King Dec 30 '17 at 18:40
  • \$\begingroup\$ @JoKing, The -a flag let me golf it a bit more, thank you! I think you can use the \! trick in your code, too: Try it online! \$\endgroup\$ – Not a tree Dec 30 '17 at 20:10
2
\$\begingroup\$

Java 8, full program, 150 bytes

interface M{static void main(String[]a)throws Exception{for(int i=0;;Thread.sleep(1000))System.out.printf("%02d:%02d:%02d%n",i/3600,i/60%60,i++%60);}}

Try it here (times out after 60 seconds, so I've set the sleep to 1 to see more output).

Explanation:

interface M{                    // Program:
  static void main(String[]a)   //  Mandatory main-method
     throws Exception{          //    Mandatory throws for Thread.sleep
    for(int i=0;                //   Start at 0
        ;                       //   Loop indefinitely
         Thread.sleep(1000))    //     After every iteration: Sleep for 1 sec
      System.out.printf("%02d:%02d:%02d%n",
                                //    Print in the format "HH:mm:ss\n":
        i/3600,i/60%60,i++%60); //     The hours, minutes and seconds
                                //     (and increase `i` by 1 afterwards with `i++`)
                                //   End of loop (implicit / single-line body)
  }                             //  End of mandatory main-method
}                               // End of program

Java 8, function, 94 bytes

v->{for(int i=0;;Thread.sleep(1000))System.out.printf("%02d:%02d:%02d%n",i/3600,i/60%60,i++%60);}

Try it here (times out after 60 seconds, so I've set the sleep to 1 to see more output).

Explanation:

v->{   // Method with empty unused parameter and no return-type
  ...  //  Same as the program above
}      // End of method

Here is a small gif to see it works as intended when 1000 ms are used:

enter image description here

\$\endgroup\$
2
\$\begingroup\$

PHP, 59 48 bytes

while(1){sleep(1);echo date('H:i:s',$i++)."\n";}

Inspired by Darren H's answer.

Old version :

<?php while(1){sleep(1);echo date('H:i:s',$i++-3600)."\n";}
\$\endgroup\$
  • \$\begingroup\$ PHP open tags can be omitted in the answer saving you 6 bytes. \$\endgroup\$ – Daniel W. Dec 28 '17 at 12:23
  • \$\begingroup\$ Great thought, but 3600 needs to be 86400 otherwise the counter starts at 23:00:00 so unfortunately you gain a byte, still beat me by 9 though! \$\endgroup\$ – Darren H Jan 1 '18 at 20:41
  • \$\begingroup\$ @DarrenH I think it depends on your locale, I hadn't thought about that. I'm in GMT+1, that's why I added 3600, but I guess for English people, you could remove the -3600 altogether, which would save 5 bytes. \$\endgroup\$ – roberto06 Jan 2 '18 at 12:13
1
\$\begingroup\$

Shell, 177 bytes

Notice that this is not entirely POSIX conformant because it uses date +%s, which is a common date expansion.

a=`date +%s`;while true;do b=`date +%s`;s=`expr $b - $a`;h=`expr $s / 3600`;s=`expr $s % 3600`;m=`expr $s / 60`;s=`expr $s % 60`;printf '\r%02d:%02d:%02d' $h $m $s;sleep 1;done
\$\endgroup\$
  • 7
    \$\begingroup\$ Normally, you should give people a chance to answer your challenge before answering it yourself. I recommend a week as some may only be here at certain times during the week. \$\endgroup\$ – Adám Dec 26 '17 at 18:02
  • 1
    \$\begingroup\$ @Adám I haven't accepted my answer, and at the time I posted much shorter answers (like yours) were submitted. \$\endgroup\$ – MarkWeston Dec 28 '17 at 12:24
1
\$\begingroup\$

Ruby, 192 117 bytes (Credit to Dada)

t=Time.now
loop do
m,s=(Time.now-t).to_i.divmod(60)
h,m=m.divmod(60)
printf"%02d:%02d:%02d
",h,m,s
sleep 1
end

How does it work?

Going to use the expanded version (Conversion to a time is given as a separate function and uses a different output format):

def format_secs(s) # Converts the value in seconds to the required format
    mins, secs = s.divmod(60) # divmod returns the quotient and the remainder of a number
    hours, mins = mins.divmod(60)
    [hours,mins,secs].map { |e| e.to_s.rjust(2,'0') }.join ':'

    =begin
    [hours,mins,secs] -Creates a new array using the values allready provided for hours, minutes and seconds
    .map { - Creates a new array based on a operation on each of an array's values
    .to_s.rjust(2,'0')} - Turns the number into a string, and then adds "0" if needed to make the timer's result at least two digits
    .join ':' - Combines the result of the operation into a single string with a ":" in between the two numbers
    =end
end

t = Time.now # Saves the time at the program's (Rough) start

loop do
    puts format_secs((Time.now - t).to_i) # Returns the result of  the "format_secs" operation on the difference between the two times (in seconds) converted to a pure integer
    sleep 1 # Waits for one second
end
\$\endgroup\$
  • 6
    \$\begingroup\$ Welcome on the site! Every answer to a code-golf challenge must be golfed. You should at least remove useless whitespaces, and use 1-character variable names. That would get you around 120 bytes, and using printf instead of puts can save a few more bytes: Try it online!. Happy golfing on PPCG! \$\endgroup\$ – Dada Dec 28 '17 at 10:06
1
\$\begingroup\$

APL NARS, 109 63 57 chars

q;t
t←0
{∊⍵,¨':: '}{1<⍴x←⍕⍵:x⋄'0',x}¨(3⍴60)⊤⌊t+←⎕DL 1⋄→2

3+3+48+3=57 (seen the others Apl solutions too)

{1<⍴x←⍕⍵:x⋄'0',x}

convert the INT ⍵ in the string of digits in a way if the lenght of that string is 1 than add one '0' in front of it

{∊⍵,¨':: '}

combine array in ⍵ with the array ':: '

00:00:01 
00:00:02 
00:00:03 
00:00:04 
00:00:05 
00:00:06 
00:00:07 
00:00:08 
00:00:09 
\$\endgroup\$
1
\$\begingroup\$

x86-64 machine code (Linux system call): 78 bytes

RDTSC spin-loop timing, Linux sys_write system call.

x86-64 doesn't provide a convenient way to query the RDTSC "reference clock" frequency at run time. You can read an MSR (and do a calculation based on that), but that requires kernel mode, or root + opening /dev/cpu/%d/msr, so I decided to make the frequency a build-time constant. (Adjust FREQ_RDTSC as necessary: any 32-bit constant won't change the size of the machine code)

Note that x86 CPUs for several years have had fixed RDTSC frequency so it is usable as a timesource, not a core clock cycle performance counter unless you take steps to disable frequency changes. (There are actual perf counters for counting real CPU cycles.) Usually it ticks at the nominal sticker frequency, e.g. 4.0GHz for my i7-6700k regardless of turbo or powersaving. Anyway, this busy-wait timing doesn't depend on load average (like a calibrated delay-loop would), and also isn't sensitive to CPU power saving.

This code will work for any x86 with a reference frequency below 2^32 Hz, i.e. up to ~4.29 GHz. Beyond that, the low 32 of the timestamp would wrap all the way in 1 second, so I'd have to look at the edx high 32 bits of the result, too.

Summary:

push 00:00:00\n on the stack. Then in a loop:

  • sys_write system call
  • ADC-loop over the digits (starting with the last) to increment the time by 1. Wrapping / carry-out handled with a cmp / cmov, with the CF result providing the carry-in for the next digit.
  • rdtsc and save the start time.
  • spin on rdtsc until the delta is >= ticks per second of the RDTSC frequency.

NASM listing:

 1  Address                            ; mov  %1, %2       ; use this macro to copy 64-bit registers in 2 bytes (no REX prefix)
 2           Machine code           %macro MOVE 2
 3           bytes                      push  %2
 4                                      pop   %1
 5                                  %endmacro
 6                                  
 7                                      ; frequency as a build-time constant because there's no easy way detect it without root + system calls, or kernel mode.
 8                                      FREQ_RDTSC equ 4000000000
 9                                  global _start
10                                  _start:
11 00000000 6A0A                        push     0xa                       ; newline
12 00000002 48BB30303A30303A3030        mov      rbx, "00:00:00"
13 0000000C 53                          push     rbx
14                                      ; rsp points to  `00:00:00\n`
20                                  
21                                      ; rbp = 0                (Linux process startup.  push imm8 / pop is as short as LEA for small constants)
22                                      ; low byte of rbx = '0'
23                                  .print:
24                                      ; edx potentially holds garbage (from rdtsc)
25                                  
26 0000000D 8D4501                      lea      eax, [rbp+1] ; __NR_write = 1
27 00000010 89C7                        mov      edi, eax     ; fd = 1 = stdout
28                                      MOVE     rsi, rsp
28 00000012 54                  <1>  push %2
28 00000013 5E                  <1>  pop %1
29 00000014 8D5008                      lea      edx, [rax-1 + 9]     ; len = 9 bytes.
30 00000017 0F05                        syscall               ; sys_write(1, buf, 9)
31                                  
32                                      ;; increment counter string:  least-significant digits are at high addresses (in printing order)
33 00000019 FD                          std                        ;  so loop backwards from the end, wrapping each digit manually
34 0000001A 488D7E07                    lea      rdi, [rsi+7]
35                                      MOVE     rsi, rdi
35 0000001E 57                  <1>  push %2
35 0000001F 5E                  <1>  pop %1
36                                  
37                                      ;; edx=9 from the system call
38 00000020 83C2FA                      add   edx, -9 + 3      ; edx=3 and set CF (so the low digit of seconds will be incremented by the carry-in)
39                                      ;stc
40                                  .string_increment_60:          ; do {
41 00000023 66B93902                    mov    cx, 0x0200 + '9'    ; saves 1 byte vs. ecx.
42                                      ; cl = '9' = wrap limit for manual carry of low digit.  ch = 2 = digit counter
43                                    .digitpair:
44 00000027 AC                          lodsb
45 00000028 1400                        adc      al, 0           ; carry-in = cmp from previous iteration; other instructions preserve CF
46 0000002A 38C1                        cmp      cl, al          ; manual carry-out + wrapping at '9' or '5'
47 0000002C 0F42C3                      cmovc    eax, ebx        ; bl = '0'.  1B shorter than JNC over a MOV al, '0'
48 0000002F AA                          stosb
49                                  
50 00000030 8D49FC                      lea     ecx, [rcx-4]    ; '9' -> '5' for the tens digit, so we wrap at 59
51 00000033 FECD                        dec     ch
52 00000035 75F0                        jnz    .digitpair
53                                      ; hours wrap from 59 to 00, so the max count is 59:59:59
54                                  
55 00000037 AC                          lodsb                        ; skip the ":" separator
56 00000038 AA                          stosb                        ; and increment rdi by storing the byte back again.  scasb would clobber CF
57                                  
58 00000039 FFCA                        dec     edx
59 0000003B 75E6                        jnz   .string_increment_60
60                                  
61                                      ; busy-wait for 1 second.  Note that time spent printing isn't counted, so error accumulates with a bias in one direction
62 0000003D 0F31                        rdtsc                         ; looking only at the 32-bit low halves works as long as RDTSC freq < 2^32 = ~4.29GHz
63 0000003F 89C1                        mov      ecx, eax             ; ecx = start
64                                  .spinwait:
65                                  ;    pause
66 00000041 0F31                        rdtsc                      ; edx:eax = reference cycles since boot
67 00000043 29C8                        sub      eax, ecx          ; delta = now - start.  This may wrap, but now we have the delta ready for a normal compare
68 00000045 3D00286BEE                  cmp      eax, FREQ_RDTSC   ; } while(delta < counts_per_second)
69                                   ;   cmp      eax, 40  ; fast count to test printing
70 0000004A 72F5                        jb     .spinwait
71                                  
72 0000004C EBBF                        jmp .print
  next address = 0x4E = size = 78 bytes.

Uncomment the pause instruction to save significant power: this heats one core up by ~15 degrees C without pause, but only by ~9 with pause. (On Skylake, where pause sleeps for ~100 cycles instead of ~5. I think it would save more if rdtsc wasn't also slow-ish so the CPU isn't doing much a lot of the time).


A 32-bit version would be a few bytes shorter, e.g. using a 32-bit version of this to push the initial 00:00:00\n string.

16                          ;    mov      ebx, "00:0"
17                          ;    push     rbx
18                          ;    bswap    ebx
19                          ;    mov      dword [rsp+4], ebx    ; in 32-bit mode, mov-imm / push / bswap / push would be 9 bytes vs. 11

And also using 1-byte dec edx. The int 0x80 system call ABI wouldn't use esi / edi, so the register setup for the syscall vs. lodsb / stosb might be simpler.

\$\endgroup\$
  • \$\begingroup\$ I could have used a nanosleep system call, but this was more interesting. With root on Linux, it is possible to read the right MSR and programmatically get the RDTSC frequency. \$\endgroup\$ – Peter Cordes Jan 2 '18 at 20:42
1
\$\begingroup\$

q/kdb+, 40 bytes

Solution:

.z.ts:{-1($)18h$a+:1};a:-1;(.)"\\t 1000"

Example:

q).z.ts:{-1($)18h$a+:1};a:-1;(.)"\\t 1000"
q)00:00:00
00:00:01
00:00:02
00:00:03
00:00:04
00:00:05

Explanation:

There are three commands being executed here:

  1. .z.ts:{-1($)18h$a+:1}; / override timer function
  2. a:-1; / initialise variable a to -1
  3. (.)"\\t 1000" / start the timer with 1000ms precision

Breakdown of the timer function:

.z.ts:{-1 string 18h$a+:1} / ungolfed timer function
      {                  } / lambda function
                     a+:1  / add 1 to variable a
                 18h$      / cast to seconds
          string           / cast to string
       -1                  / write to stdout
.z.ts:                     / assign this function to .z.ts

Bonus:

Alternative 1 for 41 bytes:

a:.z.t;.z.ts:{-1($)18h$x-a};(.)"\\t 1000"

Alternative 2 for 26 + 7 bytes = 33 bytes

.z.ts:{-1($)18h$a+:1};a:-1

and adding -t 1000 as arguments to the q binary.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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