介绍
这款程序是我用来管理时间的。刚开始我尝试了很多软件比如calendar。他用来记录长期保持的事件是方便的,也是我刚开始认为的最好选择。但是作为一名高中学生,我发现由于假期的存在,和行程的不确定性,我可能总是需要编辑我的calendar,很麻烦,所以只能记录我放学后的兴趣班时间。我想要的效果是在学校那种上课就响上课铃,下课就响下课铃,快上课了会提醒,快下课了也会提醒,这样我就能很规律的学习。而且考虑到有时候会“迟到”,所以我还要让程序能够自动地根据课程设定来安排离我现在时间最近的一堂课。
import time
import datetime
import pygame
import sys
from pyecharts import options as opts
from pyecharts.charts import Pie
from turtle import *
print()
pygame.init()
class Schedule:
@staticmethod
def to_float(lcl_tm: str) -> float: # convert string type time to float type
lst = lcl_tm.split(":")
return float(lst[0]) + round(float(lst[1]) / 60, 4)
@staticmethod
def to_string(lcl_tm: float) -> str:
int_part = str(int(lcl_tm // 1))
fl_part = str(round((lcl_tm % 1) * 60))
if len(fl_part) <= 1:
fl_part = "0" + fl_part
if len(int_part) <= 1:
int_part = "0" + int_part
return int_part + ":" + fl_part
def __init__(self, lessons, music_arr, start_tm="16:24"):
assert len( # format check for the argument
start_tm.split(":")) == 2, "wrong format of start_time argument, should be hour:minute, eg 16:30"
self.start_tm_nom = start_tm # officially announced start time of studying
self.start_plan = self.to_float(self.start_tm_nom) # planned time, which will change if the user is late.
cnt = 0
for lesson in lessons: # validation of argument 'lessons', due to the complexity of the program
if not (isinstance(lesson[1], int) or isinstance(lesson[2], int)):
raise TypeError("unable to utilise 'float' type in parameter 'lessons'")
else:
lesson.append(cnt)
cnt += 1
self.lessons = lessons # declare and assign only when the argument is valid
self.intv = 60 # to fetch state that determines whether it's time to start the program (unit: second)
self.__uncertainty = round(self.intv / 2 / 60 / 60, 5) # a range (unit:hour)
# load music resources
try:
self.start_music = pygame.mixer.Sound(music_arr[0])
self.over_music = pygame.mixer.Sound(music_arr[1])
self.near_lesson = music_arr[2]
except IndexError:
print("not enough music files for this program!")
except FileNotFoundError:
print("name of the music file is not found!")
@property
def gap(self): # encapsulation to prevent modification through undefined pathway
return self.__uncertainty
def new_start(self, now_: float):
cnt = 0
# when it's too early
if now_ <= self.start_plan + self.gap:
return 0, ""
for info in self.lessons:
if now_ <= self.start_plan:
return cnt, info[0] # 1.new lesson index 2.lesson name
self.start_plan += round((info[1] + info[2]) / 60, 5)
cnt += 1
print("you have missed all lessons today. make sure you attend them tomorrow on time!")
sys.exit()
def initialise(self) -> int:
cnt = 0 # ensure statement is only executed once
is_exe = True # same function as the one above
info = [0, 0, 0] # used to receive result
self.start_plan = self.to_float(self.start_tm_nom) # the initially planned start time
tm_to_start = 0.1 # notice when 6 minutes towards the first lesson (unit:hour)
while True:
now_tm = datetime.datetime.now().strftime('%A %H:%M').split(" ") # update the time now
now_ = self.to_float(now_tm[1])
# IF the now is later than planned starting time THEN
if (now_ > self.start_plan + self.gap) and is_exe: # execute once
info = self.new_start(now_)
print("late!\nlessons started at ", self.start_tm_nom) # nominal start time of study
print(f"attend the lesson <{info[1]}> started at ", self.to_string(self.start_plan))
is_exe = False
# IF now is earlier than planned starting time THEN
elif now_ < self.start_plan - self.gap:
if tm_to_start - self.gap <= self.start_plan - now_ <= tm_to_start + self.gap and cnt == 0:
print(f" {tm_to_start * 60} minutes towards the first lesson!")
cnt += 1
time.sleep(self.intv) # wait
# time to activate the main program
elif self.start_plan - self.gap <= now_ <= self.start_plan + self.gap:
print("implement: lesson start")
return info[0] # return the starting index of lesson list
# show time on console:None
@staticmethod
def show_time(total_tm: int): # total_time is in minute
sc = 60
total_tm -= 1
while total_tm >= 0:
time.sleep(1)
sc -= 1
print(total_tm, ":", sc)
if sc <= 0:
total_tm -= 1
sc = 60
# show time on turtle screen:None
@staticmethod
def show_time_screen(total_min: int, lesson): # parameter in minutes
if total_min < 1:
print(f"no time for {lesson}!")
return
tmp = total_min # break time length
total_min -= 1
is_exe = True # determine whether the lesson start notice should be executed
sc = 60 # second
sz = 160 # size of a character on the screen
dev = 0 # deviation in counting
# go to correct position
speed(0)
penup()
goto(-sz * 2, -sz / 2)
while total_min > -1:
if dev < 1:
intv = 1 - dev
else:
intv = 0 # set time slice to zero for deviation reduction
time.sleep(intv)
start = time.perf_counter()
sc -= 1
# effect:1:09 instead of 1:9
if 0 <= sc < 10:
str_sc = "0" + str(sc)
else:
str_sc = str(sc)
# clear the screen
clear()
write(str(total_min) + ":" + str_sc, font=("arial", sz, "normal"))
# reset second (one minute has passed)
if sc <= 0:
total_min -= 1
sc = 60
# lesson notice
if (total_min + round(sc / 60, 5)) <= tmp / 2 and is_exe: # execute only once
print(f"{tmp / 2} minutes towards the {lesson}!")
if lesson == "break time": # only execute when it's class-over time
pygame.mixer.Sound(self.near_lesson).play()
is_exe = False
end = time.perf_counter()
dev = round(end - start, 8) # time taken for program to count (deviation)
def execution(self):
start_idx = self.initialise()
for lesson_info in self.lessons:
now_idx = lesson_info[3]
if now_idx < start_idx:
continue
# class start
print("\nlesson <{}> (duration: {} minutes) starts now".format(lesson_info[0], lesson_info[1]))
self.start_music.play()
self.show_time_screen(lesson_info[1], "break time") # countdown
# next lesson notice
if now_idx < len(self.lessons) - 1:
print(f"the next lesson {self.lessons[now_idx + 1][0]} started at",
self.to_string(self.start_plan))
# class-over
if lesson_info[2] > 0: #
print(f"class is over. break time for {lesson_info[2]} minutes")
self.over_music.play()
self.start_plan += round((lesson_info[1] + lesson_info[2]) / 60, 5) # update next lesson's start time
self.show_time_screen(lesson_info[2], "lesson") # countdown
print("one day hard work is over. disfrutas tu hora hoy y duermes bien! hasta manana!")
def show_pie(self) -> None:
data_pairs = [[pair[0], pair[1]] for pair in self.lessons]
(
Pie(init_opts=opts.InitOpts(bg_color="#2c343c"))
.add(series_name="Pie chart",
center=["50%", "50%"],
radius="200",
data_pair=data_pairs,
)
.set_colors(["blue", "yellow", "red", "orange", "purple"])
.set_global_opts( # set title format
title_opts=opts.TitleOpts(
title="Pie",
pos_left="20%",
pos_top="50",
title_textstyle_opts=opts.TextStyleOpts(color="rgb(250,250,255)"), # title color
),
# is show legend
legend_opts=opts.LegendOpts(
is_show=True,
pos_left="0%",
background_color="rgb(250,250,255)",
border_color="rgb(150,150,150)"
),
)
# set label format
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c}", color="rgb(250,250,255)"))
.render("study_time_pie.html")
)
#模板
glb_lessons = [
["study", 60, 10],
["study", 60, 20],
["study", 60, 10], # to 20:10
["study", 60, 10],
["study", 60, 10], # 10:30
] #the second element of a sublist is lesson duration and the third is break time
glb_weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
glb_weekend = ["Saturday", "Sunday"]
#music_array=[class begin music,class over music, nearly class begin/over]
schedule = None
# use 24-hour system
glb_now = datetime.datetime.now().strftime('%A %H:%M').split(" ")
if glb_now[0] in glb_weekdays:
if glb_now[0] == "Wednesday":
glb_lessons.insert(2, ["English lesson", 60, 10])
schedule = Schedule(glb_lessons, music_array, "16:00")
schedule.execution()
schedule.show_pie()
done()
执行效果:
计时器:
他还会在一天的学习后根据你在每个学习内容上花的时间画饼图。
程序思路懒得讲了,喜欢的朋友用就好。这个程序运行稳定而且容易使用。