27
\$\begingroup\$

Well, Brexit happened. And Sky News, being the geniuses they are, have decided to create a countdown on the side of a bus.

enter image description here

Your job is to do something similar. The UK leaves the the EU on 31st of March 2019 and you have to create a digital countdown for this that changes every second (with a 0.05 second deviation allowed).

Input

Your program should take absolutely no input. It is banned!

Output

It should output the time until Brexit in the format ddd:hh:mm:ss. Leading and trailing newlines are allowed but the display should stay in the same place each time. It should look as though it is actually decreasing in place. As pointed out by @AnthonyPham this doesn't mean printing enough newlines to "clear" the screen, this means that you must actually clear the screen.

An output like this isn't allowed:

100:20:10:05
100:20:10:04

Neither is this

100:20:10:05
*A thousand newlines*
100:20:10:04

as they're on more than one line.

You don't have to worry about after Brexit. Your program only has to work up to 31/3/2019

Rules

  • Standard loopholes are disallowed
  • This is so shortest code in bytes wins.
  • Error messages (although I can't think how) are disallowed
  • The code should be able to be run in 2 years time (when the UK leaves the EU) and should display the actual time and not start from 730 again (see below)

Countdown rule

The countdown should not be hard-coded and should be able to run at any time before Brexit finishes and still produce the correct result. When a new day is begun the hour should follow the below format

712:00:00:01
712:00:00:00
711:23:59:59

Let me say again, the date Brexit finishes is 31/3/2019 at midnight for convenience (31:3:19 00:00:00 or 31:3:2019 00:00:00 or any other format you want)

NB: I think I have everything but I didn't post this in the Sandbox, otherwise the timing could have been off. Feel free to post any suggestions for improvements because it isn't perfect.

\$\endgroup\$
  • \$\begingroup\$ Can I run it every millisecond but still give the appearance of updating every second? This is just to make my code shorter. \$\endgroup\$ – David Archibald Apr 2 '17 at 21:47
  • \$\begingroup\$ @DavidArchibald it only says that the display has to change every second. It's just that most answers will find it easier to run every second. \$\endgroup\$ – caird coinheringaahing Apr 2 '17 at 21:49
  • \$\begingroup\$ ahh. Well I have to put 1000 if I want it to change once a second. Thanks \$\endgroup\$ – David Archibald Apr 2 '17 at 21:53
  • \$\begingroup\$ Are leading zeros required? \$\endgroup\$ – Shaggy Apr 3 '17 at 12:38
  • 1
    \$\begingroup\$ Midnight what timezone: UCT or GMT? Do we have to take that into account? \$\endgroup\$ – Titus Apr 7 '17 at 10:51

24 Answers 24

12
\$\begingroup\$

JavaScript, 134 129 113 bytes

setInterval("d=-new Date;document.body.innerHTML=`<pre>${d/864e5+17986|0}:`+new Date(d).toJSON().slice(11,19)",1)

Edit: Saved 2 bytes thanks to @Shaggy. Saved 11 bytes thanks to @l4m2.

\$\endgroup\$
  • \$\begingroup\$ Managed to beat you @Neil... by a few bytes. \$\endgroup\$ – David Archibald Apr 3 '17 at 3:35
  • \$\begingroup\$ Why not use <a id=0>? Or something like that? \$\endgroup\$ – Solomon Ucko Apr 3 '17 at 15:08
  • 3
    \$\begingroup\$ Or even document.body.innerHTML instead of o.innerHTML \$\endgroup\$ – cloudfeet Apr 3 '17 at 15:43
  • 1
    \$\begingroup\$ I wanted it to be monospace to ensure that the display stays in the same place, but I guess I could save a byte and use <tt>. \$\endgroup\$ – Neil Apr 3 '17 at 18:34
  • 3
    \$\begingroup\$ You could save 2 bytes by running the code every millisecond (or 2, or 3 ...). \$\endgroup\$ – Shaggy Apr 4 '17 at 8:47
11
\$\begingroup\$

PowerShell, 70 63 55 53 Bytes

Excluded double quotes, easy -2 thanks to @Joey

for(){cls;(date 31Mar19)-(date)|% T* ddd\:hh\:mm\:ss}

Running this with sleep adds 8 bytes, but the input is mostly invisible if it is run without them, version (63 bytes) with sleep:

for(){cls;(date 31/3/19)-(date)|% T* ddd\:hh\:mm\:ss;sleep 1}

for() is an infinite loop, and within that loop..

cls to clear the screen,

get 31/3/19 as a DateTime object, and - the current date from it, to give the time remaining, then .ToString() (|% T*) that with the correct format.

this will display negative time after brexit.

\$\endgroup\$
  • \$\begingroup\$ This is also sensitive to local date format. Though the UK dd/m/yy format is appropriate, imo, it won't run as-is on US machines. I'm curious how the T* works. I'm not familiar with that. \$\endgroup\$ – Joel Coehoorn Apr 3 '17 at 20:57
  • \$\begingroup\$ @JoelCoehoorn It's a nice trick, the % foreach actually picks up the ToString object, and will accept the next string as its argument. regarding the datetime format why won't it run on US machines? I thought the dd etc were culture-insensitive. \$\endgroup\$ – colsw Apr 3 '17 at 21:04
  • \$\begingroup\$ It's trying to find month #31 on my machine. Works fine if I change it to 3/31/19. Would also work 2019-03-31 anywhere, but that costs you a few bytes. \$\endgroup\$ – Joel Coehoorn Apr 3 '17 at 21:15
  • \$\begingroup\$ @JoelCoehoorn ah right - sorry I was thinking of the output, Updated to 31Mar19 instead of 31/3/19 which should hopefully fix it? \$\endgroup\$ – colsw Apr 3 '17 at 21:18
  • 1
    \$\begingroup\$ You can lose the quotes around the format string, as command argument parsing applies. \$\endgroup\$ – Joey Jul 8 '18 at 20:04
7
\$\begingroup\$

Excel VBA, 91 84 82 bytes

Saved 7 bytes thanks to JoeMalpass pointing out that Excel sees dates as numbers.
Saved 2 bytes thanks to JoeMalpass

Sub b()
Do
t=CDec(43555-Now)
Cells(1,1)=Int(t) &Format(t,":hh:mm:ss")
Loop
End Sub

Output is to cell A1 in the active Excel sheet.

\$\endgroup\$
  • \$\begingroup\$ -6 bytes by swapping ("2019-3-31") with (43555). When I try running this in Excel however, it freezes after about 5-6 seconds... \$\endgroup\$ – CactusCake Apr 3 '17 at 14:54
  • 1
    \$\begingroup\$ @JoeMalpass Thanks, that's a good point. It looks up after a few seconds for me, too, because it's calculating way faster than 1/second. Adding delays, though, adds bytes and the OP doesn't say it has to be able to continuously count down from now until Brexit without setting anything on fire. \$\endgroup\$ – Engineer Toast Apr 3 '17 at 16:16
  • \$\begingroup\$ Apparently Now works without the () too... \$\endgroup\$ – CactusCake Apr 3 '17 at 19:21
6
\$\begingroup\$

Python 3.6, 146 bytes

from datetime import*
x=datetime
while 1:d=x(2019,3,31)-x.now();s=d.seconds;a=s%3600;print(end=f"\r{d.days:03}:{s//3600:02}:{a//60:02}:{s%60:02}")
\$\endgroup\$
5
\$\begingroup\$

C#, 173 172 156 150 127 bytes

using System;class P{static void Main(){for(;;)Console.Write($"\r{new DateTime(2019,3,31)-DateTime.Now:d\\:hh\\:mm\\:ss}  ");}}

Saved 16 bytes thanks to @Bob Saved 6 bytes thanks to @Søren D. Ptæus

Formatted version:

using System;

class P
{
    static void Main()
    {
        for (;;)
            Console.Write($"\r{new DateTime(2019, 3, 31) - DateTime.Now:d\\:hh\\:mm\\:ss}  ");
    }
}
\$\endgroup\$
  • \$\begingroup\$ Can you do (TimeSpan)0? On phone, can't test right now. You can still drop the clear as the carriage return takes care of it: it puts the cursor back at the start of the line. \$\endgroup\$ – Bob Apr 3 '17 at 8:42
  • 2
    \$\begingroup\$ Thought: relying on the CR might fail if the length changes (less than 100 days). Fix: add two extra spaces on end. \$\endgroup\$ – Bob Apr 3 '17 at 8:45
  • \$\begingroup\$ @Bob I forgot to remove the Clear! Silly me. And no can't convert int to TimeSpan I'd already tried that one. \$\endgroup\$ – TheLethalCoder Apr 3 '17 at 8:54
  • \$\begingroup\$ You can save 6 bytes writing (t = new DateTime(2019, 3, 31) - DateTime.Now).Ticks > 0. \$\endgroup\$ – Søren D. Ptæus Apr 3 '17 at 12:14
  • \$\begingroup\$ @SørenD.Ptæus Good idea didn't even think of that one \$\endgroup\$ – TheLethalCoder Apr 3 '17 at 12:53
4
\$\begingroup\$

JavaScript ES5, 320 319 316 305 295 284 bytes

setInterval(function(){a=Math,b=a.floor,c=console,d=Date,e="00",f=new d(2019,2,31),g=a.abs(f-new d)/1e3,h=b(g/86400);g-=86400*h;var i=b(g/3600)%24;g-=3600*i;var j=b(g/60)%60;g-=60*j,c.clear(),c.log((e+h).slice(-3)+":"+(e+i).slice(-2)+":"+(e+j).slice(-2)+":"+(e+a.ceil(g)).slice(-2))})

Thanks to @Fels for referencing Math, @dgrcode for referencing console

Un-golfed

setInterval(function() {

  var math = Math, floor = math.floor, c = console, d = Date;

  var leadings = "00";

  // set our brexit date
  var brexit = new d(2019, 2, 31);

  // get total seconds between brexit and now
  var diff = math.abs(brexit - new d()) / 1000;

  // calculate (and subtract) whole days
  var days = floor(diff / 86400);
  diff -= days * 86400;

  // calculate (and subtract) whole hours
  var hours = floor(diff / 3600) % 24;
  diff -= hours * 3600;

  // calculate (and subtract) whole minutes
  var minutes = floor(diff / 60) % 60;
  diff -= minutes * 60;

  // what's left is seconds

  // clear the console (because OP said it must print in the same place)
  c.clear();

  // log the countdown, add the leadings and slice to get the correct leadings 0's
  c.log((leadings + days).slice(-3) + ":" + (leadings + hours).slice(-2) + ":" + (leadings + minutes).slice(-2) + ":" + (leadings + math.ceil(diff)).slice(-2));

});

\$\endgroup\$
  • 2
    \$\begingroup\$ You can save a bit my renaming Math like g=Math; \$\endgroup\$ – Fels Apr 3 '17 at 12:08
  • \$\begingroup\$ It looks like aliasing Math can still save 2 bytes, right? \$\endgroup\$ – Marie Apr 3 '17 at 16:06
  • \$\begingroup\$ You can save a bit more by using arrow functions and getting rid of var. Also, pick shorter names for variables, like h instead of hours, or m instead of minutes. Probably doing c=console will save a couple more bytes. Also 1e3 instead of 1000 \$\endgroup\$ – Daniel Reina Apr 3 '17 at 16:44
4
\$\begingroup\$

PHP, 84 bytes

for(;$c=DateTime;)echo(new$c('@1553990400'))->diff(new$c)->format("\r%a:%H:%I:%S ");

Fairly straightforward. 1553990400 is the timestamp for 31-3-2019 00:00:00 in UTC. It loops infinitely, using DateTime->diff()->format() to output how much time is left. After Brexit has happened, it will start counting up from 0.

Commented / more readable version:

// Infinite loop, assign DateTime (as a string) to $class
for (; $class = DateTime;) {
    echo (new $class('@1553990400')) // Create a new DateTime object for the brexit date/time.
            ->diff(new $class) // Caulculate the difference to the current date/time.
            ->format("\r%a:%H:%I:%S "); // Format it according to the specification, starting with a \r character to move to the start of the line and overwrite the previous output.
}
\$\endgroup\$
  • \$\begingroup\$ New here, and about to post my own answer. A few things: 1. Are we allowed to omit the <? tag here? 2. I think your parenthesis are wrong, right now you're calling ->diff on the echo rather than the DateTime object. 3. echo works without parenthesis anyway. 4. Even after fixing this, this doesn't work for me, but I'm new to golfing so that could just be me being an idiot. \$\endgroup\$ – Sworrub Wehttam Apr 4 '17 at 8:12
  • 1
    \$\begingroup\$ Just run it and see, it works fine, as per the requirements. There is no need to flush when running PHP from the command line. There's a \r at the beginning of the string to move the cursor to the start of the line, it keeps overwriting the previously outputted time. It's the same method that many other answers here are using. \$\endgroup\$ – chocochaos Apr 4 '17 at 9:17
  • 1
    \$\begingroup\$ Sorry, I missed your first comment. Yes, we are allowed to omit the opening tags, unless there is a requirement to supply a full program. The parenthesis are just fine the way they are. Yes, echo works without it, but calling diff on the DateTime object does not work without them. It runs fine here, what PHP version are you using and how are you running the program? :) \$\endgroup\$ – chocochaos Apr 4 '17 at 9:22
  • 1
    \$\begingroup\$ You might want to check out some posts here: codegolf.meta.stackexchange.com/questions/tagged/php \$\endgroup\$ – chocochaos Apr 4 '17 at 9:36
  • 1
    \$\begingroup\$ That just about covers it, thanks for the insight :) \$\endgroup\$ – Sworrub Wehttam Apr 4 '17 at 9:41
