import tkinter as tk
from tkinter import font
from tkcalendar import DateEntry
from datetime import date, timedelta
import calendar
import pickle
import os
import lunardate
DATA_FILE = "selected_date.pkl"
def load_selected_date():
"""加载之前保存的选定日期"""
if os.path.exists(DATA_FILE) and os.path.getsize(DATA_FILE) > 0:
with open(DATA_FILE, 'rb') as f:
return pickle.load(f)
return None
def save_selected_date(selected_date_value):
"""保存选定的日期"""
with open(DATA_FILE, 'wb') as f:
pickle.dump(selected_date_value, f)
def update_calendar():
"""清除并重新绘制日历"""
for widget in frame.winfo_children():
widget.destroy()
show_calendar(frame, current_year, current_month)
update_date_label()
def get_lunar_date_chinese(gregorian_date):
"""获取农历日期的中文表示"""
try:
lunar_date = lunardate.LunarDate.fromSolarDate(gregorian_date.year, gregorian_date.month, gregorian_date.day)
lunar_month_str = ["正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"][
lunar_date.month - 1]
if lunar_date.day == 10:
lunar_day_str = '初十'
elif 1 <= lunar_date.day < 10:
lunar_day_str = ['初一', '初二', '初三', '初四', '初五', '初六', '初七', '初八', '初九'][lunar_date.day - 1]
elif 10 < lunar_date.day <= 19:
lunar_day_str = '十' + ['一', '二', '三', '四', '五', '六', '七', '八', '九'][lunar_date.day - 11]
elif 20 < lunar_date.day <= 29:
lunar_day_str = '廿' + ['一', '二', '三', '四', '五', '六', '七', '八', '九'][lunar_date.day - 21]
else:
lunar_day_str = '三十'
return f"{lunar_month_str}月{lunar_day_str}"
except Exception as e:
print(f"Error converting date: {e}")
return ""
def show_calendar(parent, year, month):
"""生成并显示指定月份的日历,高亮显示选定的大周的周末,并显示农历日期"""
cal = calendar.Calendar()
cal_text = cal.monthdayscalendar(year, month)
normal_font = font.Font(family="Arial", size=12)
bold_font = font.Font(family="Arial", size=12, weight="bold")
small_font = font.Font(family="Arial", size=8)
week_days = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
for i, day in enumerate(week_days):
label = tk.Label(parent, text=day, font=bold_font)
label.grid(row=1, column=i, padx=5, pady=5, sticky="nsew")
parent.grid_columnconfigure(i, weight=1)
selected_week_start = get_selected_week_start(selected_date.get_date())
for row_idx, week in enumerate(cal_text):
for col_idx, day in enumerate(week):
if day == 0:
continue
gregorian_date = date(year, month, day)
lunar_str = get_lunar_date_chinese(gregorian_date)
if day == today_day and year == now.year and month == now.month:
label = tk.Label(parent, text=str(day), bg='systemInactiveCaption', font=bold_font)
elif (gregorian_date.weekday() >= 5) and is_in_same_big_week(gregorian_date, selected_week_start):
label = tk.Label(parent, text=str(day), bg='lightgreen', font=bold_font)
else:
label = tk.Label(parent, text=str(day), font=normal_font)
label.grid(row=row_idx * 2 + 2, column=col_idx, padx=5, pady=5, sticky="nsew")
lunar_label = tk.Label(parent, text=lunar_str, font=small_font)
lunar_label.grid(row=row_idx * 2 + 3, column=col_idx, padx=5, pady=0, sticky="nsew")
def update_date_label():
"""更新顶部的年份和月份标签"""
date_str = f"{current_year}年{current_month}月"
date_label.config(text=date_str)
def change_month(increment):
"""根据increment值(+1或-1)来改变当前月份,并更新日历"""
global current_month, current_year
current_month += increment
if current_month < 1:
current_month = 12
current_year -= 1
elif current_month > 12:
current_month = 1
current_year += 1
update_calendar()
def on_date_select(event=None):
"""当用户选择一个新的日期时,重新绘制日历并保存选择"""
selected_date_value = selected_date.get_date()
save_selected_date(selected_date_value)
update_calendar()
def get_selected_week_start(d):
"""返回选定日期所在的大周的第一天(星期一)"""
start_of_week = d - timedelta(days=d.weekday())
return start_of_week - timedelta(days=(start_of_week.weekday() // 7) * 7)
def is_in_same_big_week(date1, date2):
"""检查两个日期是否在同一个大周内"""
start_of_week1 = date1 - timedelta(days=date1.weekday())
start_of_week2 = date2 - timedelta(days=date2.weekday())
return (start_of_week1 - start_of_week2).days % 14 == 0
root = tk.Tk()
root.title("大小周日历")
root.geometry('600x500')
now = date.today()
current_year = now.year
current_month = now.month
today_day = now.day
selected_date_value = load_selected_date()
if selected_date_value:
selected_date = DateEntry(root, width=12, background='alice blue',
foreground='black', borderwidth=2,
year=selected_date_value.year,
month=selected_date_value.month,
day=selected_date_value.day,
locale='zh_CN', date_pattern='yyyy-mm-dd')
else:
selected_date = DateEntry(root, width=12, background='alice blue',
foreground='black', borderwidth=2, year=now.year,
locale='zh_CN', date_pattern='yyyy-mm-dd')
selected_date.bind("<<DateEntrySelected>>", on_date_select)
label_week_selector = tk.Label(root, text="大周选择框:", font=font.Font(family="Arial", size=12, weight="bold"))
date_label = tk.Label(root, text="", font=font.Font(family="Arial", size=14, weight="bold"))
btn_prev = tk.Button(root, text="<", command=lambda: change_month(-1))
btn_next = tk.Button(root, text=">", command=lambda: change_month(1))
date_label.grid(row=0, column=1, columnspan=1, padx=4, pady=5, sticky="ew")
btn_prev.grid(row=0, column=0, padx=(10, 5), pady=5)
btn_next.grid(row=0, column=2, padx=(5, 10), pady=5)
selected_date.grid(row=0, column=5, padx=5, pady=5)
label_week_selector.grid(row=0, column=4, padx=(5, 10), pady=3)
frame = tk.Frame(root)
frame.grid(row=1, column=0, columnspan=6, sticky="nsew")
root.grid_rowconfigure(1, weight=1)
for i in range(6):
root.grid_columnconfigure(i, weight=1)
update_calendar()
root.mainloop()