The DateEntry widget from the tkcalendar library adds a drop-down date picker to a Tkinter application.
Users can type a date or select one from the calendar. Python can then read the selected date as a datetime.date object, change the selected date, format it, calculate date differences or use it in database queries.
DateEntry is provided by the external tkcalendar package.
Install it from the command prompt or terminal:
pip install tkcalendar
You can also use:
python -m pip install tkcalendar
Import DateEntry from tkcalendar and add it to the Tkinter window.
import tkinter as tk
from tkcalendar import DateEntry
my_w=tk.Tk()
my_w.geometry(
"340x220"
)
my_w.title(
"plus2net.com"
)
cal=DateEntry(
my_w,
selectmode='day'
)
cal.grid(
row=0,
column=0,
padx=20,
pady=30
)
my_w.mainloop()
If no year, month or day is specified, DateEntry initially displays the current date.
A specific starting date can be supplied using year, month and day.
cal=DateEntry(
my_w,
selectmode='day',
year=2026,
month=9,
day=5
)
Another option is to create the widget first and then use set_date(), which we cover below.
The get_date() method returns the selected value as a datetime.date object.
This is usually the best method when the selected date will be used in Python date calculations.
import tkinter as tk
from tkcalendar import DateEntry
my_w=tk.Tk()
my_w.geometry(
"400x200"
)
cal=DateEntry(
my_w,
selectmode='day'
)
cal.grid(
row=0,
column=0,
padx=20,
pady=30
)
l1=tk.Label(
my_w,
text='Select a date',
bg='yellow'
)
l1.grid(
row=0,
column=2,
padx=10
)
def my_upd():
selected_date=cal.get_date()
l1.config(
text=str(selected_date)
)
b1=tk.Button(
my_w,
text='Read Date',
command=my_upd
)
b1.grid(
row=0,
column=1
)
my_w.mainloop()
Because DateEntry inherits from ttk.Entry, it also provides the normal Entry get() method.
get() returns the text currently displayed in the DateEntry field.
date_text=cal.get()
print(date_text)
get_date() returns a datetime.date object.
selected_date=cal.get_date()
print(selected_date)
DateEntry generates the virtual event:
<<DateEntrySelected>>
when the user selects a date from the drop-down calendar.
We can bind this event directly to a function.
import tkinter as tk
from tkcalendar import DateEntry
my_w=tk.Tk()
my_w.geometry(
"400x200"
)
cal=DateEntry(
my_w,
selectmode='day'
)
cal.grid(
row=0,
column=0,
padx=20,
pady=30
)
l1=tk.Label(
my_w,
bg='yellow',
width=15
)
l1.grid(
row=0,
column=1
)
def my_upd(event):
l1.config(
text=str(
cal.get_date()
)
)
cal.bind(
'<<DateEntrySelected>>',
my_upd
)
my_w.mainloop()
A DateEntry can also use a
Tkinter StringVar
through its textvariable option.
import tkinter as tk
from tkcalendar import DateEntry
my_w=tk.Tk()
my_w.geometry(
"400x200"
)
sel=tk.StringVar(my_w)
cal=DateEntry(
my_w,
selectmode='day',
textvariable=sel
)
cal.grid(
row=0,
column=0,
padx=20,
pady=30
)
l1=tk.Label(
my_w,
bg='yellow',
width=15
)
l1.grid(
row=0,
column=1
)
def my_upd(*args):
l1.config(
text=sel.get()
)
sel.trace_add(
'write',
my_upd
)
my_w.mainloop()
The StringVar changes when the DateEntry text changes, so its write trace can run another function.
If you only need to react when the user chooses a date from the calendar, <<DateEntrySelected>> is usually clearer.
Use set_date() to change the selected date from Python code.
import tkinter as tk
from tkcalendar import DateEntry
from datetime import date
my_w=tk.Tk()
my_w.geometry(
"380x220"
)
cal=DateEntry(
my_w,
selectmode='day'
)
cal.grid(
row=0,
column=0,
padx=20,
pady=30
)
selected_date=date(
2026,
9,
5
)
cal.set_date(
selected_date
)
my_w.mainloop()
from datetime import date
cal.set_date(
date.today()
)
Using a date object avoids ambiguity caused by locale-specific date strings.
There are two different formatting requirements to consider:
cal=DateEntry(
my_w,
selectmode='day',
date_pattern='MM-dd-yyyy'
)
The date_pattern option controls how the date is displayed inside DateEntry.
Because get_date() returns a datetime.date, we can use
strftime().
dt=cal.get_date()
formatted_date=dt.strftime(
"%d-%B-%Y"
)
print(
formatted_date
)
Other common formats are:
dt.strftime(
"%d-%m-%Y"
)
dt.strftime(
"%m/%d/%Y"
)
dt.strftime(
"%Y-%m-%d"
)
The %Y-%m-%d format is commonly useful when preparing dates for database operations.
DateEntry supports mindate and maxdate to restrict the dates that can be selected.
For example, allow dates from today through the next 30 days.
import tkinter as tk
from tkcalendar import DateEntry
from datetime import date, timedelta
my_w=tk.Tk()
today=date.today()
last_date=(
today
+
timedelta(
days=30
)
)
cal=DateEntry(
my_w,
mindate=today,
maxdate=last_date,
date_pattern='yyyy-mm-dd'
)
cal.grid(
row=0,
column=0,
padx=20,
pady=30
)
my_w.mainloop()
For more examples, see:
DateEntry mindate and maxdateBecause DateEntry inherits Entry behavior, its current text can be deleted:
cal.delete(
0,
'end'
)
For example:
import tkinter as tk
from tkcalendar import DateEntry
my_w=tk.Tk()
my_w.geometry(
"380x220"
)
cal=DateEntry(
my_w
)
cal.grid(
row=0,
column=0,
padx=15,
pady=30
)
b1=tk.Button(
my_w,
text='Clear',
command=lambda:
cal.delete(
0,
'end'
)
)
b1.grid(
row=0,
column=1
)
my_w.mainloop()
delete().
Two datetime.date objects can be subtracted directly.
The resulting timedelta object contains the difference in days.
import tkinter as tk
from tkcalendar import DateEntry
my_w=tk.Tk()
my_w.geometry(
"450x250"
)
cal1=DateEntry(
my_w,
date_pattern='yyyy-mm-dd'
)
cal1.grid(
row=1,
column=0,
padx=10,
pady=20
)
cal2=DateEntry(
my_w,
date_pattern='yyyy-mm-dd'
)
cal2.grid(
row=1,
column=1,
padx=10
)
l1=tk.Label(
my_w,
text='Select two dates',
bg='yellow',
font=('Arial', 18)
)
l1.grid(
row=0,
column=0,
columnspan=3,
padx=10,
pady=20
)
def my_upd():
diff_days=(
cal2.get_date()
-
cal1.get_date()
).days
l1.config(
text=f'{diff_days} days'
)
b1=tk.Button(
my_w,
text='Difference',
command=my_upd
)
b1.grid(
row=1,
column=2
)
my_w.mainloop()
For an age expressed in years, months and days, we can combine DateEntry with
relativedelta().
There is no need to convert the displayed DateEntry text back to a date string. We can read the selected date directly using get_date().
import tkinter as tk
from tkcalendar import DateEntry
from datetime import date
from dateutil.relativedelta import relativedelta
my_w=tk.Tk()
my_w.geometry(
"430x220"
)
cal=DateEntry(
my_w,
date_pattern='yyyy-mm-dd',
maxdate=date.today()
)
cal.grid(
row=0,
column=0,
padx=20,
pady=30
)
l1=tk.Label(
my_w,
text='Select date of birth',
bg='yellow'
)
l1.grid(
row=0,
column=1,
padx=10
)
def calculate_age(event=None):
dob=cal.get_date()
today=date.today()
age=relativedelta(
today,
dob
)
l1.config(
text=(
f'Years: {age.years}\n'
f'Months: {age.months}\n'
f'Days: {age.days}'
)
)
cal.bind(
'<<DateEntrySelected>>',
calculate_age
)
calculate_age()
my_w.mainloop()
The maxdate option prevents a future date from being selected as the date of birth.
DateEntry selects a date. To collect hours, minutes and seconds, we can use Tkinter Scale widgets.
The selected date and time can then be joined with datetime.combine().
from datetime import datetime, time
import tkinter as tk
from tkcalendar import DateEntry
my_w=tk.Tk()
my_w.geometry(
"450x300"
)
cal=DateEntry(
my_w,
date_pattern='yyyy-mm-dd'
)
cal.grid(
row=1,
column=0,
padx=10,
sticky='N'
)
hr=tk.Scale(
my_w,
from_=0,
to=23,
orient='vertical',
length=150
)
hr.grid(
row=1,
column=1
)
mn=tk.Scale(
my_w,
from_=0,
to=59,
orient='vertical',
length=150
)
mn.grid(
row=1,
column=2
)
sc=tk.Scale(
my_w,
from_=0,
to=59,
orient='vertical',
length=150
)
sc.grid(
row=1,
column=3
)
l1=tk.Label(
my_w,
bg='yellow',
font=('Arial', 16)
)
l1.grid(
row=0,
column=0,
columnspan=4,
padx=10,
pady=20
)
def my_upd(*args):
selected_time=time(
hour=hr.get(),
minute=mn.get(),
second=sc.get()
)
selected_datetime=datetime.combine(
cal.get_date(),
selected_time
)
formatted=selected_datetime.strftime(
"%d-%b-%Y %H:%M:%S"
)
l1.config(
text=formatted
)
cal.bind(
'<<DateEntrySelected>>',
my_upd
)
hr.config(
command=my_upd
)
mn.config(
command=my_upd
)
sc.config(
command=my_upd
)
my_upd()
my_w.mainloop()
Two DateEntry widgets can collect the start and end dates of a range.
A separate tkcalendar Calendar widget can then highlight every date in that range.
The calevent_create() and tag_config() methods belong to the Calendar widget used for displaying the highlighted dates.
import tkinter as tk
from tkcalendar import DateEntry, Calendar
from datetime import timedelta
root=tk.Tk()
root.geometry(
'430x450'
)
root.title(
'Date Range Selector'
)
start_entry=DateEntry(
root,
date_pattern='yyyy-mm-dd'
)
start_entry.grid(
row=0,
column=1,
padx=10,
pady=10
)
tk.Label(
root,
text='Start Date:'
).grid(
row=0,
column=0
)
end_entry=DateEntry(
root,
date_pattern='yyyy-mm-dd'
)
end_entry.grid(
row=1,
column=1,
padx=10,
pady=10
)
tk.Label(
root,
text='End Date:'
).grid(
row=1,
column=0
)
cal=Calendar(
root,
selectmode='none'
)
cal.grid(
row=2,
column=0,
columnspan=2,
padx=10,
pady=20
)
def update_calendar(event=None):
start_date=start_entry.get_date()
end_date=end_entry.get_date()
if start_date > end_date:
end_entry.set_date(
start_date
)
end_date=start_date
cal.calevent_remove(
'all'
)
current_date=start_date
while current_date <= end_date:
cal.calevent_create(
current_date,
'',
'highlight'
)
current_date += timedelta(
days=1
)
cal.tag_config(
'highlight',
background='lightblue',
foreground='black'
)
start_entry.bind(
'<<DateEntrySelected>>',
update_calendar
)
end_entry.bind(
'<<DateEntrySelected>>',
update_calendar
)
update_calendar()
root.mainloop()
DateEntry inherits from ttk.Entry, so its entry portion can be styled using ttk.Style().
import tkinter as tk
from tkinter import ttk
from tkcalendar import DateEntry
my_w=tk.Tk()
my_w.geometry(
'380x200'
)
style=ttk.Style()
# Uncomment if styling is not visible with the active theme
# style.theme_use('clam')
style.configure(
'my.DateEntry',
fieldbackground='lightgreen',
background='darkgreen',
foreground='darkblue',
arrowcolor='white'
)
cal=DateEntry(
my_w,
style='my.DateEntry',
date_pattern='yyyy-mm-dd'
)
cal.grid(
row=0,
column=0,
padx=30,
pady=30
)
my_w.mainloop()
tkcalendar.DateEntry(master=None, **options)
DateEntry is a date-selection entry with a drop-down calendar and is based on tkinter.ttk.Entry.
| Option | Purpose |
|---|---|
textvariable |
Connect the DateEntry value to a Tkinter variable. |
year |
Set the initial year. |
month |
Set the initial month. |
day |
Set the initial day. |
date_pattern |
Control the displayed date format. |
mindate |
Set the earliest selectable date. |
maxdate |
Set the latest selectable date. |
locale |
Set the calendar locale. |
width |
Set the width of the entry field. |
style |
Apply a ttk style. |
| Method | Purpose |
|---|---|
get() |
Return the text currently displayed in the entry. |
get_date() |
Return the selected date as a datetime.date. |
set_date() |
Set the DateEntry to another date. |
delete() |
Delete text using inherited Entry behavior. |
drop_down() |
Display or hide the drop-down calendar. |
configure() |
Change widget options. |
cget() |
Read a widget option. |
keys() |
Return available resource names. |
<<DateEntrySelected>>
This event is generated when the user selects a date from the drop-down calendar.
This returns displayed text:
value=cal.get()
For date calculations, use:
value=cal.get_date()
This is usually unnecessary:
datetime.strptime(
cal.get(),
'%m/%d/%y'
)
Instead:
selected_date=cal.get_date()
This also avoids problems when the displayed locale or date_pattern changes.
Use date_pattern to control the text displayed by DateEntry:
date_pattern='yyyy-mm-dd'
Use strftime() after obtaining a Python date:
cal.get_date().strftime(
'%Y-%m-%d'
)
DateEntry validates its contents as a date. An empty or invalid value can be restored to the previous valid date when validation occurs.
Calendar event tags such as tag_config() belong to the underlying or separate Calendar widget. In the date-range example above, a separate Calendar is used for highlighting.
DateEntry provides a drop-down date picker for Tkinter.tkcalendar package.get_date() returns the selected value as a datetime.date.get() returns the text displayed in the entry field.set_date() changes the selected date from Python code.<<DateEntrySelected>> can trigger a function when the user selects a date.date_pattern controls the DateEntry display format.strftime() formats the Python date returned by get_date().mindate and maxdate restrict the selectable range.relativedelta() can calculate age in years, months and days.ttk.Entry and can be styled with ttk.Style().Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.
01-04-2023 | |
| nice guide | |