时区转换工具

server/2025/3/18 13:36:12/

开发一个Python程序,将用户输入的北京日期时间转换为全球多个目标地区的对应时间,支持手动选择地区,并显示开始和结束两个时间段的转换结果

python">import pytz
from datetime import datetime
import pandas as pd
from tabulate import tabulate
import tkinter as tk
from tkinter import ttk, colorchooser, filedialog, messagebox
import tkinter.font as font
import json
import os
#from PIL import Image, ImageTk
from tkcalendar import DateEntry
import webbrowserclass TimeZoneConverter:def __init__(self):# 预定义常用时区映射表self.timezone_mapping = {"上海": "Asia/Shanghai","纽约": "America/New_York","伦敦": "Europe/London","东京": "Asia/Tokyo","悉尼": "Australia/Sydney","巴黎": "Europe/Paris","莫斯科": "Europe/Moscow","迪拜": "Asia/Dubai","洛杉矶": "America/Los_Angeles","巴西(圣保罗)": "America/Sao_Paulo","新德里": "Asia/Kolkata","新加坡": "Asia/Singapore","开普敦": "Africa/Johannesburg",}def add_timezone(self, name, timezone_str):"""添加新的时区配置"""if timezone_str in pytz.all_timezones:self.timezone_mapping[name] = timezone_strreturn Trueelse:print(f"错误: {timezone_str} 不是有效的时区标识符")return Falsedef convert_time(self, beijing_time, target_timezone):"""将北京时间转换为目标时区时间"""# 确保输入的是datetime对象if not isinstance(beijing_time, datetime):raise TypeError("时间必须是datetime对象")# 设置北京时区beijing_tz = pytz.timezone("Asia/Shanghai")beijing_time_with_tz = beijing_tz.localize(beijing_time)# 转换到目标时区target_tz = pytz.timezone(target_timezone)target_time = beijing_time_with_tz.astimezone(target_tz)return target_timedef convert_time_range(self, start_time, end_time, target_timezones):"""转换时间范围到多个目标时区"""results = []# 对每个目标时区进行转换for name, tz_str in target_timezones.items():start_converted = self.convert_time(start_time, tz_str)end_converted = self.convert_time(end_time, tz_str)results.append({"地区": name,"时区": tz_str,"开始时间": start_converted.strftime("%Y-%m-%d %H:%M"),"结束时间": end_converted.strftime("%Y-%m-%d %H:%M")})return resultsdef display_results(self, results):"""显示转换结果"""df = pd.DataFrame(results)print("\n时区转换结果:")print(tabulate(df, headers='keys', tablefmt='pretty', showindex=False))def get_available_timezones(self):"""获取所有可用的时区名称"""return list(self.timezone_mapping.keys())def batch_convert(self, beijing_times, target_timezones):"""批量转换多个北京时间到多个目标时区"""results = []for time_point in beijing_times:for name, tz_str in target_timezones.items():converted = self.convert_time(time_point, tz_str)results.append({"原始北京时间": time_point.strftime("%Y-%m-%d %H:%M"),"目标地区": name,"时区": tz_str,"转换后时间": converted.strftime("%Y-%m-%d %H:%M")})return resultsdef calculate_time_difference(self, time1, time2, timezone1, timezone2):"""计算两个不同时区时间点之间的时间差"""# 确保输入的是datetime对象if not isinstance(time1, datetime) or not isinstance(time2, datetime):raise TypeError("时间必须是datetime对象")# 设置时区tz1 = pytz.timezone(timezone1)tz2 = pytz.timezone(timezone2)time1_with_tz = tz1.localize(time1)time2_with_tz = tz2.localize(time2)# 计算时间差time_diff = time2_with_tz - time1_with_tz# 返回时间差(秒)return time_diff.total_seconds()def parse_datetime(datetime_str):"""解析用户输入的日期时间字符串"""try:return datetime.strptime(datetime_str, "%Y-%m-%d %H:%M")except ValueError:print("错误: 日期时间格式不正确,请使用 YYYY-MM-DD HH:MM 格式")return Nonedef main():converter = TimeZoneConverter()print("欢迎使用北京时区转换工具")print("请输入北京时间 (格式: YYYY-MM-DD HH:MM)")# 获取开始时间while True:start_time_str = input("开始时间: ")start_time = parse_datetime(start_time_str)if start_time:break# 获取结束时间while True:end_time_str = input("结束时间: ")end_time = parse_datetime(end_time_str)if end_time:if end_time < start_time:print("错误: 结束时间不能早于开始时间")else:break# 显示可用时区available_timezones = converter.get_available_timezones()print("\n可用的目标地区:")for i, tz in enumerate(available_timezones, 1):print(f"{i}. {tz}")# 选择目标时区selected_indices = input("\n请选择目标地区 (输入序号,多个序号用逗号分隔,输入'all'选择所有): ")selected_timezones = {}if selected_indices.lower() == 'all':selected_timezones = converter.timezone_mappingelse:try:indices = [int(idx.strip()) for idx in selected_indices.split(',')]for idx in indices:if 1 <= idx <= len(available_timezones):tz_name = available_timezones[idx-1]selected_timezones[tz_name] = converter.timezone_mapping[tz_name]else:print(f"警告: 序号 {idx} 超出范围,已忽略")except ValueError:print("警告: 输入格式不正确,将使用默认时区 (北京)")selected_timezones = {"北京": "Asia/Shanghai"}# 如果没有选择任何时区,使用默认值if not selected_timezones:print("未选择任何时区,将使用默认时区 (巴西)")selected_timezones = {"巴西": "America/Sao_Paulo"}# 执行转换results = converter.convert_time_range(start_time, end_time, selected_timezones)# 显示结果converter.display_results(results)class Settings:def __init__(self):self.config_file = "timezone_converter_settings.json"self.default_settings = {"font_family": "Arial","font_size": 10,"text_color": "#000000","bg_color": "#f0f0f0","bg_image": "","version": "1.0.0"}self.settings = self.load_settings()def load_settings(self):"""从文件加载设置"""if os.path.exists(self.config_file):try:with open(self.config_file, 'r', encoding='utf-8') as f:return json.load(f)except Exception as e:print(f"加载设置时出错: {e}")return self.default_settings.copy()else:return self.default_settings.copy()def save_settings(self):"""保存设置到文件"""try:with open(self.config_file, 'w', encoding='utf-8') as f:json.dump(self.settings, f, ensure_ascii=False, indent=4)return Trueexcept Exception as e:print(f"保存设置时出错: {e}")return Falsedef get(self, key, default=None):"""获取设置值"""return self.settings.get(key, default)def set(self, key, value):"""设置值"""self.settings[key] = valuereturn self.save_settings()def reset_to_default(self):"""重置为默认设置"""self.settings = self.default_settings.copy()return self.save_settings()class TimeZoneConverterGUI:def __init__(self, root):self.root = rootself.root.title("北京时区转换工具")self.root.geometry("900x700")self.converter = TimeZoneConverter()self.settings = Settings()# 加载设置self.load_ui_settings()# 创建菜单self.create_menu()# 创建界面组件self.create_widgets()def load_ui_settings(self):"""加载UI设置并应用"""# 设置字体self.font_family = self.settings.get("font_family", "Arial")self.font_size = self.settings.get("font_size", 10)self.default_font = (self.font_family, self.font_size)self.header_font = (self.font_family, self.font_size + 6, "bold")# 设置颜色self.text_color = self.settings.get("text_color", "#000000")self.bg_color = self.settings.get("bg_color", "#f0f0f0")# 应用背景色self.root.configure(bg=self.bg_color)# 加载背景图片self.bg_image_path = self.settings.get("bg_image", "")self.bg_image = Noneself.bg_label = Noneif self.bg_image_path and os.path.exists(self.bg_image_path):self.load_background_image(self.bg_image_path)def load_background_image(self, image_path):"""加载背景图片"""try:# 加载图片image = Image.open(image_path)# 调整图片大小以适应窗口window_width = self.root.winfo_width()window_height = self.root.winfo_height()# 如果窗口尚未渲染,使用几何尺寸if window_width <= 1:window_width = 900window_height = 700image = image.resize((window_width, window_height), Image.LANCZOS)# 转换为Tkinter可用的格式self.bg_image = ImageTk.PhotoImage(image)# 创建或更新背景标签if self.bg_label:self.bg_label.configure(image=self.bg_image)else:self.bg_label = tk.Label(self.root, image=self.bg_image)self.bg_label.place(x=0, y=0, relwidth=1, relheight=1)self.bg_label.lower()  # 将背景放到最底层# 更新设置self.settings.set("bg_image", image_path)return Trueexcept Exception as e:messagebox.showerror("错误", f"加载背景图片失败: {str(e)}")return Falsedef create_menu(self):"""创建菜单栏"""menubar = tk.Menu(self.root)# 文件菜单file_menu = tk.Menu(menubar, tearoff=0)file_menu.add_command(label="导出结果", command=self.export_results)file_menu.add_separator()file_menu.add_command(label="退出", command=self.root.quit)menubar.add_cascade(label="文件", menu=file_menu)# 设置菜单settings_menu = tk.Menu(menubar, tearoff=0)settings_menu.add_command(label="界面设置", command=self.open_settings)settings_menu.add_command(label="重置设置", command=self.reset_settings)menubar.add_cascade(label="设置", menu=settings_menu)# 帮助菜单help_menu = tk.Menu(menubar, tearoff=0)help_menu.add_command(label="使用说明", command=self.show_help)help_menu.add_command(label="关于", command=self.show_about)menubar.add_cascade(label="帮助", menu=help_menu)self.root.config(menu=menubar)def create_widgets(self):# 创建主框架self.main_frame = ttk.Frame(self.root)self.main_frame.pack(fill="both", expand=True, padx=20, pady=20)# 标题title_label = ttk.Label(self.main_frame, text="北京时区转换工具", font=self.header_font)title_label.pack(pady=10)# 输入框架input_frame = ttk.LabelFrame(self.main_frame, text="输入北京时间")input_frame.pack(fill="x", padx=10, pady=10)# 开始时间 - 使用日期选择器和时间滚动选择start_frame = ttk.Frame(input_frame)start_frame.pack(fill="x", padx=10, pady=5)ttk.Label(start_frame, text="开始日期:").pack(side="left", padx=5)self.start_date_entry = DateEntry(start_frame, width=12, background='darkblue',foreground='white', borderwidth=2, date_pattern='yyyy-mm-dd')self.start_date_entry.pack(side="left", padx=5)ttk.Label(start_frame, text="时间:").pack(side="left", padx=5)# 小时选择self.start_hour_var = tk.StringVar()self.start_hour_spinbox = ttk.Spinbox(start_frame, from_=0, to=23, width=2, textvariable=self.start_hour_var, format="%02.0f")self.start_hour_spinbox.pack(side="left")self.start_hour_var.set("09")ttk.Label(start_frame, text=":").pack(side="left")# 分钟选择self.start_minute_var = tk.StringVar()self.start_minute_spinbox = ttk.Spinbox(start_frame, from_=0, to=59, width=2, textvariable=self.start_minute_var, format="%02.0f")self.start_minute_spinbox.pack(side="left")self.start_minute_var.set("00")# 结束时间end_frame = ttk.Frame(input_frame)end_frame.pack(fill="x", padx=10, pady=5)ttk.Label(end_frame, text="结束日期:").pack(side="left", padx=5)self.end_date_entry = DateEntry(end_frame, width=12, background='darkblue',foreground='white', borderwidth=2, date_pattern='yyyy-mm-dd')self.end_date_entry.pack(side="left", padx=5)ttk.Label(end_frame, text="时间:").pack(side="left", padx=5)# 小时选择self.end_hour_var = tk.StringVar()self.end_hour_spinbox = ttk.Spinbox(end_frame, from_=0, to=23, width=2, textvariable=self.end_hour_var, format="%02.0f")self.end_hour_spinbox.pack(side="left")self.end_hour_var.set("18")ttk.Label(end_frame, text=":").pack(side="left")# 分钟选择self.end_minute_var = tk.StringVar()self.end_minute_spinbox = ttk.Spinbox(end_frame, from_=0, to=59, width=2, textvariable=self.end_minute_var, format="%02.0f")self.end_minute_spinbox.pack(side="left")self.end_minute_var.set("00")# 时区选择框架timezone_frame = ttk.LabelFrame(self.main_frame, text="选择目标时区")timezone_frame.pack(fill="both", expand=True, padx=10, pady=10)# 创建时区选择列表 - 使用Treeview替代Listbox以支持更好的滚动columns = ("时区名称",)self.timezone_tree = ttk.Treeview(timezone_frame, columns=columns, show="headings", selectmode="extended")self.timezone_tree.heading("时区名称", text="时区名称")self.timezone_tree.column("时区名称", width=150)self.timezone_tree.pack(side="left", fill="both", expand=True, padx=10, pady=10)# 添加滚动条scrollbar = ttk.Scrollbar(timezone_frame, orient="vertical", command=self.timezone_tree.yview)scrollbar.pack(side="right", fill="y", pady=10)self.timezone_tree.config(yscrollcommand=scrollbar.set)# 填充时区列表for tz in self.converter.get_available_timezones():self.timezone_tree.insert("", tk.END, values=(tz,))# 按钮框架button_frame = ttk.Frame(self.main_frame)button_frame.pack(fill="x", padx=10, pady=10)# 转换按钮convert_button = ttk.Button(button_frame, text="转换时区", command=self.convert)convert_button.pack(side="left", padx=10)# 全选按钮select_all_button = ttk.Button(button_frame, text="全选时区", command=self.select_all)select_all_button.pack(side="left", padx=10)# 清除选择按钮clear_button = ttk.Button(button_frame, text="清除选择", command=self.clear_selection)clear_button.pack(side="left", padx=10)# 结果框架result_frame = ttk.LabelFrame(self.main_frame, text="转换结果")result_frame.pack(fill="both", expand=True, padx=10, pady=10)# 创建表格columns = ("地区", "时区", "开始时间", "结束时间")self.result_tree = ttk.Treeview(result_frame, columns=columns, show="headings")# 设置列标题for col in columns:self.result_tree.heading(col, text=col)self.result_tree.column(col, width=100)self.result_tree.pack(side="left", fill="both", expand=True, padx=10, pady=10)# 添加结果表格的滚动条result_scrollbar = ttk.Scrollbar(result_frame, orient="vertical", command=self.result_tree.yview)result_scrollbar.pack(side="right", fill="y", pady=10)self.result_tree.config(yscrollcommand=result_scrollbar.set)# 状态栏self.status_var = tk.StringVar()self.status_var.set(f"版本: {self.settings.get('version')} | 就绪")status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)status_bar.pack(side=tk.BOTTOM, fill=tk.X)# 绑定窗口大小变化事件,以调整背景图片self.root.bind("<Configure>", self.on_window_resize)def on_window_resize(self, event):"""窗口大小变化时调整背景图片"""if self.bg_image_path and os.path.exists(self.bg_image_path):# 仅当窗口大小真正变化时才重新加载if event.widget == self.root and (event.width != self.root.winfo_width() or event.height != self.root.winfo_height()):self.load_background_image(self.bg_image_path)def select_all(self):"""全选所有时区"""for item in self.timezone_tree.get_children():self.timezone_tree.selection_add(item)def clear_selection(self):"""清除所有选择"""self.timezone_tree.selection_remove(self.timezone_tree.get_children())def convert(self):"""执行时区转换"""try:# 获取开始时间start_date = self.start_date_entry.get()start_hour = self.start_hour_var.get().zfill(2)start_minute = self.start_minute_var.get().zfill(2)start_datetime_str = f"{start_date} {start_hour}:{start_minute}"start_datetime = datetime.strptime(start_datetime_str, "%Y-%m-%d %H:%M")# 获取结束时间end_date = self.end_date_entry.get()end_hour = self.end_hour_var.get().zfill(2)end_minute = self.end_minute_var.get().zfill(2)end_datetime_str = f"{end_date} {end_hour}:{end_minute}"end_datetime = datetime.strptime(end_datetime_str, "%Y-%m-%d %H:%M")# 检查时间顺序if end_datetime < start_datetime:messagebox.showerror("错误", "结束时间不能早于开始时间")return# 获取选中的时区selected_items = self.timezone_tree.selection()if not selected_items:messagebox.showwarning("警告", "请至少选择一个目标时区")return# 构建选中的时区字典selected_timezones = {}for item in selected_items:tz_name = self.timezone_tree.item(item, "values")[0]selected_timezones[tz_name] = self.converter.timezone_mapping[tz_name]# 执行转换results = self.converter.convert_time_range(start_datetime, end_datetime, selected_timezones)# 清空现有结果for item in self.result_tree.get_children():self.result_tree.delete(item)# 显示结果for result in results:self.result_tree.insert("", tk.END, values=(result["地区"],result["时区"],result["开始时间"],result["结束时间"]))# 更新状态栏self.status_var.set(f"版本: {self.settings.get('version')} | 转换完成: {len(results)}个结果")except ValueError as e:messagebox.showerror("输入错误", f"请检查日期和时间格式: {str(e)}")except Exception as e:messagebox.showerror("错误", f"发生错误: {str(e)}")def export_results(self):"""导出结果到文件"""if not self.result_tree.get_children():messagebox.showinfo("提示", "没有可导出的结果")returnfile_path = filedialog.asksaveasfilename(defaultextension=".csv",filetypes=[("CSV文件", "*.csv"), ("Excel文件", "*.xlsx"), ("所有文件", "*.*")])if not file_path:returntry:# 收集结果数据results = []for item in self.result_tree.get_children():values = self.result_tree.item(item, "values")results.append({"地区": values[0],"时区": values[1],"开始时间": values[2],"结束时间": values[3]})# 创建DataFramedf = pd.DataFrame(results)# 根据文件扩展名导出if file_path.endswith('.csv'):df.to_csv(file_path, index=False, encoding='utf-8-sig')elif file_path.endswith('.xlsx'):df.to_excel(file_path, index=False)else:df.to_csv(file_path, index=False, encoding='utf-8-sig')messagebox.showinfo("成功", f"结果已成功导出到 {file_path}")except Exception as e:messagebox.showerror("导出错误", f"导出结果时出错: {str(e)}")def open_settings(self):"""打开设置对话框"""settings_window = tk.Toplevel(self.root)settings_window.title("界面设置")settings_window.geometry("500x400")settings_window.resizable(False, False)settings_window.transient(self.root)  # 设置为主窗口的子窗口# 创建设置框架settings_frame = ttk.Frame(settings_window, padding=20)settings_frame.pack(fill="both", expand=True)# 字体设置font_frame = ttk.LabelFrame(settings_frame, text="字体设置")font_frame.pack(fill="x", padx=10, pady=10)# 字体选择ttk.Label(font_frame, text="字体:").grid(row=0, column=0, sticky="w", padx=5, pady=5)# 获取系统可用字体available_fonts = sorted(font.families())font_var = tk.StringVar(value=self.font_family)font_combo = ttk.Combobox(font_frame, textvariable=font_var, values=available_fonts, state="readonly")font_combo.grid(row=0, column=1, sticky="ew", padx=5, pady=5)# 字体大小ttk.Label(font_frame, text="字体大小:").grid(row=1, column=0, sticky="w", padx=5, pady=5)size_var = tk.IntVar(value=self.font_size)size_spinbox = ttk.Spinbox(font_frame, from_=8, to=24, textvariable=size_var, width=5)size_spinbox.grid(row=1, column=1, sticky="w", padx=5, pady=5)# 颜色设置color_frame = ttk.LabelFrame(settings_frame, text="颜色设置")color_frame.pack(fill="x", padx=10, pady=10)# 文本颜色ttk.Label(color_frame, text="文本颜色:").grid(row=0, column=0, sticky="w", padx=5, pady=5)text_color_var = tk.StringVar(value=self.text_color)text_color_entry = ttk.Entry(color_frame, textvariable=text_color_var, width=10)text_color_entry.grid(row=0, column=1, sticky="w", padx=5, pady=5)text_color_button = ttk.Button(color_frame, text="选择...", command=lambda: self.choose_color(text_color_var))text_color_button.grid(row=0, column=2, padx=5, pady=5)# 背景颜色ttk.Label(color_frame, text="背景颜色:").grid(row=1, column=0, sticky="w", padx=5, pady=5)bg_color_var = tk.StringVar(value=self.bg_color)bg_color_entry = ttk.Entry(color_frame, textvariable=bg_color_var, width=10)bg_color_entry.grid(row=1, column=1, sticky="w", padx=5, pady=5)bg_color_button = ttk.Button(color_frame, text="选择...", command=lambda: self.choose_color(bg_color_var))bg_color_button.grid(row=1, column=2, padx=5, pady=5)# 背景图片设置bg_frame = ttk.LabelFrame(settings_frame, text="背景图片")bg_frame.pack(fill="x", padx=10, pady=10)bg_path_var = tk.StringVar(value=self.bg_image_path)bg_path_entry = ttk.Entry(bg_frame, textvariable=bg_path_var, width=30)bg_path_entry.grid(row=0, column=0, sticky="ew", padx=5, pady=5)bg_browse_button = ttk.Button(bg_frame, text="浏览...", command=lambda: self.browse_bg_image(bg_path_var))bg_browse_button.grid(row=0, column=1, padx=5, pady=5)bg_clear_button = ttk.Button(bg_frame, text="清除", command=lambda: bg_path_var.set(""))bg_clear_button.grid(row=0, column=2, padx=5, pady=5)# 按钮框架button_frame = ttk.Frame(settings_frame)button_frame.pack(fill="x", padx=10, pady=20)# 保存按钮save_button = ttk.Button(button_frame, text="保存设置", command=lambda: self.save_ui_settings(font_var.get(), size_var.get(), text_color_var.get(), bg_color_var.get(),bg_path_var.get(), settings_window))save_button.pack(side="right", padx=5)# 取消按钮cancel_button = ttk.Button(button_frame, text="取消", command=settings_window.destroy)cancel_button.pack(side="right", padx=5)# 使对话框模态settings_window.grab_set()settings_window.focus_set()settings_window.wait_window()def choose_color(self, color_var):"""打开颜色选择器"""color = colorchooser.askcolor(color_var.get())[1]if color:color_var.set(color)def browse_bg_image(self, path_var):"""浏览选择背景图片"""file_path = filedialog.askopenfilename(filetypes=[("图片文件", "*.png *.jpg *.jpeg *.gif *.bmp"), ("所有文件", "*.*")])if file_path:path_var.set(file_path)def save_ui_settings(self, font_family, font_size, text_color, bg_color, bg_image, dialog):"""保存UI设置并应用"""# 保存设置self.settings.set("font_family", font_family)self.settings.set("font_size", font_size)self.settings.set("text_color", text_color)self.settings.set("bg_color", bg_color)self.settings.set("bg_image", bg_image)# 应用设置self.font_family = font_familyself.font_size = font_sizeself.default_font = (self.font_family, self.font_size)self.header_font = (self.font_family, self.font_size + 6, "bold")self.text_color = text_colorself.bg_color = bg_color# 应用背景色self.root.configure(bg=self.bg_color)# 加载背景图片self.bg_image_path = bg_imageif bg_image and os.path.exists(bg_image):self.load_background_image(bg_image)elif not bg_image and self.bg_label:self.bg_label.destroy()self.bg_label = Noneself.bg_image = None# 关闭对话框dialog.destroy()# 提示用户messagebox.showinfo("设置已保存", "界面设置已保存并应用")def reset_settings(self):"""重置为默认设置"""if messagebox.askyesno("确认", "确定要重置所有设置到默认值吗?"):self.settings.reset_to_default()messagebox.showinfo("成功", "设置已重置为默认值,重启应用后生效")def show_help(self):"""显示使用说明"""help_text = """北京时区转换工具使用说明:1. 输入北京时间:- 选择开始日期和时间- 选择结束日期和时间2. 选择目标时区:- 在列表中选择一个或多个目标时区- 可以使用"全选时区"按钮选择所有时区- 可以使用"清除选择"按钮取消所有选择3. 点击"转换时区"按钮执行转换4. 在结果表格中查看转换后的时间5. 可以使用"导出结果"功能将结果保存为CSV或Excel文件6. 在"设置"菜单中可以自定义界面外观"""help_window = tk.Toplevel(self.root)help_window.title("使用说明")help_window.geometry("600x400")help_window.transient(self.root)text_widget = tk.Text(help_window, wrap="word", padx=10, pady=10)text_widget.pack(fill="both", expand=True)text_widget.insert("1.0", help_text)text_widget.config(state="disabled")scrollbar = ttk.Scrollbar(text_widget, command=text_widget.yview)scrollbar.pack(side="right", fill="y")text_widget.config(yscrollcommand=scrollbar.set)close_button = ttk.Button(help_window, text="关闭", command=help_window.destroy)close_button.pack(pady=10)help_window.grab_set()help_window.focus_set()def show_about(self):"""显示关于信息"""version = self.settings.get("version", "1.0.0.0")about_text = f"""北京时区转换工具版本: {version}功能:- 将北京时间转换为全球多个时区的时间- 支持时间段转换- 自定义界面外观- 结果导出功能时区转换工具"""messagebox.showinfo("关于", about_text)def run_gui():root = tk.Tk()app = TimeZoneConverterGUI(root)root.mainloop()if __name__ == "__main__":run_gui()

