Create a clock/timer with streamlit tools

  1. Are you running your app locally or is it deployed?

locally

  1. Share the link to your app’s public GitHub repository (including a requirements file).

there is none (yet)

  1. Share the full text of the error message (not a screenshot).

no error message

  1. Share the Streamlit and Python versions.

streamlit 1.29.0, python 3.9.2

I want to create a time tracking app where it would be convenient to have a clock running. Two solutions were discussed so far: using pure JS or an async background-task. See How to make a timer? - #5 by sebastiandres and How to make a timer? - #6 by andfanilo

However, there are problems with both:

  • The JS solution has no access to high-level widgets, such as the metric
  • The async task is continously running, which is apparent from the “running” symbol in the upper right corner. Furthermore, it gets a bit messy when more than one such task is required.

My current solution uses such tasks though:

import asyncio        
import streamlit as st     
import time
from functools import partial
from datetime import datetime

def clock(field, name, starttime):
    """Print a time in a field"""
    tdelta =  datetime.now().replace(microsecond=0) - starttime.replace(microsecond=0)
    minutes, seconds = divmod(int(tdelta.total_seconds()), 60)      
    hours, minutes = divmod(minutes, 60)                                                                       
    field.metric(name, f"{hours}:{minutes:02d}:{seconds:02d}")

async def run_jobs(job_list):
    while True:
        for job in job_list:
            job()
        # Not sure why asyncio.sleep was used here...
        time.sleep(0.1)

col1, col2 = st.columns(2)
# Placeholder Fields for Timers
with col1:
    all_tasks = st.empty()
with col2:
    ph = st.empty()

jobs = []

# Jobs are queued for the fields
jobs.append(partial(clock, all_tasks, "foo", datetime(2023, 12, 28, 14)))
jobs.append(partial(clock, ph, "baz", datetime(2023, 12, 28, 16)))

if jobs:
    # not sure why asyncio is actually needed - a normal function works as well.
    asyncio.run(run_jobs(jobs))

I wonder now, if there are any new tools that can handle this a bit more elegantly and in the browser’s context, such that no running script is shown?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.