Zum Berechnen hab ich die Date Funktionen genutzt. Dazu muss man ggf. das Datum dazurechnen und kann automatisch addieren.
Ich hab die Pausen als Array umgesetzt. Es können also theoretisch beliebig viele Pausen zur Berechnung genutzt werden. Dafür müsste man aber ne Listview für die Pausen nutzen, oder so.
Selbiges auch für die Soll-Zeit. Der Code unterstützt für jeden Wochentag eine eigene Soll-Zeit. Momentan wird die eine von der Gui für alle Wochentage benutzt.
Ich hoffe, es ist ausreichend kommentiert.
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Date.au3>
; Gui parameters. Edit these to change the window
Global $iWidth = 660, $iHeight = 260, $iDefSpace = 10, $iColCount = 2, $iCtrlHeight = 30
; Array of all inputs. [0] Name, [1] ButtonCtrl (or Null for labels), [2] InputCtrl, [3] complete date value, [4] initialValue
Global $arTimerInputs = [ _
["Ankunft", -1, -1, 0, ""], _
["Pause Begin", -1, -1, 0, ""], _
["Pause Ende", -1, -1, 0, ""], _
["Feierabend", -1, -1, 0, ""], _
["Soll-Arbeitzeit", Null, -1, 0, "07:45"] _
]
; Array of all information. [0] LabelText, [1] Label to display data
Global $arInformation = [ _
["Länge der Pause", -1], _
["Überstunden heute", -1], _
["Tatsächliche Arbeitszeit", -1], _
["Frühester Feierabend", -1], _
["Spätester Feierabend", -1], _
["Pause nach 6 Stunden", -1] _
]
; Init some variables
Global $iDefCtrlSpace = $iDefSpace/2, $iColWidth = ($iWidth-($iColCount+1)*$iDefSpace)/$iColCount
Global $arBreaks[1][2]
Global $arTargetTimes[7] ;1=sun to 7=sat
Global $sCurrentDay = _NowCalcDate(), $iLastMinute = -1
;create gui
Global $iMainGui = GUICreate("Zeitrechner", $iWidth, $iHeight)
GUISetFont(12, 400, 0, "DM Sans", $iMainGui)
; generate date control
Global $iDateWidth = 300
Global $iCtrlDate = GUICtrlCreateDate($sCurrentDay, $iDefSpace+($iWidth-2*$iDefSpace-$iDateWidth)/2, $iDefSpace, $iDateWidth, $iCtrlHeight)
GUICtrlSetState($iCtrlDate, $GUI_DISABLE) ; remove this line to enable date changes
; generate inputs
Global $iCtrlInputTop = $iDefSpace+$iCtrlHeight+$iDefCtrlSpace ; calculate the top to start the input controls
For $i=0 To UBound($arTimerInputs)-1 Step 1
Local $arPos = _calcCtrlPos(UBound($arTimerInputs), $i, $iCtrlInputTop) ; calculate left and top value for controls
Local $iWidthFirst = ($iColWidth-$iDefCtrlSpace)*0.6 ; width of the first control (Button/Label) in the column
Local $iWidthSecond = $iColWidth-$iWidthFirst-$iDefCtrlSpace ; width of the second control (Input) in the column
If Not IsKeyword($arTimerInputs[$i][1]) Then ; Create Button or Label. Depending on -1 or Null in the control field
$arTimerInputs[$i][1] = GUICtrlCreateButton($arTimerInputs[$i][0], $arPos[0], $arPos[1], $iWidthFirst, $iCtrlHeight)
Else
GUICtrlCreateLabel($arTimerInputs[$i][0], $arPos[0], $arPos[1]+$iCtrlHeight/4, $iWidthFirst, $iCtrlHeight, BitOR($SS_NOTIFY, $ES_CENTER))
EndIf
; generate input field
$arTimerInputs[$i][2] = GUICtrlCreateInput($arTimerInputs[$i][4], $arPos[0]+$iWidthFirst+$iDefCtrlSpace, $arPos[1], $iWidthSecond, $iCtrlHeight, BitOR($GUI_SS_DEFAULT_INPUT, $ES_CENTER))
Next
; generate labels for calculated information
Global $iCtrlInfoTop = $iCtrlInputTop+Int((UBound($arTimerInputs)+1)/$iColCount)*($iCtrlHeight+$iDefCtrlSpace)+$iDefCtrlSpace*2 ; calculate the top to start the info controls
For $i=0 To UBound($arInformation)-1 Step 1
Local $arPos = _calcCtrlPos(UBound($arInformation), $i, $iCtrlInfoTop) ; calculate left and top value for controls
Local $iWidthFirst = ($iColWidth-$iDefCtrlSpace)*0.6 ; width of the first control (Label) in the column
Local $iWidthSecond = $iColWidth-$iWidthFirst-$iDefCtrlSpace ; width of the second value control (Label) in the column
GUICtrlCreateLabel($arInformation[$i][0], $arPos[0], $arPos[1], $iWidthFirst, $iCtrlHeight) ; create information description ctrl
$arInformation[$i][1] = GUICtrlCreateLabel("test", $arPos[0]+$iWidthFirst+$iDefCtrlSpace, $arPos[1], $iWidthSecond, $iCtrlHeight, BitOR($GUI_SS_DEFAULT_INPUT, $ES_CENTER)) ; create value label
Next
GUIRegisterMsg($WM_COMMAND, '_WM_COMMAND')
GUISetState(@SW_SHOW, $iMainGui)
While 1
$iMsg = GUIGetMsg()
Switch $iMsg
Case $GUI_EVENT_CLOSE
Exit
Case $iCtrlDate ; change the date (if not disabled)
$sCurrentDay = GUICtrlRead($iCtrlDate)
ConsoleWrite($sCurrentDay)
EndSwitch
; check for button pressed
For $i=0 To UBound($arTimerInputs)-1 Step 1
If $iMsg = $arTimerInputs[$i][1] Then
GUICtrlSetData($arTimerInputs[$i][2], _NowTime(4))
_calc()
EndIf
Next
; automatically update all information every minute
If $iLastMinute<>@MIN Then
$iLastMinute = @MIN
_calc()
EndIf
WEnd
Func _calc()
; fetch timer dates
For $i=0 To UBound($arTimerInputs)-1 Step 1
$arTimerInputs[$i][3] = _timeToDate(GUICtrlRead($arTimerInputs[$i][2]))
Next
; init values
Local $iWorkTimeReal = Null, $iOvertime = Null, $sEndEarly = Null, $sEndLate = Null, $sBreak6Hours = Null
Local $sStart = $arTimerInputs[0][3]
Local $sEnd = $arTimerInputs[3][3]
If IsKeyword($sEnd) Then $sEnd = _NowCalc() ; If the end is not known, it is set to the current time
; load breaks (currently only one break (with button+input))
$arBreaks[0][0] = $arTimerInputs[1][3]
$arBreaks[0][1] = $arTimerInputs[2][3]
Local $iBreakLength = 0
; load the target time, currently from the input
Local $arTargetTimeTmp = StringRegExp($arTimerInputs[4][3], "^\d{4}/\d{2}/\d{2} (\d{2}):(\d{2}):\d{2}$", 2)
If Not @error Then
Local $iTargetTimeTmp = Int($arTargetTimeTmp[1])*60+Int($arTargetTimeTmp[2])
For $i = 0 To UBound($arTargetTimes)-1 Step 1
$arTargetTimes[$i] = $iTargetTimeTmp
Next
EndIf
; Accumulate all break lengths
For $i = 0 To UBound($arBreaks)-1 Step 1
If Not IsKeyword($arBreaks[$i][0]) And Not IsKeyword($arBreaks[$i][1]) Then
$iBreakLength+=_DateDiff("n", $arBreaks[$i][0], $arBreaks[$i][1])
ElseIf Not IsKeyword($arBreaks[$i][0]) And $i=UBound($arBreaks)-1 Then ; If the end of the last break is not known, it is assumed to end now
$iBreakLength+=_DateDiff("n", $arBreaks[$i][0], _NowCalc())
EndIf
Next
; calculate work time if possible
If Not IsKeyword($sStart) And Not IsKeyword($sEnd) Then $iWorkTimeReal=_DateDiff("n", $sStart, $sEnd)
; calculate target time if possible
Local $arDate = StringRegExp($sCurrentDay, "^(\d{4})/(\d{2})/(\d{2})$", 2)
Local $iTargetTime = $arTargetTimes[_DateToDayOfWeek($arDate[1], $arDate[2], $arDate[3])-1]
; calculate overtime if possible
If Not IsKeyword($iWorkTimeReal) And Not IsKeyword($iTargetTime) Then $iOvertime = $iWorkTimeReal - $iTargetTime ; + $iBreakLength ; if you want to calculate the break time into the overtime
; calculate early end if possible
If Not IsKeyword($sStart) And Not IsKeyword($iTargetTime) Then $sEndEarly = _DateAdd("n", $iTargetTime-$iBreakLength, $sStart)
; calculate late end if possible
If Not IsKeyword($sStart) And Not IsKeyword($iTargetTime) Then $sEndLate = _DateAdd("n", $iTargetTime+$iBreakLength, $sStart)
; calculate break hours if possible
If Not IsKeyword($sStart) Then $sBreak6Hours = _DateAdd("h", 6, $sStart)
; Update gui with calculated information
_updateCtrlValue($arInformation[0][1], "_minToTime", $iBreakLength)
_updateCtrlValue($arInformation[1][1], "_minToTime", $iOvertime)
_updateCtrlValue($arInformation[2][1], "_minToTime", $iWorkTimeReal)
_updateCtrlValue($arInformation[3][1], "_dateToTime", $sEndEarly)
_updateCtrlValue($arInformation[4][1], "_dateToTime", $sEndLate)
_updateCtrlValue($arInformation[5][1], "_dateToTime", $sBreak6Hours)
EndFunc
Func _updateCtrlValue($iCtrl, $sFunc, $val)
If Not IsKeyword($val) Then ; set value if it could be calculated. Reset otherwise
GUICtrlSetData($iCtrl, Call($sFunc, $val))
Else
GUICtrlSetData($iCtrl, "")
EndIf
EndFunc
Func _minToTime($iMin)
return ($iMin<0?"- ":"")&StringFormat("%02d:%02d", Abs(Int($iMin/60)), Abs(Mod($iMin, 60)))
EndFunc
Func _timeToDate($sTime)
If Not StringRegExp($sTime, "^\d{2}:\d{2}$") Then return Null
return _NowCalcDate()&" "&$sTime&":00"
EndFunc
Func _dateToTime($sDate)
return _DateTimeFormat($sDate, 4)
EndFunc
Func _calcCtrlPos($iArSize, $index, $iSpaceTop) ; calculate position of control in grid
Local $arPos = [$iDefSpace+($iColWidth+$iDefCtrlSpace)*(Int($index/($iArSize/$iColCount))), _ ; calculate left value
$iSpaceTop+($iCtrlHeight+$iDefCtrlSpace)*Int(Mod($index, $iArSize/$iColCount))] ; calculate top value
return $arPos
EndFunc
; check for input changes
Func _WM_COMMAND($hWnd, $Msg, $wParam, $lParam)
Local $id = BitAND($wParam, 0x0000FFFF)
Local $code = BitShift($wParam, 16)
If $code = $EN_UPDATE Then
For $i=0 To UBound($arTimerInputs)-1 Step 1
If $id = $arTimerInputs[$i][2] Then _checkCtrl($arTimerInputs[$i][2])
Next
EndIf
Return $GUI_RUNDEFMSG
EndFunc
Func _checkCtrl($iCtrl)
Local $sData = GUICtrlRead($iCtrl)
If StringRegExp($sData, "^\d{2}:\d{2}$") OR $sData="" Then ; if the input is correct, calculate
GUICtrlSetBkColor($iCtrl, 0xFFFFFF)
_calc()
Else ; set red background otherwise
GUICtrlSetBkColor($iCtrl, 0xFF9999)
EndIf
EndFunc
Alles anzeigen