找回密码
 加入
搜索
查看: 5518|回复: 11

[效率算法] 【已解决】关于排班表的算法问题

  [复制链接]
发表于 2013-3-28 12:29:33 | 显示全部楼层 |阅读模式
本帖最后由 xms77 于 2013-3-29 12:44 编辑

这个是公司的排班表,我们公司是4班2运转,4个班分别是:Team1,Team2,Team3,Team4, 每4个星期白晚班会轮换一次,比如说:Team1
第1周(FW1)是从星期天到星期二上白班,星期三到星期六休息
第2周(FW2)是从星期天到星期三上白班,星期四到星期六休息
第3周(FW3)是从星期天到星期二上白班,星期三到星期六休息
第4周(FW4)是从星期天到星期三上白班,星期四到星期六休息
第5周(FW5)倒班了,是从星期天到星期二上晚班班,星期三到星期六休息
第6周(FW6)是从星期天到星期三上晚班班,星期四到星期六休息
。。。
。。。
我想要的结果就是可以从某个日期和时间来推断是哪个班在上班?
刚刚开始思考,脑子里面很乱,没有什么头绪,不知道大家有没有好的idea?


几乎废了一夜,总算完成了自己的代码,代码很冗长,不如5楼大师的算法简洁。
#include <date.au3>
#include <array.au3>

Local $return = _Date2WeekYearTeamDayNight("2013-02-13 20:32:29")
If IsArray($return) Then _ArrayDisplay($return)

;偶数周,Team1,3是日,一,二,三上班; Team2,4是四,五,六上班
;奇数周,Team1,3是日,一,二上班; Team2,4是三,四,五,六上班
;Weeks4Turn的值是偶数:Team1夜班,Team3白班, Team2夜班,Team4白班
;Weeks4Turn的值是奇数:Team1白班,Team3夜班,Team2白班,Team4夜班

Func _Date2WeekYearTeamDayNight($iDateTime) ;日期时间格式:'2013-03-17 08:32:29'
        Local $AllInfo[3]
        $iDateTime = StringStripWS($iDateTime,3)
        if Not StringRegExp($iDateTime,"\d{4}[-/]\d{1,2}[-/]\d{1,2} \d{1,2}:\d{2}:\d{2}",0) Then Return SetError(-1)  ;返回日期格式错误
        Local $temp = StringRegExp($iDateTime,'(\d{4}[-/]\d{1,2}[-/]\d{1,2})',1)
        Local $date = $temp[0]
        Local $temp = StringRegExp($iDateTime,'(\d{1,2}:\d{2}:\d{2})',1)
        Local $time = $temp[0]
        Local $DayNight = _JudgeDayNightShift($time)
        If @error Then Return SetError(-1)  ;返回日期格式错误
        If $DayNight = "N-" Then    ;把日期转换为前一天的晚上
                $iDateTime = _DatetimeBack8Hours($iDateTime)
                MsgBox(0,"new datetime is ",$iDateTime)
                $temp = StringRegExp($iDateTime,'(\d{4}[-/]\d{1,2}[-/]\d{1,2})',1)
                $date = $temp[0]
                $temp = StringRegExp($iDateTime,'(\d{1,2}:\d{2}:\d{2})',1)
                $time = $temp[0]
        EndIf
        $DayNight = _JudgeDayNightShift($time)
        $FiscalYear = _Date2FiscalYear($date)
        $WeekName = _Date2WeekName($date)
        $weeks = _Data2Weeks($date)
        $Weeks4Turn = _DateCheck4WeeksTurn($date)
        $AllInfo[0] = "WW" & $weeks & $FiscalYear
        Local $DayNight = _JudgeDayNightShift($time)
        If Not @error Then
                Select
                        Case $DayNight = "D"        
                                $AllInfo[2] = "D"
                                Select 
                                        Case $Weeks4Turn = 0  ;偶数
                                                If $WeekName = 7 Or $WeekName = 1 Or $WeekName = 2 Or $WeekName = 4 Then   ;如果是星期日,一,二,三
                                                        $AllInfo[1] = "T3"
                                                Else
                                                        $AllInfo[1] = "T4"
                                                EndIf
                                        Case $Weeks4Turn = 1 ;奇数
                                                If $WeekName = 7 Or $WeekName = 1 Or $WeekName = 2  Then   ;如果是星期日,一,二,三
                                                        $AllInfo[1] = "T1"
                                                Else
                                                        $AllInfo[1] = "T2"
                                                EndIf
                                EndSelect
                        Case $DayNight = "N"
                                $AllInfo[2] = "N"
                                Select 
                                        Case $Weeks4Turn = 0  ;偶数周
                                                If $WeekName = 7 Or $WeekName = 1 Or $WeekName = 2 Or $WeekName = 4 Then   ;如果是星期日,一,二,三
                                                        $AllInfo[1] = "T1"
                                                Else
                                                        $AllInfo[1] = "T2"
                                                EndIf
                                        Case $Weeks4Turn = 1 ;奇数周
                                                If $WeekName = 7 Or $WeekName = 1 Or $WeekName = 2  Then   ;如果是星期日,一,二,三
                                                        $AllInfo[1] = "T3"
                                                Else
                                                        $AllInfo[1] = "T4"
                                                EndIf
                                EndSelect                
                EndSelect        
        EndIf
        Return $AllInfo
