Что нового

Детальный подсчёт рабочих часов

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Версия AutoIt: 3.3.10.2

Описание:
Требуется разработать функцию, которая смогла бы детально подсчитать процентное соотношение рабочих часов.
Известно что на многих предприятиях и фирмах (так по крайней мере у нас в Израиле), за дополнительные часы работы есть доплата, также доплата полагается и за работу в выходные и праздники, вот собственно это и следует подсчитать по определённому алгоритму.
Я уже сделал набросок того как я это вижу, и что нужно учитывать при подсчёте.
В наброске ниже есть уже рабочие вспомогательные функции, которые мне помогли написать в моей же теме "Подсчёт разницы времени с учётом захода солнца", за что ребятам большое спасибо.

Пытался сделать сам, честно, но мозг видимо уже не тот, заржавел я немного :whistle:...

Вот несколько примеров, где показано наглядно при каком раскладе какой должен быть результат (обратите также внимание, что параметр $bHolidayIn иногда меняется, вместе с ним меняется и параметр $sHolidayInOutTime):

№1
Код:
;Тут "Total hours" должно быть 16 (всего часов)
;100% должно быть 8
;125% должно быть 2
;150% это 0, поскольку $vExtraPaymentAbove150 = True, свыше 10-ти часов идёт надбавка в 50%, а к этому времени идёт работа в праздничные часы, поэтому по сути остальные часы это 200%.
;175 это 0, см. выше
;200% должно быть 6
$bHolidayIn = True ;Это значит что праздник заходит (начинается)
_PrecentCalc('07:00', '23:00', $bHolidayIn, $sHolidayInOutTime, $vExtraPaymentAbove150)


№2
Код:
;Тут "Total hours" должно быть 10 (всего часов)
;100% должно быть 4
;125% должно быть 0 (от 13:00 до 17:00 (время захода праздника) 4 часа, поэтому остальное уже надбавка в 50%)
;150% это 4, поскольку в остальные часы идёт надбавка в 25%, как часы переработки (свыше 8-и).
;175 должно быть 2 (те самые часы переработки, где 25% добавляются к 50% т.к уже пошло время работы в праздничные часы)
;200% это 0, надбавки уже нет
$bHolidayIn = True ;Это значит что праздник заходит (начинается)
_PrecentCalc('13:00', '23:00', $bHolidayIn, $sHolidayInOutTime, $vExtraPaymentAbove150)


№3
Код:
;Тут "Total hours" должно быть 16 (всего часов)
;100% должно быть 0
;125% должно быть 0
;150% это 16, т.е все часы, т.к от 07:00 (начало работы) и до 17:00 (время "выхода" праздника), это часы в 150%, а дальше уже свыше 10-ти часов, т.е это часы переработки где идёт надбавка в 50%, т.е тоже 150%
;175 должно быть 0
;200% должно быть 0
$bHolidayIn = False ;Это значит что праздник выходит (заканчивается)
_PrecentCalc('07:00', '23:00', $bHolidayIn, $sHolidayInOutTime, $vExtraPaymentAbove150)


Вот собственно сам набросок скрипта для тестирования и построения функции подсчёта:
Код:
Global $vExtraPayment125 = 9 ;Оплата в 125% если число раб. часов достигло этого значения
Global $vExtraPayment150 = 10 ;Оплата в 150% если число раб. часов достигло этого значения
Global $vHolidayInTime = '17:00' ;Время "захода" (начало) праздника (время захода солнца)
Global $vHolidayOutTime = '17:00' ;Время "выхода" (конец) праздника (время захода солнца)

Global $vExtraPaymentAbove150 = True ;Учитывать подсчёт экстра-часов (свыше 150%), в некоторых случаях это не нужно учитывать
Global $bHolidayIn = True ;Указывает на то, начинается или нет время с которого следует считать часы работы как праздн. часы (время указывается в след. параметре)
Global $sHolidayInOutTime = $bHolidayIn ? $vHolidayInTime : $vHolidayOutTime

$aPrecentCalc = _PrecentCalc('07:00', '23:00', $bHolidayIn, $sHolidayInOutTime, $vExtraPaymentAbove150)
	