4
\$\begingroup\$

CJam, 69 62 59 57 bytes

Saved 7 bytes by converting to time format differently

Saved 3 bytes thanks to Martin Ender's suggestions

Saved 2 bytes by using a carriage return instead of backspaces

{15539904e5esm1e3/{60md\}2*24md\]W%{sYTe[}%':*CTe[oDco1}g

Can't be run on TIO for obvious reasons.

It rewrites the display constantly in an infinite loop so the text kind of flashes in and out (at least in my console), although it only actually updates the time once per second.

This 70-byte version only prints once per second:

{15539904e5es:Xm1e3/{60md\}2*24md\]W%{sYTe[}%':*CTe[oDco{esXm1e3<}g1}g

Explanation

{                           e# Begin a while loop
  15539904e5                e#  The timestamp on which Brexit will occur
  es                        e#  The current timestamp
  m                         e#  Subtract
  1e3/                      e#  Integer divide by 1000, converting to seconds from ms
  {                         e#  Run this block twice
   60md                     e#   Divmod by 60
   \                        e#   Swap top elements
  }2*                       e#  (end of block) 
                            e#    This block divmods the timestamp by 60, resulting in 
                            e#    the remaining minutes and seconds. Then the minutes get 
                            e#    divmod-ed by 60, to get hours and minutes remaining
  24md\                     e#  Divmod hours remaining by 24 and swap top elements, to get
                            e#    the hours left and days left.
  ]                         e#  Wrap the entire stack in an array
  W%                        e#  Reverse it since it's currently in the wrong order
  {                         e#  Apply this block to each element of the array
   s                        e#   Cast to string (array of digit characters)
   YTe[                     e#   Pad to length 2 by adding 0s to the left
  }%                        e#  (end of map block)
  ':*                       e#  Join with colons
  CTe[                      e#  Pad to length 12 by adding 0s to the left, dealing with the
                            e#    special case of the day being 3 digits. 
  o                         e#  Pop and print the resulting string, which is the time
  Dco                       e#  Print a carriage return, moving the cursor back to the start
  1                         e#  Push 1
}g                          e# Pop 1, if it's true, repeat (infinite loop)
\$\endgroup\$
  • \$\begingroup\$ Can't test right now, but you can probably replace Ab with s, and save a byte by doing 1e3/ first and then divide in the opposite order 60md\60md\24md\]W%. \$\endgroup\$ – Martin Ender Apr 3 '17 at 20:53
  • \$\begingroup\$ @MartinEnder Yep, they both work. Thanks \$\endgroup\$ – Business Cat Apr 3 '17 at 20:57
  • \$\begingroup\$ Oh and {60md\}2* saves another. \$\endgroup\$ – Martin Ender Apr 3 '17 at 20:58
3
\$\begingroup\$

Python 3.5 (118 Bytes)

import datetime as d,os
d=d.datetime
while 1:os.system("cls");e=str(d(2019,3,31)-d.today());print(e[:3]+':'+e[-15:-7])
\$\endgroup\$
3
\$\begingroup\$

C#6, 149 bytes

Thanks to Bob for saving 57 bytes!

using System;class P{static void Main(){DateTime a,x=new DateTime(2019,3,31);while((a=DateTime.Now)<x)Console.Write($"\r{x-a:ddd\\:hh\\:mm\\:ss}");}}

Ungolfed program:

using System;

class P
{
    static void Main()
    {
        DateTime a,
                x = new DateTime(2019, 3, 31);
        while ( (a = DateTime.Now) < x)
            Console.Write($"\r{x-a:ddd\\:hh\\:mm\\:ss}");
    }
}

C#, 210 206 159 bytes

Thanks to Bob for saving another 47 bytes!

Thanks to Martin Smith for saving 4 bytes!

using System;class P{static void Main(){DateTime a,x=new DateTime(2019,3,31);while((a=DateTime.Now)<x)Console.Write("\r"+(x-a).ToString(@"ddd\:hh\:mm\:ss"));}}

Ungolfed program:

using System;

class P
{
    static void Main()
    {
        DateTime a,
                x = new DateTime(2019, 3, 31);
        while ( (a = DateTime.Now) < x)
            Console.Write("\r" + (x - a).ToString(@"ddd\:hh\:mm\:ss"));
    }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ new DateTime(2019,3,31) is shorter. \$\endgroup\$ – Martin Smith Apr 3 '17 at 4:54
  • 1
    \$\begingroup\$ You can also remove the Console.Clear and instead prepend "\r" to the string, e.g. "\r"+(x-a)... \$\endgroup\$ – Bob Apr 3 '17 at 6:43
  • 1
    \$\begingroup\$ More improvements: (x-a).ToString(@"d\:hh\:mm\:ss") is equivalent to ` String.Format("\r{0:d\\:hh\\:mm\\:ss}",x-a)` is equivalent to $@"{x-a:d\:hh\:mm\:ss}" (shorter, interpolated string in C# 6.0). If you do that, you can then further shorten the full "\r"+$@"{x-a:d\:hh\:mm\:ss}" into $"\r{x-a:d\\:hh\\:mm\\:ss}". \$\endgroup\$ – Bob Apr 3 '17 at 6:49
  • 1
    \$\begingroup\$ @TheLethalCoder I took that as simply not allowing a "fake" multi-newline approach. A carriage return still overwrites the only thing on the screen. At least one other answer also uses this approach. Also can remove the sleep as it's only important that the display changes once per second, with non-changing updates allowed (see question comments). edit: actually, question comments also explicitly allow the CR... \$\endgroup\$ – Bob Apr 3 '17 at 8:12
  • 1
    \$\begingroup\$ @Bob Sorry I read your suggestion as a new line, my mistake. But yeah the sleep can be removed \$\endgroup\$ – TheLethalCoder Apr 3 '17 at 8:15
3
\$\begingroup\$

C, 104 bytes

main(x){for(;x=1553990400-time(0);)printf("\n%03d:%02d:%02d:%02d\e[1A",x/86400,x/3600%24,x/60%60,x%60);}

Breakdown

main(x){
    for(;x=1553990400-time(0);)             // Seconds remaining
        printf("\n%03d:%02d:%02d:%02d\e[1A",// Move cursor and print:
            x/86400,                        // Days
            x/3600%24,                      // Hours
            x/60%60,                        // Minutes
            x%60);                          // Seconds
    puts("Now we can stop talking about it forever."); // Wishful thinking
}

Relies on time returning number of seconds since 01/01/1970, which is the case for me (using Clang/GCC on macOS) and should be the case for most UNIX stuff.

Uses bash terminal escape sequences to move the cursor around (<esc>[1A moves the cursor up 1 line). It would be nicer to be able to simply use \r, but printf won't flush until it sees a newline, and flushing it manually takes a lot more.

Probably the most CPU intensive countdown I've ever seen. Runs in a hot loop to make sure it's always as accurate as can be. If run after the deadline, it will produce some pretty weird stuff (negatives everywhere!)

\$\endgroup\$
  • \$\begingroup\$ @TobySpeight sure, corrected. I think of them as bash because I always use this reference page: tldp.org/HOWTO/Bash-Prompt-HOWTO/x361.html \$\endgroup\$ – Dave Apr 3 '17 at 15:33
  • \$\begingroup\$ Are there any rules for the form of main in C? In C90: omitting return from main causes UB in case the caller (OS) will use the return value. In standard C: main(x) is not a valid form of main, implicit int has been removed from the language. I believe the minimal, safe version is int main(){}. \$\endgroup\$ – Lundin Apr 4 '17 at 12:45
  • \$\begingroup\$ @Lundin in code golf, languages are defined by their implementation (i.e. if you can find a publicly available compiler which compiles the code how you want, you can do it, but if it needs non-standard flags setting, those flags count towards your bytecount). You're correct that this is nowhere near standards compliant (as well as the things you've noticed, there's implicitly defined functions due to no imports and the reliance on time returning a number of seconds since 01/01/1970). Take a look at meta for the (rather disperse) rules people follow around here. \$\endgroup\$ – Dave Apr 4 '17 at 17:38
  • \$\begingroup\$ Part of the fun of code golf challenges is discovering bizarre language hacks and obsolete features! \$\endgroup\$ – Dave Apr 4 '17 at 17:40
3
\$\begingroup\$

AHK, 145 Bytes

This is not the shortest answer but the result gives a very nice feeling of doom, I think. I originally tried to send the keystrokes Ctrl+A followed by DEL and then whatever the time was but the refresh rate was too slow and it would destroy whatever environment you were in. Instead, then, I went with the GUI. It turned out to take less bytes to completely destroy the window and recreate it than it did to update the control over and over so I went with that. It's a nice effect.

Loop{
s=20190331000000
s-=A_Now,S
d:=t:=20000101000000
t+=s,S
d-=t,D
d*=-1
FormatTime f,%t%,:HH:mm:ss
GUI,Destroy
GUI,Add,Text,,%d%%f%
GUI,Show
}

I'm gonna sing the doom song!

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

C#, 128 127 Bytes

using System;class P{static void Main(){for(;;)Console.Write($"\r{new DateTime(2019,3,31)-DateTime.Now:ddd\\:hh\\:mm\\:ss}");}}

Ungolfed code:

using System;
class P
{
    static void Main()
    {
        for(;;)
            Console.Write($"\r{new DateTime(2019,3,31)-DateTime.Now:ddd\\:hh\\:mm\\:ss}"); 
    }
}

I would not have figured out the \r trick without help from the other C# answers here.

For anyone looking for further improvement, you can also put the Write() expression inside the for loop. Seems like I should be able to save a byte somehow here, because that saves me the semi-colon for that statement, but it works out to the same number because you can't have a fully empty body:

using System;class P{static void Main(){for(;;Console.Write($"\r{new DateTime(2019,3,31)-DateTime.Now:ddd\\:hh\\:mm\\:ss}"));}}
\$\endgroup\$
  • \$\begingroup\$ Welcome to PPCG! \$\endgroup\$ – Martin Ender Apr 3 '17 at 20:10
  • \$\begingroup\$ You can still save a single character by using an interpolated string ;) Console.Write($"\r{new DateTime(2019,3,31)-DateTime.Now:ddd\\:hh\\:mm\\:ss}"); \$\endgroup\$ – Bob Apr 4 '17 at 0:11
  • \$\begingroup\$ Well played, I tried to find a way to have a while (true) loop in the shortest possible code! I'll remember that trick. You may need to add a couple of spaces like I did though to your write otherwise when the days goes from 3 digits to 2 digits, it won't overwrite the last character of your time string and you'll get a weird output \$\endgroup\$ – NibblyPig Apr 4 '17 at 8:00
  • \$\begingroup\$ You can save a byte by using an interpolated string like in my answer. Your format of dddpads the zeroes, looks better than the two spaces method nice. \$\endgroup\$ – TheLethalCoder Apr 4 '17 at 8:25
  • \$\begingroup\$ Updated for the interpolated string. \$\endgroup\$ – Joel Coehoorn Apr 4 '17 at 18:59
3
\$\begingroup\$

Ruby (83 bytes)

loop{h=431664-Time.now.to_r/3600;$><<['%02d']*4*?:%[h/24,h%24,h%1*60,h*3600%60]+?\r}

Ungolfed

loop do
  seconds = 1553990400 - Time.now.to_r

  print (["%02d"] * 4).join(':') % [
    seconds / 24 / 60 / 60     ,
    seconds      / 60 / 60 % 24,
    seconds           / 60 % 60,
    seconds                % 60,
  ] + "\r"
end

Basically one of the Python submissions, with some improvements. We just emit an "\r" to go beginning of the string before re-rendering. And for the string format of "%03d:%02d:%02d:%02d", we really don't care about the width on the first specifier… so we can just do "%02d"*4, and emit a backspace and a space to clear the extra unnecessary colon.

Also, I found a two-character shorter print: $><<. $> is a shorthand global for $defout, which is the output stream for print and printf and defaults to STDOUT. IO#<< writes the right hand side of it to the stream. How is that two characters shorter? Well, I can now omit the space that led before the parenthesis wrapping the format string.

At this point I genuinely think there is no possible way to shorten this program further in Ruby.

Edit: I was wrong. Instead of the first Time.new(2019,3,31), we can just use the raw UNIX time: 1553990400.

Edit 2: I've tried playing around with factoring out minutes, and dividing the UNIX timestamp by that constant, but it doesn't actually wind up saving any bytes. :(

Edit 3: Turns out caching h=3600 actually hurt me by two bytes. Whoops.

Edit 4: Saved 3 bytes thanks to @EricDuminill. He used floats, but rationals work without loss of precision!

Edit 5: Array#* as an alias for Array#join, with the Ruby ?-syntax for individual characters!

\$\endgroup\$
  • \$\begingroup\$ Working with hours instead of seconds seems to save 3 bytes : loop{h=431664-Time.now.to_f/3600;$><<('%02d:'*4+"\b \r")%[h/24,h%24,h%1*60,3600*h%60]} Seconds might be off by 1 though, due to rounding. \$\endgroup\$ – Eric Duminil Apr 4 '17 at 12:50
  • \$\begingroup\$ Thanks! Tied with PHP now. :) I used to_r instead of to_f to preserve precision. \$\endgroup\$ – Stephen Touset Apr 4 '17 at 17:34
  • \$\begingroup\$ You're welcome. This clock might still be 1s early though, even with .to_r instead of .to_f \$\endgroup\$ – Eric Duminil Apr 4 '17 at 17:44
  • \$\begingroup\$ @StephenTouset You can move +"\r" to the right of the array. This enables you to use ['%02d']*4*?: instead of '%02d:'*4+"\b " so you can lose the parentheses, which nets you one byte. Save yet another byte by writing +?\r instead of +"\r". \$\endgroup\$ – Synoli Apr 4 '17 at 21:29
  • \$\begingroup\$ Excellent discovery! \$\endgroup\$ – Stephen Touset Apr 4 '17 at 21:41
2
\$\begingroup\$

JavaScript+HTML, 136+7=143 bytes

setInterval("d=1553990400-new Date/1e3|0;w.innerText=[60,60,24,999].map(z=>(q='00'+d%z,d=d/z|0,q.slice(z<61?-2:-3))).reverse().join`:`")
<a id=w
\$\endgroup\$
2
\$\begingroup\$

C#, 142 bytes

using System;class P{static void Main(){a:Console.Write($"\r{(new DateTime(2019,3,31)-DateTime.Now).ToString("d\\:h\\:mm\\:ss  ")}");goto a;}}

Ungolfed program:

using System;
class P
{
    static void Main()
    {
        a: Console.Write($"\r{(new DateTime(2019, 3, 31) - DateTime.Now).ToString(@"d\:h\:mm\:ss  ")}"); goto a;
    }
}
\$\endgroup\$
  • \$\begingroup\$ This won't stop printing when it hits brexit, not sure if that's a problem \$\endgroup\$ – TheLethalCoder Apr 3 '17 at 15:10
  • \$\begingroup\$ @TheLethalCoder That's legal. The instructions specifically state the code only has to work until 31/3/2019, and what happens after that doesn't matter. If you can save bytes by having weird output or even exceptions after that date, then more power to you. \$\endgroup\$ – Joel Coehoorn Apr 3 '17 at 16:46
  • \$\begingroup\$ Also: I suspect it will be possible to get this even shorting by skipping the ToString() bytes and instead build the formatting into the Write() method, or maybe an interpolated string \$\endgroup\$ – Joel Coehoorn Apr 3 '17 at 16:48
  • \$\begingroup\$ Okay... it's definitely possible. I have it down to 127 bytes. I'm appending it below your original, so you still get credit for the basic goto idea. \$\endgroup\$ – Joel Coehoorn Apr 3 '17 at 17:10
  • \$\begingroup\$ My edit go wiped :( Guess I'll have to post my own answer. \$\endgroup\$ – Joel Coehoorn Apr 3 '17 at 20:01
2
\$\begingroup\$

Bash + GNU date, 128 bytes

2 bytes shaved off thanks to @muru, and 2 off earlier thanks to @This Guy.

C=:%02d;while sleep 1;do D=$[B=3600,A=24*B,1553990400-`date +%s`];printf "%03d$C$C$C\r" $[D/A] $[D%A/B] $[D%A%B/60] $[D%60];done

Ungolfed

DAY=86400
HOUR=3600
while sleep 1 ; do
 DIFF=$[1553990400-`date +%s`]
 printf "%03d:%02d:%02d:%02d\r" \
         $[DIFF/DAY] \
         $[DIFF%DAY/HOUR] \
         $[DIFF%DAY%HOUR/60] \
         $[DIFF%60]
done
\$\endgroup\$
  • 1
    \$\begingroup\$ Never golfed in Bash before but can you remove the spaces at the while: while[1]? \$\endgroup\$ – caird coinheringaahing Apr 2 '17 at 19:45
  • \$\begingroup\$ Fair point, have now given that a try but it yields line 1: [1]: command not found error. Spaces are mandatory it seems :-( \$\endgroup\$ – steve Apr 2 '17 at 21:15
  • 2
    \$\begingroup\$ Assign 3600 to a variable to save 2 bytes? You might also be able to change B=3600;A=86400 to B=3600;A=24*B for another byte? \$\endgroup\$ – caird coinheringaahing Apr 2 '17 at 22:03
  • \$\begingroup\$ 3600 variable now done, thx. 24*B would need A=$[24*B] so not possible there though \$\endgroup\$ – steve Apr 2 '17 at 22:09
  • 1
    \$\begingroup\$ C=:%02d;printf "%03d$C$C$C\r" to save a byte? And move the assignments to A and B in the arithmetic context: D=$[B=3600,A=24*B,1553990400-`date +%s`] to save another? \$\endgroup\$ – muru Apr 3 '17 at 10:47
2
\$\begingroup\$

MATL, 45 bytes

737515`tZ'-tkwy-':HH:MM:SS'XOw'%03d'YDwYcDXxT

TIO apparently doesn't support clearing the output, but thankfully MATL Online does!

At 2 bytes more, a bit more CPU-friendly version that does a pause (sleep) every second:

737515`tZ'-tkwy-':HH:MM:SS'XOw'%03d'YDwYcDT&XxT

Try this on MATL Online

737515 is "31st of March 2019" represented MATLAB's default epoch format - number of days from January 0, 0000, optionally including a fractional part to represent the time of day. (I tried to shorten this by calculating it somehow, but its only factors are 5 and another six digit number (147503), and I couldn't figure out a way to do it in less than 6 bytes.)

`    % start do-while loop
tZ`- % duplicate Brexit date, get current date (& time), subtract
tk   % duplicate the difference, get the floor of it (this gives number of days left)
w    % switch stack to bring unfloored difference to top
y    % duplicate the floored value on top of that
-    % subtract to get fractional part representing time
':HH:MM:SS'XO % get a datestr (date string) formatted this way
w    % switch to bring number of days back on top
'%03d'YD      % format that to take 3 places, with 0 padding if needed
wYc  % switch to bring time string back on top, concatenate date and time
D    % display the concatenated result!
T&Xx % clear screen after a 1 second pause (the pause is optional, without it the call is `Xx`)
T    % push True on stack to continue loop
\$\endgroup\$
1
\$\begingroup\$

PHP, 64 bytes

while($d=1553990401-time())echo--$d/86400|0,date(":H:i:s\r",$d);

This will count exactly until 0:00:00:00 and then break/exit. Run with -r.

-2 bytes if I wouldn´t have to print the 0.

\$\endgroup\$
1
\$\begingroup\$

RPL, 83 78 bytes

Assuming your HP48, or similar, is setup with correct (UK) time and date, mm/dd date format, and 24h time format:

WHILE 1REPEAT DATE 3.302019DDAYS":"1.1 24TIME HMS- TSTR 15 23SUB + + 1DISP END

I was surprised to be able to save 2 bytes by removing spaces around ":". 1.1 is the shortest valid date, later dumped by SUB. Be careful with emulators, the time may run faster or slower (or not at all) than your wall clock. With a real HP, you can stop this program by pressing the ON key … or wait for empty batteries.

\$\endgroup\$
0
\$\begingroup\$

PHP, 102 95 90 bytes

Saved 7 bytes thanks to @TheLethalCoder & by not factoring

Saved another 5 bytes by concatenating

<? $b=1553990400-time();echo floor($b/$d=86400).date(':H:i:s', $b%$d);header('Refresh:1');

This is my first golf, so I'm probably missing quite a few tricks, but here you are regardless.

As for @chocochaos' PHP answer that would otherwise trump this, I believe it is flawed for reasons I have explained in my comments, but as I'm new here I might be wrong. Or I'm just a newbie :)

\$\endgroup\$
  • \$\begingroup\$ You may need a closing tag? (Not sure on that). You only use $a once so might as well use the number in place. I'm not too familiar with php but looks like there could be more improvements \$\endgroup\$ – TheLethalCoder Apr 4 '17 at 8:28
  • \$\begingroup\$ What do you mean by flawed because of reasons stated in the comments? If you mean the comments on their answer, you're the only one who's commented. \$\endgroup\$ – caird coinheringaahing Apr 4 '17 at 8:32
  • \$\begingroup\$ @TheLethalCoder No closing tag needed. And nice one! \$\endgroup\$ – Sworrub Wehttam Apr 4 '17 at 8:37
  • 1
    \$\begingroup\$ You can save ~7 bytes by using a <?= opening tag and dropping the echo, assigning $b in the place you first use it. Additionally you can save 3 bytes using ^0 instead of floor. It's bitwise or and involves a cast to int, it's the shortest way to cast to int I've seen. \$\endgroup\$ – user59178 Apr 4 '17 at 8:58
  • 1
    \$\begingroup\$ My answer runs just fine :) Also, you might want to read up on some posts here: codegolf.meta.stackexchange.com/questions/tagged/php There's no need for opening tags either. I would really recommend to write your solution in such a way that it would run from the command line, then you would not have to mess around with headers to refresh. That refresh will also cause your solution to "miss" a second once in a while, because it does not take into account the time lost on the request itself. \$\endgroup\$ – chocochaos Apr 4 '17 at 9:41
0
\$\begingroup\$

AWK, 78 bytes

BEGIN{for(;v=1552953600-systime();printf"\r%d:%s",v/86400,strftime("%T",v)){}}

Try it online!

Was longer before I realized I could precalculate the end time. Sometimes it pays to be a bit late to the game and get ideas from others.

FYI, the TIO link doesn't work very well, since it doesn't implement \r properly.

\$\endgroup\$
0
\$\begingroup\$

F#, 142 bytes

open System
let f=
 let t=DateTime(2019,3,31)
 while DateTime.Now<=t do Console.Clear();t-DateTime.Now|>printf"%O";Threading.Thread.Sleep 1000

I grew up in Ireland about half a kilometre from the border. Apart from a "Welcome to Fermanagh" sign and the road markings changing you wouldn't know you'd entered another country. Used to cross it twice on the way to school.

\$\endgroup\$
0
\$\begingroup\$

c, gcc 114 bytes

main(s){system("clear");if(s=1553900399-time(0)){printf("%d:%d:%d:%d\n",s/86400,s/3600%24,s/60%60,s%60);main(s);}}

Nothing omitted, full program. The program compiles in gcc on Ubuntu. The countdown will not show a long trail of print statements because of the system call to clear and halts when the countdown reaches 0 seconds.

UnGolfed

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>


//Brexit countdown timer
int main(){
  int sec = 1553900400 - time(0);//seconds remaining until Brexit
  if(sec){
    sleep(1);
    system("clear");
    printf("Brexit Countdown\n");
    printf("days Hours Mins Secs\n");
    printf("%d:  %d:    %d:  %d\n",
            sec/86400, sec/3600%24,
            sec/60%60, sec%60);
    main();
  }
}
\$\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.