4

I want to code simple digital clock in the python shell. I want to avoid using tkinter if possible. This is what I currently have;

import time
while True:
    from datetime import datetime
    now = datetime.now()  
    print ("%s/%s/%s %s:%s:%s" % (now.month,now.day,now.year,now.hour,now.minute,now.second)) 
    time.sleep(1)

This produces a recurring print out, something like this;

06/29/16 23:08:32

06/29/16 23:08:33

06/29/16 23:08:34

I know this is crude, I'm still learning. I just want one line with a "ticking" digital clock in the shell. I'm using python 3.5.1 on idle and windows 10.

If this isn't possible, I'd very much like to know why.

Kindest thanks

slugonamission
  • 9,562
  • 1
  • 34
  • 41
DanMcGrew
  • 45
  • 1
  • 1
  • 4
  • Possible duplicate of [Replace console output in python](http://stackoverflow.com/questions/6169217/replace-console-output-in-python) – Михаил Павлов May 29 '16 at 22:38
  • I don't think you are going to have much luck with this in idle, I would recommend you completely forget about idle and use ipython or one of the many good python IDEs' like pycharm etc.. – Padraic Cunningham May 29 '16 at 22:56

7 Answers7

10

If you're just printing out a fixed length output like this each time, you can use the carriage return character to rewind to the start of the line, as long as you don't print a newline. Example:

# Note trailing comma, that suppresses the newline in Python
print ("%s/%s/%s %s:%s:%s" % (now.month,now.day,now.year,now.hour,now.minute,now.second)),

# Now rewind back to the start of the line. Again, not trailing comma
print("\r"),

Now, you may also notice that nothing is ever printed to the screen. This is because standard out is buffered, so you can flush with this:

# At the top...
import sys

# In the loop, after the first print
sys.stdout.flush()

This all works as follows. Imagine that there is actually a cursor on screen. You first print out the time with the first print (and the flush), then you move the cursor back to the start of the line with print("\r"),. This doesn't actually remove any of the characters, it just moves the cursor. You then write the next time out again. Because it nicely happens to be the exact same length, the time gets written out again, replacing the old characters.

The resulting script is then as follows:

import time
import sys

while True:
    from datetime import datetime
    now = datetime.now()
    print ("%s/%s/%s %s:%s:%s" % (now.month,now.day,now.year,now.hour,now.minute,now.second)),
    sys.stdout.flush()
    print("\r"),
    time.sleep(1)

If you want finer grained control over what's going on, you can start using the curses library, but I imagine that's overkill for what you're trying to do here.

EDIT: As @PadraicCunningham mentioned in the comments, the correct syntax to suppress newline printing in Python 3 and force the contents to flush to the screen is the following:

print("hello", flush=True, end="")

Also, as @AlexHall mentions, the print statement does not actually print a fixed width statement; so to do this, we should use strftime() instead.

Therefore the correct program is:

import time

while True:
    from datetime import strftime
    print (strftime("%m/%d/%Y %H:%M:%S"), end="", flush=True)
    print("\r", end="", flush=True)
    time.sleep(1)
Damodar Dahal
  • 559
  • 4
  • 16
slugonamission
  • 9,562
  • 1
  • 34
  • 41
  • 1
    You could set `flush=True` in the print function but I don't think whatever you do is going to work in idle – Padraic Cunningham May 29 '16 at 22:54
  • @PadraicCunningham: thanks, I didn't realise that was an option. I'm not sure about IDLE myself, and sadly don't have it lying around to test. It _does_ work in the Python REPL though. – slugonamission May 29 '16 at 22:55
  • @PadraicCunningham - just realised OS X does actually ship with IDLE. It sadly doesn't work, and given [this answer](http://stackoverflow.com/questions/19187759/implementing-a-backspace-in-python-3-3-2-shell-using-idle), I don't think there is a way to get it to work. Still, to the OP, this method works if you're running from the command prompt. – slugonamission May 29 '16 at 23:01
  • 1
    No worries, the OP is using python3.5 so you would also set `end=""` to remove newlines, from memory I didn't think this worked in idle, I think installing idlex may do the trick http://idlex.sourceforge.net/ – Padraic Cunningham May 29 '16 at 23:01
  • 1
    Whoops, I'm still used to Python 2. Updated though, cheers :) – slugonamission May 29 '16 at 23:03
  • Use `strftime` instead of this manual formatting (which doesn't work for double digits btw). I need neither `flush=True` nor `sys.stdout.flush()` when I test this in the terminal with `python3`, and you've included both at the end. You said Python 2 in your edit but I think you meant 3. Move the datetime import to the top. – Alex Hall May 29 '16 at 23:09
  • 1
    @AlexHall, whoops, removed `.flush()`. As for requiring `flush=True`, that completely depends on your platform. Linux and OS X's libc typically buffers output, and only flushes to the screen on a newline; I'm not 100% sure on Windows' behaviour. – slugonamission May 29 '16 at 23:15
  • I'm using OSX. But yes, I understand it might vary. Just pointing it out. – Alex Hall May 29 '16 at 23:19
3

All you need is:

from time import strftime
while True:
    print (strftime("%m/%d/%Y %H:%M:%S"), end="", flush=True)
    print("\r", end="", flush=True)
    time.sleep(1)
Mohammad Kanan
  • 4,452
  • 10
  • 23
  • 47
Greg
  • 31
  • 4
2

tried this in repl.it, this worked for me...( added commas & now.strftime )

import time
from datetime import datetime
while True:   
    now = datetime.now()
    print (now.strftime("%m/%d/%Y %H:%M:%S"), end="", flush=True),
    print("\r", end="", flush=True),
    time.sleep(1)

Greenman
  • 29
  • 1
  • 4
0

The following code is working for me.

from time import sleep
from datetime import datetime
while True:
    now = datetime.now()
    stdout.write(now.strftime("\r%m/%d/%Y %H:%M:%S")),
    stdout.flush()
    sleep(1)
stdout.write("\n")
0

You could set end= " " to remove newlines and add a carriage return i.e.:

'\r'

Therefore the correct program which should work for you is:

from datetime import datetime
import time    

 while True:
    now = datetime.now()
    print("\r%s/%s/%s %s:%s:%s" % (now.month, now.day, now.year, now.hour, now.minute, now.second), end='')
    time.sleep(1)
 print('')
Peyman Mohamadpour
  • 17,954
  • 24
  • 89
  • 100
0

A slight improvement on the above answers (removing the trailing comma; and changing end from "" to "\r" to do the carriage return as part of a single print statement.

import time
from datetime import datetime
while True:   
    now = datetime.now()
    print (now.strftime("%m/%d/%Y %H:%M:%S"), end="\r", flush=True)
    time.sleep(1)
MaxW
  • 3
  • 2
0

ImportError: cannot import name 'strftime' from 'datetime' (/usr/lib/python3.7/datetime.py) So, use the following code:

import time, sys

while True:
    from datetime import datetime
    now = datetime.now()
    showClock =" %s:%s:%s" % (now.hour,now.minute,now.second)
    print(showClock, end="\r")
info-farmer
  • 255
  • 3
  • 18