MsgBox(64, @ScriptName, _
	'Total hours: ' & $aPrecentCalc[0] & @CRLF & @CRLF & _
	'100%: ' & $aPrecentCalc[1] & @CRLF & _
	'125%: ' & $aPrecentCalc[2] & @CRLF & _
	'150%: ' & $aPrecentCalc[3] & @CRLF & _
	'175%: ' & $aPrecentCalc[4] & @CRLF & _
	'200%: ' & $aPrecentCalc[5] _
	)

;Функция должна вернуть расчёт часов разделённые на 100%, 125%, и т.д., с учётом начала праздника (по часам) или его завершения (выход)
;Параметры:
;$sTimeStart - время начала работы
;$sTimeEnd - время завершения работы
;$bHolidayIn - указывает на то, начинается или нет время с которого следует считать часы работы как праздн. часы (время указывается в след. параметре)
;$sHolidayTime - время начала или завершения праздничных часов, если 0 то все часы должны считаться обычно (в соот-вий с таблицей часов переработки)
;$bAbove150 - указывает на то, следует ли считать часы переработки (или праздн. часы) свыше 150%.
Func _PrecentCalc($sTimeStart, $sTimeEnd, $bHolidayIn, $sHolidayTime, $bAbove150 = True)
	Local $iTotalHours = 0
	Local $i100 = 0, $i125 = 0, $i150 = 0, $i175 = 0, $i200 = 0
	
	;???
	
	Local $aRet[6] = [$iTotalHours, $i100, $i125, $i150, $i175, $i200]
	Return $aRet
EndFunc

;Функция возвращает:
;$aArr[0] - всего часов между $sTimeStart и $sTimeEnd
;$aArr[1] - время ДО заката ($sTimeSunset), т.е это по сути время начала или завершения праздника
;$aArr[2] - время ПОСЛЕ заката ($sTimeSunset), "..."
Func _TimeCalc($sTimeStart, $sTimeEnd, $sTimeSunset)
	Local $mTimeStart, $mTimeEnd, $iTotalMinutes, $iTotalHours, $mTimeSunset, $iTimeInMinutes
	Local $iTimeBeforeSunsetMinutes, $iTimeAfterSunsetMinutes, $iTimeBeforeSunset, $iTimeAfterSunset
	
	$mTimeStart = _TimeInMinutes($sTimeStart)
	$mTimeEnd = _TimeInMinutes($sTimeEnd)
	
	If $mTimeEnd < $mTimeStart Then
		$mTimeEnd += 1440
	EndIf
	
	$iTotalMinutes = $mTimeEnd - $mTimeStart
	$iTimeInMinutes = _TimeInMinutes($sTimeSunset)
	
	If $iTimeInMinutes Then
		$mTimeSunset = $iTimeInMinutes
		$iTimeBeforeSunsetMinutes = _TimeBetween($mTimeStart, $mTimeSunset) - _TimeBetween($mTimeEnd, $mTimeSunset)
		$iTimeAfterSunsetMinutes = $iTotalMinutes - $iTimeBeforeSunsetMinutes
		$iTimeBeforeSunset = Round(Round($iTimeBeforeSunsetMinutes / 30, 1) / 2, 2)
		$iTimeAfterSunset = Round(Round($iTimeAfterSunsetMinutes / 30, 1) / 2, 2)
	Else
		$iTimeBeforeSunset = 0
		$iTimeAfterSunset = 0
	EndIf
	
	$iTotalHours = Round(Round($iTotalMinutes / 30, 1) / 2, 2)
	
	Local $aRet[3] = [$iTotalHours, $iTimeBeforeSunset, $iTimeAfterSunset]
	Return $aRet
EndFunc

;Функция переводит время в минуты
Func _TimeInMinutes($sTimeParam)
	Return Execute(StringReplace($sTimeParam, ':', '*60+'))
EndFunc

;Функция возвращает разницу между минутами времени
Func _TimeBetween($iTime1, $iTime2)
	Return($iTime1 < $iTime2 ? $iTime2 - $iTime1 : 0)
EndFunc


