This challenge is inspired by xkcd:

enter image description here


You'll simulate the copying a large file (1 Gigabyte). The transfer rate will vary between 10 kB/second to 100 MB/second. Your task is to output the time remaining of the file transfer. The output should look like:

Time remaining: 03:12    (meaning it's 3 minutes and 12 seconds left)
Time remaining: 123:12   (meaning it's 2 hours, 3 minutes and 12 seconds left)
Time remaining: 02:03:12 (optional output, meaning the same as above)

Leading zeros need not be displayed for minutes and hours (optional), but must be shown for seconds. Showing the time remaining using only seconds is not OK.

The file transfer:

  • The transfer rate will start at 10 MB/second.
  • Every second, there will be a 30% chance that the transfer rate will change
  • The new transfer rate should be picked randomly (uniform distribution) in the range [10 kB/s, 100 MB/s], in steps of 10 kB/s.

Note: You don't need to actually copy a file.

You may choose to use: 1 GB = 1000 MB, 1 MB = 1000 kB, 1 kB = 1000 B, or 1 GB = 1024 MB, 1 MB = 1024 kB, 1 kB = 1024 B.


  • You start at 01:40, not 01:39.
  • You display the time after the transfer rate changes, but before anything is transferred at that rate
  • The seconds should be displayed as integers, not decimals. It's optional to round up/down/closest.
  • You should clear the screen every second, unless that's impossible in your language.
  • The output should be constant: Time remaining: 00:00 when the file transfer is over.


I have rounded up all decimal seconds. Assume the lines below are shown with 1 second in between, and the screen is cleared between each one:

Time remaining: 01:40  (Transfer rate: 10 MB/s)
Time remaining: 01:39      1 GB - 10 MB
Time remaining: 01:38      1 GB - 2*10 MB
Time remaining: 01:37      1 GB - 3*10 MB
Time remaining: 01:28:54   1 GB - 4*10 MB  (TR: 180 kB/s)
Time remaining: 01:28:53   1 GB - 4*10 MB - 180 kB
Time remaining: 01:28:52   1 GB - 4*10 MB - 2*180 kB  
Time remaining: 00:13      1 GB - 4*10 MB - 3*180 kB  (TR: 75 MB/s)
Time remaining: 00:12      1 GB - 4*10 MB - 3*180 kB - 75 MB
Time remaining: 00:11      1 GB - 4*10 MB - 3*180 kB - 2*75 MB
Time remaining: 00:10      1 GB - 4*10 MB - 3*180 kB - 3*75 MB
Time remaining: 00:09      1 GB - 4*10 MB - 3*180 kB - 4*75 MB
Time remaining: 00:08      1 GB - 4*10 MB - 3*180 kB - 5*75 MB
Time remaining: 14:09:06   1 GB - 4*10 MB - 3*180 kB - 6*75 MB  (TR: 10 kB/s)
Time remaining: 14:09:05   1 GB - 4*10 MB - 3*180 kB - 6*75 MB - 10 kB
Time remaining: 00:06      1 GB - 4*10 MB - 3*180 kB - 6*75 MB - 20 kB  (TR: 88.110 MB/s)
Time remaining: 00:05
Time remaining: 00:04
Time remaining: 00:03
Time remaining: 00:02
Time remaining: 00:01
Time remaining: 00:00     <- Transfer is finished. Display this.
  • 1
    \$\begingroup\$ You should put the XKCD tool-tip text below the image. Save people the time of having to look it up themselves. \$\endgroup\$
    – mbomb007
    Commented Feb 2, 2017 at 20:39
  • 6
    \$\begingroup\$ @mbomb007, hover the image :) \$\endgroup\$ Commented Feb 2, 2017 at 20:43
  • \$\begingroup\$ Should that be, "you start at 1:40 (or 1:42) not 1:39 (or 1:41)"? \$\endgroup\$ Commented Feb 2, 2017 at 20:57
  • \$\begingroup\$ Also if we are using the 1024 version, what are the step sizes we should be using? \$\endgroup\$ Commented Feb 2, 2017 at 21:00
  • \$\begingroup\$ If hours remaining is zero, can we leave output as 00:00:10 for example? \$\endgroup\$ Commented Feb 2, 2017 at 21:12

9 Answers 9


Pyth - 70 68 bytes

K^T5J^T3W>KZ%." r3úBTê;¥

Try it online without sleeps.

  • \$\begingroup\$ @DigitalTrauma sorry, was using Luis' answer as a guide ._. \$\endgroup\$
    – Maltysen
    Commented Feb 3, 2017 at 1:58
  • \$\begingroup\$ @DigitalTrauma fixed. \$\endgroup\$
    – Maltysen
    Commented Feb 3, 2017 at 1:59
  • 6
    \$\begingroup\$ Lol. When porting from (golfing) language A to (golfing) language B is easier than reading the spec ;-) \$\endgroup\$ Commented Feb 3, 2017 at 2:00
  • \$\begingroup\$ @Maltysen Sorry about that! :-) \$\endgroup\$
    – Luis Mendo
    Commented Feb 3, 2017 at 2:05
  • 2
    \$\begingroup\$ Can you give an explanation of what the heck is going on here? \$\endgroup\$ Commented Feb 4, 2017 at 1:27

