Elegant date and time picker?

When it is necessary to select a date and time (to, say, minute accuracy), there are several options:

  1. Use a DatePicker in combination with two (integer) Spinners for hour and minute
    • -> but I cannot force the format of the Spinners to produce leading zeros, can I?
  2. Use DatetimeInput
    • -> works, but not particularly fancy
  3. Use a DatePicker together with an IntSlider in minutes, that formats the int as “%H:%M”.
    • -> but then I have to write my own bokeh TickFormatter - how?
  4. There is no such thing as a DatetimeSlider with configurable time step, is there?

I’m wondering if people already came up with an elegant solution to this one? Or are you all content to use DatetimeInput?

1 Like

Hi @marfel

I understand you use case. But I have not seen that functionality anywhere.

I needed a nice datepicker too. In the old version I use a datepicker with two int slider, but it was not nice

image

Trying to improve the datetime picker, I found this library

You can see that this js library is really simple to use, you define the button and you have an on_submit method. The example only uses the simplepicker.js and simplepicker.css of the dist folder.

Below there is an screenshot and the code. The files are served with the static-dirs option of panel serve.

panel serve --show clock.py --autoreload --static-dirs assets=./simplepicker-master

#clock.py
from datetime import date, datetime
from bokeh.models.widgets import Div

import panel as pn
pn.config.sizing_mode = 'stretch_width'
pn.config.js_files = {'sp':"./assets/dist/simplepicker.js"}


jpg = pn.pane.Markdown( '# ' + str(datetime.now())[10:19], 
            margin=(-1,0,15,0),  height=25, width=75,
            style={'color': "white", 'font-family': 'sans-serif'}) 

clock = pn.Row(pn.Spacer(), jpg)


html = """
<link rel="stylesheet" href="./assets/dist/simplepicker.css">

<style>
    .simplepicker-btn{ 
        border-radius: 15px;
      }
</style>

<button class="simplepicker-btn">Select Date:</button>

<script>
    let simplepicker = new SimplePicker({zIndex: 10});

    const $button = document.querySelector('button');

    $button.addEventListener('click', (e) => {
        simplepicker.open();
      });

    simplepicker.on('submit', (date, readableDate) => {
        console.log(date, readableDate  );
        Bokeh.documents[0].get_model_by_name('div_date').text = String(readableDate) ; 
      });

    simplepicker.on('close', (date) => {
        console.log('Picker Closed');
      });
</script>
"""

dt_input = pn.widgets.DatetimeInput(name='Datetime Input', value=datetime(2019, 2, 8))

dt_pckr_strt = Div(text="", visible= True, name='div_date')

MONTHS = ['January','February','March','April','May','June',
'July','August','September','October','November','December']

def callback(attr,old,new):
    month = int(MONTHS.index(new.split(' ')[1])+1)
    day = int(new.split(' ')[0])
    year = int(new.split(' ')[2])
    if new.split(' ')[4]=='PM': 
        hour = int(new.split(' ')[3].split(':')[0])+12
        if hour==24: hour = 12
    else:
        hour = int(new.split(' ')[3].split(':')[0])
        if hour==12: hour = 0
    minute = int(new.split(' ')[3].split(':')[1])
    print ('datetime:', datetime(year,month,day,hour,minute,0) )
    dt_input.value = datetime(year,month,day,hour,minute,0)


dt_pckr_strt.on_change('text',callback)


tmpl = pn.template.VanillaTemplate(title='Hola')
tmpl.header.append(clock)

tmpl.sidebar.append(pn.Row(pn.pane.HTML(html),
                            dt_pckr_strt
                        )
                    )
tmpl.sidebar.append(dt_input)

def update():
    jpg.object = '# ' + str(datetime.now())[10:19]

pcbk = pn.state.add_periodic_callback(update, period=1000)

tmpl.servable()
3 Likes