Примечания:
Если $sHolidayInOutTime не указан (0), то считать все часы нужно без учёта захода или выхода праздника, т.е по обычной схеме подсчёта часов и часов переработки.
В наброске нужно доделать (точнее проработать) функцию _PrecentCalc.

Задача очень интересная, и я уверен что есть несложное решение, но мозг кипел пока я сам пытался это решить.
Спасибо за внимание.
 

ra4o

AutoIT Гуру
Сообщения
1,165
Репутация
246
Позвольте уточнить :
- Какая дискретность отсчета часов (кратно часу, пол-часа, по минутно) ?
- Исходя из предыдущего вопроса - может ли быть время задано с минутами ?
- Может ли начало и конец рабочей смены находится в разных сутках ( например начало в 21-00, окончание в 6-00 следующего дня) ?
- Какая максимальная продолжительнось смены ? (Возможно ли более суток ? )
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
ra4o [?]
Какая дискретность отсчета часов (кратно часу, пол-часа, по минутно) ?
Поминутно.

Исходя из предыдущего вопроса - может ли быть время задано с минутами ?
Да.

Может ли начало и конец рабочей смены находится в разных сутках ( например начало в 21-00, окончание в 6-00 следующего дня) ?
Может.

Какая максимальная продолжительнось смены ? (Возможно ли более суток ? )
Максимально это 23:59, хотя и это уже считается незаконным )), у нас столько нельзя работать.

Обратите внимание на функцию _TimeCalc, которая во многом должна упростить задачу, она возвращает время до и после заката, а также общее число часов, с учётом минут естественно.
И ещё, если время начала работы указано такое же как и время завершения (допустим 08:00 и 08:00), то это считается как 0 (для всех параметров), т.е тут как бы и нечего считать.
 

ra4o

AutoIT Гуру
Сообщения
1,165
Репутация
246
Ещё уточнение:
- Переработка от 8 до 10 часов +25% вне праздика, в праздник 25+50=75% ?
- Переработка свыше 10 часов при $vExtraPaymentAbove150 = false : +25% , true: +50% (вне праздника ) и 75% и 200% соответственно в праздник ?
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
ra4o [?]
Переработка от 8 до 10 часов +25% вне праздика, в праздник 25+50=75% ?
Не совсем, от 8 до 10 и в праздник это +25, просто если "эти" от 8 до 10 приходятся на время праздника, то считается как 175% всего.
Т.е прибавлять к текущему уровню оплаты.

Переработка свыше 10 часов при $vExtraPaymentAbove150 = false : +25% , true: +50% (вне праздника ) и 75% и 200% соответственно в праздник ?
Не уверен что понял, но если $vExtraPaymentAbove150 = false, то значений в 175% и 200% быть не может, они все считаются как 150%.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Вроде получилось:

Код:
Global $vExtraPayment125 = 8 ;Оплата в 125% если число раб. часов достигло этого значения
Global $vExtraPayment150 = 10 ;Оплата в 150% если число раб. часов достигло этого значения

Global $vHolidayInTime = '17:00' ;Время "захода" (начало) праздника (время захода солнца)
Global $vHolidayOutTime = '17:00' ;Время "выхода" (конец) праздника (время захода солнца) ; Совпадает с предыдущим параметром чтобы не путаться

Global $vExtraPaymentAbove150 = True ;Учитывать подсчёт экстра-часов (свыше 150%), в некоторых случаях это не нужно учитывать
Global $bHolidayIn = True ;Указывает на то, начинается или нет время с которого следует считать часы работы как праздн. часы (время указывается в след. параметре)
Global $sHolidayInOutTime = $bHolidayIn ? $vHolidayInTime : $vHolidayOutTime

$sTimeStart = '07:00'
$sTimeEnd = '23:00'

$aPrecentCalc = _PrecentCalc($sTimeStart, $sTimeEnd, $bHolidayIn, $sHolidayInOutTime, $vExtraPaymentAbove150)

