林 娟,周飞亚,周发刚,阳镇涛,唐铸文
(1.荆楚理工学院第一临床学院暨荆门市第一人民医院,中国荆门 448000;2.温州医科大学附属第二医院,中国温州 325027;3.荆楚理工学院,中国荆门 448000)
在教务系统[1]中有多处用到开课日期.计算课程进度表、查询课表时,需要指定一个本学期的开课日期,作为计算课表的日期起点,否则计算机不知道从何时开始计算.
开课日期可以用很多方法实现.如用数据库技术,由管理员将实际的每一学期开课日期保存在数据库中,使用时,直接从数据库中取出,呈现在用户面前.此法不仅需要每学期要输入一次,而且占用系统资源,还有一个原因是管理人员也要知道开课的日期.本文的目的旨在从算法的角度来自动实现开课日期.
经过观察及多年的开学日期的回顾,学校开学后的开课日期一般是在9月1日或元宵节前后三天左右的星期一.将9月1日与元宵节作为“基点”,列出基点左右4 天的日期与星期,开课日期基本上集中在此范围,见表1.虽然,开课日期受行政因素[2-4]等有关情况的制约,但是,大多数情况下如此.
表1 开课日期与星期可能分布的范围Tab.1 The range of possible distribution about course start date and week
如果将开课日期制作成一个类,用户使用时,系统会显示默认的开课日期.如果确有不符的日期,有关教务人员是会发出通知的,在使用中,由用户修改开课日期.
作者用VFP 的类,设计成一个日期控件对象,在需要时,将其选放到表单界面中.程序运行时,系统自动显示出当前学期的开课日期[5-6],经多年应用,效果较好.现将作者开发的开课日期类介绍如下.
每年有二个学期.下半年(秋季)开学的是第一学期,学期期段为当年的8月到次年的1月,上半年(春季)开学的为第二学期,学期期段设为2月到7月.开课日期主要用来计算这二个学期的开始上课的日期,使日期、周次能与现实一致.
用Microsoft Visual FoxProo 类设计器设计开课日期类.基类选用“textbox”文本框,将这个日期类命名为datemonday,对datemonday 的属性value 设为“date()”,使datemonday 成为日期类型.在datemonday 的init 方法中编写代码,在程序启动时,算出开课的阳历日期.
VFP 中有一个日期星期转换函数dow()[7]和一个某月中的几号day()函数,可以帮助实现转换.用dow()函数得到星期几,用day()函数取得日期号,合成到年月中,这样,即可得到开课日期.见式(1),(2).
式中W 表示星期几;D 代表开课日期;y=设定的阳历日期;参数2 表示模式;使星期一等于1;星期二等于2,…n,1 是减去本身的修正值.
因春节的习俗,春季开学日期存在很大的变数,阴历日期计算也复杂得多.但是,有一个规律,开学日期常在元宵节左右,因此,将元宵节的阳历日期计算出来,再用上述阳历日期算法即得出春季开学日期.
可以将中华农历网1900—2100 的春节日期取出[8],用数组的方法,编入程序中应用.Rucypli 提供了二进制算法程序nltoyl(nlYear,nlMonth,nlDay),实现1900—2049年的任何一天的农历到阳历的转换,代码请参考Rucypli 的算法程序[9].其方法是先计算出当年之前的所有农历年总天数,再计算出当年之前的月天数,再加上开始年日期,即得出元宵节的阳历日期.
阴历日期计算的结果,如果开课日期不是在星期一的,用式(2);是在星期一的,用式(3).
y 为阴历计算成阳历后的日期;7 为下一周的修正值.
在init 方法中,调用日期星期一函数,有3 个参数.第一个是年份,第二个是学期,第三个是模式值.顺序不能颠倒.年与模式值是数值型,学期是字符型.如果是自动获取开课日期的,模式值用0;如果用户在使用中改变了学期,重新获取开课日期的,模式值用1.Init 自动获取开课日期程序如下:
nYear=year(date())
cXueqi=″
nModelValue=0
this.value=daymondy(nYear,cXueqi,nModelValue)
将daymondy()函数保存在daymondy.prg 文件中或者在datemonday 的方法中新建一个daymondy 方法文件.在本程序中,首先获取计算机的当前日期,然后取出年、月、日的值,判断是在某一学期.如果是在第一学期,则月、日分别赋以9、1,年用当前的年号,合成年月日,用dow()函数找到当前的星期一那一天日期,即为开学日期.
假设是在第二学期的时间范围,需要考虑阴历(农历)的因素.第一步计算出当年正月十五的日期.第二步再用上述的方法,将计算出的日期转换成星期一的日期.
以上程序是自动获取计算机的当前日期,在实际操作中,用户有可能改变当前的年号,来查某一年、某一学期的课表,在程序中采用参数传递的方法来解决.
当用户在操作界面中修改了年号,先要判断是在某一学期,将选择的年号、学期传给实际参数处理.如果是在第二学期,则对年+1,是在第一学期,年用原值,最后合成年月日,即是开学的星期一日期.
对天、月的处理程序代码保存在Getmonday.prg 文件中,供daymondy()程序调用.Getmonday()程序有4个参数,分别表示星期几、日期、阴阳历值、日月值.返回值是数值型.
星期几用来判断是不是星期一,用第二个参数、第一个参数计算出星期一的这一天日期、月份;第三个参数用来判断是阳历还是阴历.如果元宵节这一天是星期一,按节日休假处理,即推迟一周上课,反之,将9月1日或元宵节前后三天左右的星期一作为开课(学)日期.第四个参数用来判断日、月值的返回,例如,9月1日是星期二,经过计算后,可能是在8月31日就开课了,要将月份改为8月份.
如果日期与实际不符,用户可能要修改日期.但是改的日期不一定是星期一,就需要提醒用户注意.解决的办法是在datemonday 类的InteractiveChange 中编写程序,用_xq=DOW(_DateValue,2)进行判断,当_xq≠1 时,显示报警信息,提醒用户注意.
将主要常量集中存入到CONSTEXT.H 文件中.本文中用到的常量如下:
**CONSTEXT.H
#DEFINE MSGTEXT1_LOC“参数设置不对!获取的是当前日期.请重新设置.”
#DEFINE MSGTEXT2_LOC“错误!请重新指定日期.您改的开课日期不是星期一,是”
#DEFINE DATEERROR_LOC“日期出错,本系统阴历日期只计算1900—2049年!”
#DEFINE MSGCAPTION_LOC“开课日期”
#DEFINE FIRSTXUEQI_LOC“第一学期”
#DEFINE XINQI1_LOC“星期一”
#DEFINE XINQI2_LOC“星期二”
#DEFINE XINQI3_LOC“星期三”
#DEFINE XINQI4_LOC“星期四”
#DEFINE XINQI5_LOC“星期五”
#DEFINE XINQI6_LOC“星期六”
#DEFINE XINQI7_LOC“星期日”
日期变换与修改日期不同,前者是操作环境条件发生改变,后者是用户修改日期.开课日期常与学期联合应用.用户在操作中,有可能不是选择当前的学期或当年的内容.如果选择了某学期,开课日期就要随之变化,使开课日期与学期相应保持一致.学期控件也是一种类生成的,其中的值通常有一定的备选项.学期的组成是由当年年份与次年年份加学期名构成的,如“2013—2014 第一学期或2012—2013 第二学期”.当用户选择“2013—2014 第一学期”时,开课日期显示的是“09/02/2013”,当选择的是“2012—2013 第二学期”时,显示的是“02/25/2013”日期.要使开课日期与学期发生变化能保持一至,在学期控件中的click 方法中,用以下代码:
**o.exchangedate
_xueqi=alltr(this.displayvalue)
nYear=val(substr(_xueqi,1,4))&&取出年份
cXueqi=alltr((substr(_xueqi,10))&&取出学期
nModelValue=1
thisform.datemonday1.value=daymondy(nYear,cXueqi,nModelValue)
将设计好的开课日期类保存到某一个类中,供开发程序用.当需要时,将其选放到表单的某一个位置,并在前面加上标签.当程序启动时,会自动将开课日期计算出来,呈现在用户面前.开课日期返回的值是日期型的阳历,格式用的是American(月/日/年)型.
开课日期界面如图1.
图1 开课日期界面(2013年下半年的开课日期)Fig.1 The interface course start date(the date of second half in 2013)
用开课日期类计算的近几年开课日期见表2.
表2 开课日期类计算的近几年开课日期Tab.2 The calculated course start date with date class in recent years
从2008年到2013年有12 个学期,实际的开课日期与表2 中的开课日期是一致的.准确率达100%.
有了计算机以后,课表就有了静态与动态之分.周课表就是一种半静态半动态的形式,它是按星期排的课程内容,每周重复,直至学期结束.第一周的第一次上课日期不确定,需要指定一个开始的日期,将日期与课表的内容固定下来,供教师或学生使用.课程进度表要么是静态的,要么是动态的,它是依靠周课表的星期所对应的日期生成的每个课时单位.开课日期类就是将周课表或课程进度表等做成动态的,进一步提高教务系统的自动化程度.
本文中的一周概念是指周一到周日.开课日期是指学生每一学期第一次上课的星期一日期,用它来作为计算本学期课表的起点.不是开始上课的日期,不在此内容之列.
寒暑假不属于国家法定节假日,国家没有明确规定假日有多少天.教育部的规定寒假一般是二十天,暑假一般是两个月,大部分是由各省教育厅根据当地的气候或天气情况而定的.学校的寒假期间一般与春节重迭,与元宵节邻近.在国务院的《全国年节及纪念日放假办法》中,没有元宵节,元宵节不纳入到节日内,也是人民的困惑.官方通用阳历与国际接轨,民间使用阴历传递传统习俗.开课日期兼顾了阳历、阴历的算法.
通过表2 发现,近几年元宵节有二个星期一,二个星期四.凡是元宵节在周四以前的,本周都要开学上课,凡是元宵节在周一的推迟一周开学,可能是因为开学第一天是节日,又要开学,又要过节,不如推迟一周开学.元宵节在星期四的,开学准备工作基本完成,不推迟.凡是“基点”在星期五的,不在本周内开学,推迟到下周一开学.这是因为距本周星期一有4 天时间,而距下周一只有3 天时间,符合基点左右三天的计算法则.另一方面,星期五是节日,与双休日相连,让教师、学生充分享受集中使用节假日的欢乐,不如就到下周开课,见表1.如2014年元宵节在2月14日,是星期五,系统计算的结果是2月17日开课;阳历如2000,2006,2017年的9月1日是星期五,推迟到下周一(9月4日)上课.
开课日期的控件属性设计为可修改,当与现实确有不符的情况下,用户按照“月/日/年”的格式可以修改.修改开课日期的值只能是某一个星期一日期,如果不是星期一日期,系统会报警,提醒用户注意.
查阅万年历,在1990—2049年间,元宵节没有在1月份的,大多数是在阳历2、3月份中,故在程序中没有考虑1月份会有元宵节.
开课日期除了用作课表起点计算外,在计算机排课算法中,将开课日期与教师等数据一起用函数递增的方法处理,也许能帮助解决排课时期的冲突问题[9-14],有待进一步研究.
本文用VFP 的类,将实际的开课日期上升为理论认识,开发出日期控件,将极有可能的开课日期呈现在用户面前.解决了过去由人们告诉计算机何时开课,而现在,是由计算机告诉我们何时开课.
凡是基点在星期四以前的,取本周的星期一为开课日期,其中,如果阴历基点是星期一的,推迟到下周一开课;凡是基点是在星期五以后的,取下一周星期一开课.从计算的结果可以看出,理论与实际实现了统一,从而证明这种算法是有效的,能将复杂的问题变得简单.本算法在教务软件开发领域具有广阔的应用前景,反过来说,也可以作为学校开课的参考依据.
[1]周发刚,阳镇涛.临床学院教务管理系统的开发与应用[J].中华医学教育杂志,2012,32(1):13-17.
[2]卢骁鹏,张 弦,周发刚.临床学院学时课表的开发与实践[J].中国医学教育技术,2012,26(3):311-315.
[3]黎 琼,周飞亚,阳镇涛,等.临床学院课程进度表的编排研究[J].中国医学教育技术,2013,27(5):553-557.
[4]MICROSOFT C.Visual Forpro 6.0 中文版语言参考手册[M].北京:希望电子出版社,1999:493-494.
[5]中华农历网.万年历[EB/OL].[2013-10-12].http://www.nongli.net/.
[6]Rucypli.CSDN 论坛[EB/OL].[2011-7-13].CSDN 论坛.http://topic.csdn.net/u/20110713/15/8d0010ac-e78f-41b5-89b5-f82073fa968b.html.
[7]黄 锟,陈志刚.混合算法在大学课程表问题中的应用研究[J].电脑与信息技术,2008,16(2):25-27.
[8]黄 辉,李虎雄,厉旭杰,等.基于Web 的高校办公自动化系统的研究与设计[J].现代计算机,2009,29(1):182-184.
[9]陶 滔,谢卫星.课表模型及排课算法应用[J].计算机系统应用,2011,20(2):198-201.
[10]丁德路,姜云飞.基于智能规划的时间表问题研究[J].小型微型计算机系统,2003(2):246-250.
[11]王帮海,李振柛.基于贪婪算法的自动排课表系统的研究与实现[J].计算机工程与设计,2012,29(18):4843-4846.
[12]吴金荣.关于大学课程表问题的研究[J].运筹与管理,2002,11(6):66-70.
[13]王秋芬,袁东锋.课程表编排问题的算法研究[J].计算机与现代化,2012,19(3):19-22.
[14]严李强,付建平,郭 鑫,等.基于数据库关系运算的排课算法设计[J].电脑知识与技术,2013,9(25):5665-5672.