I made a simple countdown timer to count to a fixed point in time. I’m using a datetime stored in a data table and it counts from now. Both are timezone aware and use UTC. Shows countdown in format “X Days HH:MM:SS”. The “s” in the server call ensures there is no spinner every second.
Client code:
def __init__(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)
# Any code you write here will run when the form opens.
self.ending_countdown.text = anvil.server.call('get_countdown', self.end_date.text)
def timer_1_tick(self, **event_args):
"""This method is called Every [interval] seconds. Does not trigger if [interval] is 0."""
self.ending_countdown.text = anvil.server.call_s('get_countdown', self.end_date.text)
Note: A timer has to be added to the form. I set the tick to be 1 second.
Server code:
from datetime import datetime as dt #the datetime people really should fix this namespace
from datetime import timedelta, timezone
@anvil.server.callable
def get_countdown(end_time):
total_seconds = abs(dt.now(timezone.utc) - end_time).total_seconds()
#calculate days, hours, minutes, and seconds remaining
days = total_seconds // (3600 * 24)
hours = (total_seconds // 3600) % 24
minutes = (total_seconds // 60) % 60
seconds = total_seconds % 60
countdown = '{} хоног, {:02d}:{:02d}:{:02d}'.format(int(days), int(hours), int(minutes), int(seconds))
return countdown
Seems like a lot of server calls. does it need to be on the server?
here’s the approach for timezone aware on the client:
Client code:
from datetime import datetime, timedelta
from anvil import tz
def __init__(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)
# Any code you write here will run when the form opens.
self.timer_1_tick()
def timer_1_tick(self, **event_args):
"""This method is called Every [interval] seconds. Does not trigger if [interval] is 0."""
self.ending_countdown.text = get_countdown(self.end_date.text)
def get_countdown(end_time):
local = tz.tzlocal()
total_seconds = abs(datetime.now(local) - end_time).total_seconds()
#calculate days, hours, minutes, and seconds remaining
days = total_seconds // (3600 * 24)
hours = (total_seconds // 3600) % 24
minutes = (total_seconds // 60) % 60
seconds = total_seconds % 60
countdown = '{} хоног, {:02d}:{:02d}:{:02d}'.format(int(days), int(hours), int(minutes), int(seconds))
return countdown
edit: some work with timezones recently changed my approach
TypeError: can't subtract offset-naive and offset-aware datetimes
What I will need to do is convert the data table time to a string then back to a datetime that isn’t timezone aware. That’s the only way I figured out how to do it client side. Let me see if I can do it…