$sRes = _
	'Holiday ' & ($bHolidayIn ? 'in' : 'out') & ' time: ' & $sHolidayInOutTime & @CRLF & _
	'From ' & $sTimeStart & ' to ' & $sTimeEnd & @CRLF & @CRLF & _
	'Total: ' & $aPrecentCalc[0] & @CRLF & _
	'Before sunset: ' & $aPrecentCalc[6] & @CRLF & _
	'After sunset: ' & $aPrecentCalc[7] & @CRLF & @CRLF & _
    '100%: ' & $aPrecentCalc[1] & @CRLF & _
    '125%: ' & $aPrecentCalc[2] & @CRLF & _
    '150%: ' & $aPrecentCalc[3] & @CRLF & _
    '175%: ' & $aPrecentCalc[4] & @CRLF & _
    '200%: ' & $aPrecentCalc[5]

;MsgBox(64, @ScriptName, $sRes)
ConsoleWrite($sRes & @CRLF)

;Функция должна вернуть расчёт часов разделённые на 100%, 125%, и т.д., с учётом начала праздника (по часам) или его завершения (выход)
;Параметры:
;$sTimeStart - время начала работы
;$sTimeEnd - время завершения работы
;$bHolidayIn - указывает на то, начинается или нет время с которого следует считать часы работы как праздн. часы (время указывается в след. параметре)
;$sHolidayTime - время начала или завершения праздничных часов, если 0 то все часы должны считаться обычно (в соот-вий с таблицей часов переработки)
;$bAbove150 - указывает на то, следует ли считать часы переработки (или праздн. часы) свыше 150%.
Func _PrecentCalc($sTimeStart, $sTimeEnd, $bHolidayIn, $sHolidayTime, $bAbove150 = True)
	Local $aTimeCalc = _TimeCalc($sTimeStart, $sTimeEnd, $sHolidayTime)
	Local $i100 = 0, $i125 = 0, $i150 = 0, $i175 = 0, $i200 = 0, $i100To150 = 0
	
	Local $iTotalHours = $aTimeCalc[0]
	Local $iBeforeSunsetHours = $aTimeCalc[1]
	Local $iAfterSunsetHours = $aTimeCalc[2]
	
	Local Const $iExtraDiff = ($vExtraPayment150 - $vExtraPayment125)
	
    If $sHolidayTime == '0' Or $sHolidayTime == '' Then
		$i100 = (($iTotalHours >= $vExtraPayment125) ? $vExtraPayment125 : $iTotalHours)
		$i125 = (($iTotalHours >= ($i100 + $iExtraDiff)) ? $iExtraDiff : ($iTotalHours - $i100))
		$i150 = ($iTotalHours - $i125 - $i100)
	Else
		Switch $bHolidayIn
			Case True
				$i100 = (($iBeforeSunsetHours > $vExtraPayment125) ? $vExtraPayment125 : $iBeforeSunsetHours)
				$i125 = ((($iBeforeSunsetHours - $i100) > $iExtraDiff) ? $iExtraDiff : ($iBeforeSunsetHours - $i100))
				
				$i150 = ((($i100 + $i125) < $iBeforeSunsetHours) ? ($iBeforeSunsetHours - ($i100 + $i125)) : 0)
				$i150 += ((($i100 + $i125) < $vExtraPayment125) ? ($vExtraPayment125 - ($i100 + $i125)) : 0)
				$i150 = ((($i150 + $i100 + $i125) > $iTotalHours) ? ($iTotalHours - ($i100 + $i125)) : $i150)
				
				$i100To150 = ($i100 + $i125 + $i150)
				
				$i175 = ($iTotalHours - $i100To150)
				$i175 = (($i175 + $i100To150) > $iTotalHours ? $iTotalHours - $i100To150 : ($i175 > $iExtraDiff ? $iExtraDiff : $i175))
				$i175 -= ((($i175 + $i125) > $iExtraDiff) ? ((($i175 - $i125) < 0) ? $i175 : $i125) : 0)
				
				$i200 = ($iTotalHours - ($i100To150 + $i175))
			Case Else
				$i100 = (($iBeforeSunsetHours < $vExtraPayment125) ? ((($vExtraPayment125 > $iTotalHours) ? $iTotalHours : $vExtraPayment125) - $iBeforeSunsetHours) : 0)
				
				$i125 = (($iBeforeSunsetHours < $vExtraPayment150) ? ((($vExtraPayment150 > $iTotalHours) ? $iTotalHours : $vExtraPayment150) - $iBeforeSunsetHours) : 0)
				$i125 = (($i125 > $iExtraDiff) ? $iExtraDiff : $i125)
				$i125 = ((($i125 + $i100) > $iTotalHours) ? ($iTotalHours - $i100) : $i125)
				$i125 = ((($i125 + $i100 + $iBeforeSunsetHours) > $iTotalHours) ? ($iAfterSunsetHours - $i100) : $i125)
				
				$i150 = (($iTotalHours - $i100 - $i125) - (($iBeforeSunsetHours > $vExtraPayment125) ? ($iBeforeSunsetHours - $vExtraPayment125) : 0))
				
				$i100To150 = ($i100 + $i125 + $i150)
				
				$i175 = ($iTotalHours - $i100To150)
				$i175 = (($i175 + $i100To150) > $iTotalHours ? $iTotalHours - $i100To150 : ($i175 > $iExtraDiff ? $iExtraDiff : $i175))
				
				$i200 = ($iTotalHours - ($i100To150 + $i175))
		EndSwitch
		
		If Not $bAbove150 Then
			$i150 += $i175 + $i200
			$i175 = 0
			$i200 = 0
		EndIf
	EndIf
    
    Local $aRet[8] = [$iTotalHours, Round($i100, 2), Round($i125, 2), Round($i150, 2), Round($i175, 2), Round($i200, 2), $iBeforeSunsetHours, $iAfterSunsetHours]
    Return $aRet
