闹钟的设计原理与实现(一)
华中科技大学 陈学友
2012年5月18日
现在很多人由于需要处理各种事物,但是由于某些原因可能会忘记在某个时间段需要完成的工作和其他事情,因此需要一个闹钟来提醒自己,避免忘记这些应该做的事情。如果只有一个提醒事件,情况非常简单,但是对于多事件提醒的闹钟来说,如何解决提醒不冲突,如何使资源占据最小是一个迫切需要解决的问题。本文介绍一个闹钟的设计与实现,此外还提出一种最近时间的方式来解决闹钟的设计问题。
闹钟 最近时间 多时间提醒处理机制
一个闹钟提醒包括三部分:
提醒的开始时间 |
重复周期 |
提醒的内容 |
提醒的开始时间是闹钟不可少的,提醒的内容是能够有效的提醒用户接下来要做的事情。很多闹钟是一次性闹钟,因此没有重复的周期,比如某天去机场车站接人或者参加某个考试等。还有很多事件需要定期的重复提醒,比如朋友的生日通常一年一次,起床闹钟通常每天都有。如果不设计【重复周期】,用户每次都得输入一个新的闹钟,这将是一件非常繁琐的事。我们希望尽量能有减少这种不友好的设计,因此【重复周期】是不可少的,在这种情况下,
【重复周期】=N
就代表是单次闹钟了。
【重复周期】可以是每年,每月,每周,每日,每时,每小时,每分,每秒(嗯,好吧,每秒都提醒这个意义可能不是很大,至少很少有人会有这种提醒的需要),也可以是用户自定义的时间间隔,比如是6小时等。理论上重复的周期也可以是一个世纪或者一千年。
对于多时间提醒的闹钟,需要生成一个提醒的列表来保存需要提醒的时间。
提醒的开始时间 |
重复周期 |
提醒的内容 |
S1 |
T1 |
Text1 |
S2 |
T2 |
Text2 |
S3 |
T3 |
Text3 |
举例说明一下,
设系统的时钟为Tn,假设一个提醒时间为
2012/5/20 13:30:00 |
每天 |
该起床了 |
那么我们需要提醒的时间就有
2012/5/2013:30:00
2012/5/2113:30:00
2012/5/2213:30:00
….
我们知道对于上面的例子,可以有一个简单的实现方法,那就是检测
Tn.Hour==13&&Tn.Mintue=30&&Tn.second==00
条件是否成立,这样我们就能实现每天都提醒该事件的发生。同样对于每年,每月也采用类似的方式。再如生日提醒
1990/5/20 13:30:00 |
每年 |
生日快乐 |
可以表示为
If(Tn.Month==5&& Tn.Day==20&& Tn.Hour==13&&Tn.Mintue=30&&Tn.second==00)
{
闹钟提醒;
}
但是对于一个【重复周期】为6小时的吃药时间提醒,
2012/5/20 13:30:00 |
每5小时 |
吃药 |
那么我们需要提醒的时间就有
2012/5/2013:30:00
2012/5/2018:30:00
2012/5/2123:30:00
2012/5/2104:30:00
……
如果使用上面的方法就无法准确提醒了。下一节介绍如何处理这个问题。
为解决上一节提出的自定义时间提醒问题,需要引入一个【真实提醒时间】。所谓【真实提醒时间】是指下一次要提醒时与系统进行比对,匹配则触发提醒事件的闹钟时间。
对于
2012/5/20 13:30:00 |
每5小时 |
吃药 |
这个提醒事件,假设当前系统时间Tn=2012/5/20 17:00:00. 那么【真实提醒时间】只有一个,且等于2012/5/2018:30:00.
与此对应,一个闹钟提醒除了原有的三部分外,还要增加【真实提醒时间】:
提醒的开始时间 |
重复周期 |
提醒的内容 |
真实提醒时间 |
【真实时间】可以根据系统的当前时间动态改变。下面讨论真实时间如何计算。
设S表示【提醒的开始时间】,Tv表示【真实提醒时间】,,Tc表示【重复周期】,则
Tv=S;
While(Tv<Tn)
Tv+=Tc;
最后,新的提醒事件列表就变成这样
提醒的开始时间 |
重复周期 |
提醒的内容 |
真实提醒时间 |
S1 |
T1 |
Text1 |
Tv1 |
S2 |
T2 |
Text2 |
Tv2 |
S3 |
T3 |
Text3 |
Tv3 |
我们只需要将Tn与Tvi一一比对就可以准确的触发提醒事件了。触发某个事件后将
Tvi+=Tci;
就可以得到下一次的真实提醒时间列表了。
进一步优化
既然拥有了Tv这张【真实提醒时间】,我们都知道,时间是线性的,因此Tvi与Tvj必然有一个大小关系,假设 Tvmin=Min{Tvi|i=1,2,3,….};那么我们就不需要每次都遍历这个【真实提醒时间】列表了。在初始化和列表发生改动是重新计算Tvmin,
If(Tn==Tvmin)
{
提醒事件;
更新Tv列表;
Tvmin==Min{Tvi|i=1,2,3,….};
}