EndFunc

Func _JudgeDayNightShift($itime)
        $itime = StringStripWS($itime,3)
        If Not StringRegExp($itime,'\d{1,2}:\d{2}:\d{2}',0) Then Return SetError(-1)
        Local $splitime = StringSplit($itime,':')
        Select
                Case Int($splitime[1]) >= 7 And Int($splitime[1]) < 19
                        Return "D"
                Case Int($splitime[1]) >= 19
                        Return "N"
                Case Int($splitime[1]) < 7
                        Return "N-"
        EndSelect        
EndFunc

Func _Date2WeekName($idate)
        $idate= StringStripWS($idate,3)
        if Not StringRegExp($idate,"\d{4}[-/]\d{1,2}[-/]\d{1,2}",0) Then Return SetError(-1)  ;返回日期格式错误
        Local $splitdate = StringSplit($idate,"-")        
        Local $WeekName = _DateToDayOfWeekISO($splitdate[1],$splitdate[2],$splitdate[3])
        If $WeekName = 0 Then Return SetError(-2)   ;转换日期出错
        Return $WeekName
EndFunc

Func _Date2FiscalYear($idate)
        $idate= StringStripWS($idate,3)
        if Not StringRegExp($idate,"\d{4}[-/]\d{1,2}[-/]\d{1,2}",0) Then Return SetError(-1)  ;返回日期格式错误
        Local $splitdate = StringSplit($idate,"-")
        Local $year = Int(StringRight($splitdate[1],2)) 
        if Int($splitdate[2]) < 7 then
                Return "FY"& $year
        Else
                Return "FY"& $year +1
        EndIf
EndFunc

Func _Data2Weeks($idate)
        $idate= StringStripWS($idate,3)
        if Not StringRegExp($idate,"\d{4}[-/]\d{1,2}[-/]\d{1,2}",0) Then Return SetError(-1)  ;返回日期格式错误
        Local $iDateCalc = _DateDiff('d',"2012-6-30", $idate)
        Local $Weeks = Mod(Int($iDateCalc/7)+1,52)
        If $Weeks = 0 Then $Weeks = 52
        Return $Weeks
EndFunc

Func _DateCheck4WeeksTurn($idate)
        $idate= StringStripWS($idate,3)
        if Not StringRegExp($idate,"\d{4}[-/]\d{1,2}[-/]\d{1,2}",0) Then Return SetError(-1)  ;返回日期格式错误
        Local $iDateCalc2 = _DateDiff('d',"2012-7-15", "2013-3-24")
        Local $iWeeks4Turn = Mod(Int(Int($iDateCalc2/7)/4),2)
        Return $iWeeks4Turn
EndFunc