PowerShell, 190 215 187 bytes

($t="Time remaining: ")+"00:01:42";for($f,$r=1gb,10mb;$f-gt0;$f-=$r){if((Random 10)-lt3){$r=(Random -mi 1kb -ma (10mb+1))*10}$t+[Timespan]::FromSeconds([int]($f/$r));sleep 1}$t+"00:00:00"

Try it online! (TIO doesn't support clearing screen between lines)

Sets our initial $file size and our initial transfer $rate to 1gb and 10mb/s, respectively. Then, so long as we still have $file remaining, we loop.

Inside the loop, the if selects a number from 0 to 9 inclusive, and if it's 0, 1, or 2 (i.e., 30% of the time), we change the rate. This picks a random integer between 1kb and 10mb then that's multiplied by 10 to get our step count.

We then leverage the FromSeconds static method from the TimeSpan .NET library to construct the time remaining. The output format of that call exactly matches the challenge requirements, so no need for additional formatting.

(Saved a bunch thanks to @ConnorLSW)

  • 1
    \$\begingroup\$ @StewieGriffin TIO has output caching. Select "disable output cache" in the Settings drawer, and it gives different results. \$\endgroup\$ Commented Feb 2, 2017 at 22:03
  • \$\begingroup\$ Maybe I'm missing something but the -f operator doesn't appear to do anything. By taking that out and using for loop instead of while, and then changing both instances of get-date to date, I was able to shave off 22 bytes. Try it online! \$\endgroup\$
    – briantist
    Commented Feb 3, 2017 at 14:05
  • \$\begingroup\$ @briantist TIO requires Get-Date because otherwise it uses the Linux date command, which is different. You can drop it on Windows because PowerShell wraps the Windows date command. But, thanks for the for loop construction! \$\endgroup\$ Commented Feb 3, 2017 at 14:18
  • \$\begingroup\$ @AdmBorkBork yeah I noticed that, but in a stock Windows environment it would work. I wonder if it's acceptable to just put nal date get-date in the header in TIO? \$\endgroup\$
    – briantist
    Commented Feb 3, 2017 at 14:19
  • \$\begingroup\$ @AdmBorkBork and on windows it doesn't wrap the windows date command, it just ignores it because it's not an .exe on windows, so it falls back to the same behavior as random (try the command with get- prepended if all else fails). \$\endgroup\$
    – briantist
    Commented Feb 3, 2017 at 14:22

Ruby, 116 110 bytes

Try it online, except repl.it reads \r as a newline and also can't use $><< so it's replaced with its 5-byte equivalent, print.

Shoutout to JonasWielicki for the initial idea of using \r to reset the line.

f=1e5;r=1e3;(k=f/r=rand<0.3?1+rand(1e4):r;$><<"\rTime remaining: %02d:%02d"%[k/60,k%60];f-=r;sleep 1)while f>0

This version is untested on Windows, but works on Unix.


MATL, 78 bytes

Thanks to @Maltysen and @DigitalTrauma for corrections.

1e5 1e3`XK10&XxyXIy/t0>*12L/'MM:SS'XO'Time remaining: 'whD-r.3<?1e4Yr}K]I0>]xx

Try it at MATL Online! (you may need to press "Run" several times if it doesn't initially work).

The online interpreter times out after 30 seconds. You may want to change 10 (pause time in tenths of second) to something smaller such as 3 in order to increase speed of display


1e5                  % Push 1e5: file size in 10-kB units
1e3                  % Push 1e3: initial rate in 10-kB/s units
`                    % Do...while
  XK                 %   Copy current rate into clipboard K (doesn't consume it)
  10&Xx              %   Wait 1 second and clear screen
  y                  %   Duplicate current file size onto the top of the stack
  XI                 %   Copy it to clipboard I (doesn't consume it)
  y                  %   Duplicate current rate onto the top of the stack
  /                  %   Divide. This gives the estimated remaining time in seconds
                     %   It may be negative in the last iteration, because the
                     %   "remaining" file size may have become negative
  t0>*               %   If negative, convert to 0
  12L/               %   Push 86400 and divide, to convert from seconds to days
  'MM:SS'XO          %   Format as a MM:SS string, rounding down
  'Time remaining: ' %   Push this string
  wh                 %   Swap, concatenate
  D                  %   Display
  -                  %   Subtract. This gives the new remaining file size
  r                  %   Push random number uniformly distributed in (0,1)
  .3<                %   Is it less than 0.3?
  ?                  %   If so
    1e4Yr            %     Random integer between 1 and 1e4. This is the new rate 
                     %     in 10-kB/s units
  }                  %   Else
    K                %     Push rate that was copied into clipboard K
  ]                  %   End
  I                  %   Push previous remaining file size from clipboard I
  0>                 %   Is it positive?
]                    % End. If top of the stack is true: next iteration
xx                   % Delete the two numbers that are on the stack
  • \$\begingroup\$ I don't understand MATL, but it looks to me as if you're always getting a new rate instead of only 30% of the time from your explanation. \$\endgroup\$
    – Maltysen
    Commented Feb 3, 2017 at 1:21
  • \$\begingroup\$ @Maltysen Corrected now. Thanks for the heads-up! \$\endgroup\$
    – Luis Mendo
    Commented Feb 3, 2017 at 1:38