在这里插入图片描述


http://www.ppmy.cn/server/175969.html

相关文章

Python 视频爬取教程

文章目录 前言基本原理环境准备Python安装选择Python开发环境安装必要库 示例 1&#xff1a;爬取简单直链视频示例 2&#xff1a;爬取基于 HTML5 的视频&#xff08;以某简单视频网站为例&#xff09; 前言 以下是一个较为完整的 Python 视频爬取教程&#xff0c;包含基本原理…

计算机基础:二进制基础13,十六进制与二进制的相互转换

专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏&#xff0c;故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 &#xff08;一&#xff09;WIn32 专栏导航 上一篇&#xff1a;计算机基础&#xff1a;二进制基础12&#xff0c;十进制数转换为…

EasyExcel动态拆分非固定列Excel表格

使用EasyExcel动态拆分非固定列Excel表格 在Excel数据解析场景中&#xff0c;​动态列结构拆分是典型挑战&#xff08;如供应链系统中不同品类的属性字段差异较大&#xff09;。传统基于POJO映射的方案无法应对列数量不固定的场景。本方案采用EasyExcel的动态模型解析和Map数据…

C++之list类及模拟实现

目录 list的介绍 list的模拟实现 定义节点 有关遍历的重载运算符 list的操作实现 &#xff08;1&#xff09;构造函数 (2)拷贝构造函数 &#xff08;3&#xff09;赋值运算符重载函数 &#xff08;4&#xff09;析构函数和clear成员函数 &#xff08;5&#xff09;尾…