Func _DatetimeBack8Hours($iDateTime)
        $iDateTime = StringStripWS($iDateTime,3)
        if Not StringRegExp($iDateTime,"\d{4}[-/]\d{1,2}[-/]\d{1,2} \d{1,2}:\d{2}:\d{2}",0) Then Return SetError(-1)  ;返回日期格式错误
        Local $temp = StringRegExp($iDateTime,'(\d{4}[-/]\d{1,2}[-/]\d{1,2})',1)
        Local $date = $temp[0]
        Local $temp = StringRegExp($iDateTime,'(\d{1,2}:\d{2}:\d{2})',1)
        Local $time = $temp[0]
        Local $newDate = _DateAdd('D',-1,$date)
        Local $newTime = StringRegExpReplace($time,'\d{1,2}(:\d{2}:\d{2})','20$1')
        Return $newDate & ' ' & $newTime
EndFunc

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
发表于 2013-3-28 12:58:16 | 显示全部楼层
如果你有上面这个照片的电子版,可以考虑用图片分割然后识别颜色的方法把全年的数据识别出来,然后用软件读取指定天的指定班次。
 楼主| 发表于 2013-3-28 21:21:35 | 显示全部楼层
回复 2# sanmoking
想到先用_DateToDayOfWeekISO($iYear, $iMonth, $iDay)函数把日期转换为星期,然后怎么来区分周。继续开动脑筋~~~
发表于 2013-3-28 23:00:17 | 显示全部楼层
本帖最后由 sanmoking 于 2013-3-28 23:36 编辑

回复 3# xms77


    其实用我的那个排班表就能给你的班排出来,白天没仔细看你的轮班周期,晚上到家帮你排了一下,一共是8周一轮,共56天,所以只需要制作一个56天一轮的班表即可:

T1T3T2T4T1T3T2T4T1T3T2T4 T2T4T1T3T2T4T1T3T2T4T1T3T2T4T1T3

T1T3T2T4T1T3T2T4T1T3T2T4T1T3T2T4 T2T4T1T3T2T4T1T3T2T4T1T3

T1T3T2T4T1T3T2T4T1T3T2T4 T2T4T1T3T2T4T1T3T2T4T1T3T2T4T1T3

T1T3T2T4T1T3T2T4T1T3T2T4T1T3T2T4 T2T4T1T3T2T4T1T3T2T4T1T3

T3T1T2T4T3T1T2T4T3T1T2T4 T4T2T1T3T4T2T1T3T4T2T1T3T4T2T1T3

T3T1T2T4T3T1T2T4T3T1T2T4T3T1T2T4 T4T2T1T3T4T2T1T3T4T2T1T3

T3T1T2T4T3T1T2T4T3T1T2T4 T4T2T1T3T4T2T1T3T4T2T1T3T4T2T1T3

T3T1T2T4T3T1T2T4T3T1T2T4T3T1T2T4 T4T2T1T3T4T2T1T3T4T2T1T3


如果是四个team1的轮班都放一起的话,配置文件如下,因为界面位置太小,所以+代表白班,-代表晚班,没有的就是休息:
[data]
默认班次=xms77的班表
[xms77的班表]
轮班序列=|1+3-|1+3-|1+3-|2+4-|2+4-|2+4-|2+4-|1+3-|1+3-|1+3-|1+3-|2+4-|2+4-|2+4-|1+3-|1+3-|1+3-|2+4-|2+4-|2+4-|2+4-|1+3-|1+3-|1+3-|1+3-|2+4-|2+4-|2+4-|3+1-|3+1-|3+1-|4+2-|4+2-|4+2-|4+2-|3+1-|3+1-|3+1-|3+1-|4+2-|4+2-|4+2-|3+1-|3+1-|3+1-|4+2-|4+2-|4+2-|4+2-|3+1-|3+1-|3+1-|3+1-|4+2-|4+2-|4+2-
起始日期=2013/01/27



如果只是需要提取出TEAM1的班表的话,配置文件如下:
[data]
默认班次=xms77的班表-TEAM1
[xms77的班表-TEAM1]
轮班序列=|日班|日班|日班|休息|休息|休息|休息|日班|日班|日班|日班|休息|休息|休息|日班|日班|日班|休息|休息|休息|休息|日班|日班|日班|日班|休息|休息|休息|晚班|晚班|晚班|休息|休息|休息|休息|晚班|晚班|晚班|晚班|休息|休息|休息|晚班|晚班|晚班|休息|休息|休息|休息|晚班|晚班|晚班|晚班|休息|休息|休息
起始日期=2013/01/27