Bash + common utils, 117

Straightforward implementation. A few bytes saved by dividing out by 10000:

date -ud@$[b/r] "+Time remaining: %T"
sleep 1

Try it online. Using sleep 0 on the TIO so you don't have to wait. clear doesn't work on TIO.


JavaScript (ES6), 162 bytes

Shows minutes as is with padded seconds (floored)

E.g., 123:45

setInterval(c=>c.log(`Time remaining: ${c.clear(d=t/s),d/60|0}:`+`0${t-=s>t?t:s,r=Math.random,s=r()<0.3?1+r()*1e4|0:s,d%60|0}`.slice(-2)),1e3,console)

  • \$\begingroup\$ I think you forgot to shorten console.clear to c.clear ;-) That's a great idea, BTW \$\endgroup\$ Commented Feb 3, 2017 at 18:47
  • \$\begingroup\$ @ETHproductions Ooooops! Thanks :) \$\endgroup\$ Commented Feb 3, 2017 at 18:55
  • \$\begingroup\$ You could get this down to 154 bytes by adding HTML - <input id=o> - and making a couple of other adjustments: t=1e5;i=s=1e3;setInterval(_=>o.value=`Time remaining: ${(d=t/s)/60|0}:`+`0${t-=s>t?t:s,r=Math.random(),s=r<.3?1+r*1e4|0:s,d%60|0}`.slice(-2),i) \$\endgroup\$
    – Shaggy
    Commented May 12, 2017 at 14:51