C# ManualResetEvent‌的高级用法

一、ManualResetEvent 的核心作用‌ ManualResetEvent 是 C# 中用于 ‌线程同步‌ 的类&#xff08;位于 System.Threading 命名空间&#xff09;&#xff0c;通过信号机制控制线程的等待与执行。其核心功能包括&#xff1a; 阻塞线程‌&#xff1a;调用 WaitOne() 的线程会等…

【实测闭坑】LazyGraphRAG利用本地ollama提供Embedding model服务和火山引擎的deepseek API构建本地知识库

LazyGraphRAG 2024年4月&#xff0c;为解决传统RAG在全局性的查询总结任务上表现不佳&#xff0c;微软多部门联合提出Project GraphRAG&#xff08;大模型驱动的KG&#xff09;&#xff1b;2024年7月&#xff0c;微软正式开源GraphRAG项目&#xff0c;引起极大关注&#xff0c…

【前端面试题】宏任务与微任务的区别

宏任务与微任务的区别 JavaScript采用单线程模型&#xff0c;通过 事件循环&#xff08;Event Loop&#xff09; 机制处理异步操作。 类比于厨师上菜的过程&#xff0c;顾客点的菜可能存在容易处理的 “软菜” 与难处理的 “硬菜” &#xff0c;以及要加米饭酒水这些立马可以上…

Java常用设计模式

设计模式是软件开发中解决常见问题的模板或指南。Java中的23种设计模式通常被分为三大类&#xff1a;创建型模式&#xff08;Creational Patterns&#xff09;、结构型模式&#xff08;Structural Patterns&#xff09;和行为型模式&#xff08;Behavioral Patterns&#xff09…