实际上附件里的配置文件都是像上图里面的一样,实际上是有备注的,上面帖子里面的为了美观,我把备注都去掉了。
有备注的轮班序列太长了,如下所示:
[示例班表]
轮班序列=|日班@@备注#crlf换了一行|晚班@@#crlf第一行空,这是第二行#crlf第三行|休息@@休息就不用备注了吧#crlf好吧又换了一行
起始日期=2013/01/27

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×

评分

参与人数 1金钱 +50 收起 理由
xms77 + 50 谢谢熊哥的关注和支持~

查看全部评分

发表于 2013-3-29 00:48:19 | 显示全部楼层
本帖最后由 zldfsz 于 2013-3-29 01:03 编辑

#include <Date.au3>
$day = InputBox("输入要查询的日期", "输入要查询的日期,格式为YYYY/MM/DD", _NowCalcDate())
Dim $FirstDay = '2012/06/30';第一周第一天的日期
;以下是 用1代表Team1白班,Team3夜班;
;        用-1代表Team3白班,Team1夜班
;        用2代表Team2白班,Team4夜班
;        用-2代表Team4白班,Team2夜班
Dim $s[28]=[ 2, 1, 1, 1, 2, 2, 2, _;第一周的排班表 
                    2, 1, 1, 1, 1, 2, 2, _;第二周的排班表 
                    2,-1,-1,-1,-2,-2,-2, _;第三周的排班表 
                   -2,-1,-1,-1,-1,-2,-2]  ;第四周的排班表 
Dim $ss[56]
;由前4周转换为前8周的排班表
For $i = 0 To 55
        If $i > 27 Then
                $ss[$i] = -1 * $s[$i - 28]
        Else
                $ss[$i] = $s[$i]
        EndIf
Next
$iDateCalc = _DateDiff('D', $FirstDay, $day)
$j = $ss[Mod($iDateCalc, 56)]
Switch $j
        Case 1
                $result = $day & " Team1白班,Team3夜班,Team2、Team4休息"
        Case -1
                $result = $day & " Team3白班,Team1夜班,Team2、Team4休息"
        Case 2
                $result = $day & " Team2白班,Team4夜班,Team1、Team3休息"
        Case -2
                $result = $day & " Team4白班,Team2夜班,Team1、Team3休息"
EndSwitch
MsgBox(4096, "", $result)

评分

参与人数 1金钱 +50 收起 理由
xms77 + 50 谢谢关注和帮忙~

查看全部评分

 楼主| 发表于 2013-3-29 10:35:40 | 显示全部楼层
回复 5# zldfsz
谢谢大师,很简洁的代码。
 楼主| 发表于 2013-3-29 11:28:05 | 显示全部楼层
回复 4# sanmoking
总算完成了,我的算法比较复杂,废了一夜的脑细胞!
 楼主| 发表于 2013-3-29 11:33:32 | 显示全部楼层
回复 5# zldfsz
我的算法太复杂了,但是功能还是可以的,真他妈累人啊
发表于 2013-3-29 15:11:48 | 显示全部楼层
回复 4# sanmoking


    大哥能介绍是怎么写的吗?
发表于 2013-3-29 15:42:30 | 显示全部楼层
回复 9# sniperone

我那个日历是适用于任何有循环的轮班表。
类似于计算某一天是星期几的方法(相当于一轮7天)。
发表于 2013-3-30 23:02:13 | 显示全部楼层
回复 8# xms77

呵呵,这种问题找到规律就好办了,才发现我第一的单词都写错了,英语不好就这样,发现还不能编辑,如果A版看到了帮忙改一下
发表于 2013-4-2 18:59:59 | 显示全部楼层
很不错的东西,顺便学习下各种算法
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-11-15 06:58 , Processed in 0.092410 second(s), 29 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表