EndFunc

;Функция возвращает:
;$aArr[0] - всего часов между $sTimeStart и $sTimeEnd
;$aArr[1] - время ДО заката ($sTimeSunset), т.е это по сути время начала или завершения праздника
;$aArr[2] - время ПОСЛЕ заката ($sTimeSunset), "..."
Func _TimeCalc($sTimeStart, $sTimeEnd, $sTimeSunset)
    Local $mTimeStart, $mTimeEnd, $iTotalMinutes, $iTotalHours, $mTimeSunset, $iTimeInMinutes
    Local $iTimeBeforeSunsetMinutes, $iTimeAfterSunsetMinutes, $iTimeBeforeSunset, $iTimeAfterSunset
    
    $mTimeStart = _TimeInMinutes($sTimeStart)
    $mTimeEnd = _TimeInMinutes($sTimeEnd)
    
    If $mTimeEnd < $mTimeStart Then
        $mTimeEnd += 1440
    EndIf
    
    $iTotalMinutes = $mTimeEnd - $mTimeStart
    $iTimeInMinutes = _TimeInMinutes($sTimeSunset)
    
    If $iTimeInMinutes Then
        $mTimeSunset = $iTimeInMinutes
        $iTimeBeforeSunsetMinutes = _TimeBetween($mTimeStart, $mTimeSunset) - _TimeBetween($mTimeEnd, $mTimeSunset)
        $iTimeAfterSunsetMinutes = $iTotalMinutes - $iTimeBeforeSunsetMinutes
        $iTimeBeforeSunset = Round(Round($iTimeBeforeSunsetMinutes / 30, 1) / 2, 2)
        $iTimeAfterSunset = Round(Round($iTimeAfterSunsetMinutes / 30, 1) / 2, 2)
    Else
        $iTimeBeforeSunset = 0
        $iTimeAfterSunset = 0
    EndIf
    
    $iTotalHours = Round(Round($iTotalMinutes / 30, 1) / 2, 2)
    
    Local $aRet[3] = [$iTotalHours, $iTimeBeforeSunset, $iTimeAfterSunset]
    Return $aRet
EndFunc

;Функция переводит время в минуты
Func _TimeInMinutes($sTimeParam)
    Return Execute(StringReplace($sTimeParam, ':', '*60+'))
EndFunc

;Функция возвращает разницу между минутами времени
Func _TimeBetween($iTime1, $iTime2)
    Return($iTime1 < $iTime2 ? $iTime2 - $iTime1 : 0)
EndFunc


Мозг конечно придётся восстанавливать, но ничего, хорошая утилита получится :laugh:.
 
Верх