Python 3.6 (212 203 bytes)

from random import*
import time,datetime
while 1:
 print(f"\x1b[KTime remaining: {datetime.timedelta(seconds=d//r)}",end="\r");d=max(0,d-r);time.sleep(1)
 if random()>.7:r=randint(1,1e4)*1e4

Pretty straightforward, I think. Erases the line using ANSI escape sequence and K command.

  • 1
    \$\begingroup\$ Skip a space in your first line with from random import*. d//r is shorter than int(d/r). Also, might as well go with r=1e7;d=1e9 from the start. \$\endgroup\$
    – Value Ink
    Commented Feb 3, 2017 at 23:55
  • \$\begingroup\$ @ValueInk Right, didn’t think of 1eX for r and d because I wanted them to be integers; when I shortened the randint line, I forgot about that ... :) \$\endgroup\$ Commented Feb 4, 2017 at 8:45

Batch, 193 bytes

@echo Time remaining: %m%:%n:~1%
@timeout/t>nul 1
@if %random:~-1% lss 3 set/ar=%random%%%p+1
@if %t% gtr 0 goto l

Note: Slight bias towards rates of 27.68 MB/s or less.


C 184 171 155 bytes

f(){i,j=0,r=1e7;for(i=1e9;i>0;i-=r){j=i/r;printf("Time remaining: %02d:%02d:%02d\r",j/3600,(j/60)%60,j%60);sleep(1);if(rand()%10<3)r=(rand()%10000)*1e4;}}

I hope this qualifies.

Ungolfed version:

void f()
    int j=0;
    float rate=1e7; 
    for(int size=1e9;i>0; size-=rate)
       printf("Time remaining: %02d:%02d:%02d\r",j/3600,(j/60)%60,j%60);




Explanation: In the golfed version i corresponds to size in ungolfed version and r is rate in ungolfed version. j stores the time remaining in seconds.

  • I have 10^9 bytes to copy. I start copying at the rate of 10 Megabytes/second,
  • If the probablity is less than 30% , change the rate (from 10 kilobytes to 100 Megabytes per second)

@ValueInk Thanks for saving 13 bytes.

@nmjcman101 Thanks for saving 16 bytes.

  • \$\begingroup\$ This doesn't look like it actually does what the challenge says. Can you explain how it works? \$\endgroup\$
    – Value Ink
    Commented Feb 4, 2017 at 6:45
  • \$\begingroup\$ It just simulates time output, i have not figured out how to do the data transfer part. Guess I'm gonna put this on hold until then. \$\endgroup\$
    – Abel Tom
    Commented Feb 4, 2017 at 6:53
  • \$\begingroup\$ You don't change the rate after 3 iterations. It has a 30% chance of changing. So you probably want to do something similar to the following: if(rand()%10<3)r=(rand()%10000+1)*1e4; (Especially since the minimum rate is 10 kB/s, not 1MB/s like your solution is saying, and the rate chance should be a somewhat uniform distribution.) \$\endgroup\$
    – Value Ink
    Commented Feb 8, 2017 at 3:40
  • \$\begingroup\$ @ValueInk Thanks so much. :) Updated. Gets the work done! I did not know how exactly to simulate the 30% probability part. So much clearer now. \$\endgroup\$
    – Abel Tom
    Commented Feb 8, 2017 at 10:01
  • \$\begingroup\$ you can golf j/3600,(j/60)%60,j%60 (21) with s=60; and j/s/s,j/s%s,j%s (20) \$\endgroup\$
    – Davide
    Commented Feb 9, 2017 at 15:19

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.