Что нового

Подсчёт разницы времени с учётом захода солнца

CreatoR

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

Есть два разных времени, первое это начало работы, а второе - её завершение.
Также есть (но может и не быть) время указывающее на заход солнца.

С этого нужно получить несколько результатов (при чём с округлением минут до получаса):
1) Общее число часов между двумя указателями времени (время захода солнца в этом случае игнорируется).
2) Число часов до захода солнца.
3) Число часов после захода солнца.

* Если час захода солнца не указан, то второй и третьий пункт равняются нулю.

Код:
$sTimeStart = '15:00'
$sTimeEnd = '23:00'

$sTimeSunset = '18:00'

$iTotalHours = DateDiff?
$iTimeBeforeSunset = ?
$iTimeAfterSunset = ?


Возможно я что то упустил в ТЗ, позже если что поправлю (если столкнусь с этим :stars:smile:.
 
A

Alofa

Гость
Код:
#include <Date.au3>
Local $iTotalHours, $iTimeBeforeSunset = 0, $iTimeAfterSunset = 0
Local $sTimeStart = '15:20' ; Начало работы | (в пределах
Local $sTimeEnd = '23:10' ; Конец работы	   | одной даты)
Local $sTimeSunset = '18:40' ; Заход солнца

$iTotalHours = _TimeCalc($sTimeStart, $sTimeEnd) ; Общее число часов (с округлением)
If $sTimeSunset Then
	$iTimeBeforeSunset = _TimeCalc($sTimeStart, $sTimeSunset) ; Число часов до захода солнца (с округлением)
	$iTimeAfterSunset = _TimeCalc($sTimeSunset, $sTimeEnd) ; Число часов после захода солнца (с округлением)
EndIf

MsgBox(64, '', '$iTotalHours = ' & $iTotalHours & @LF & '$iTimeBeforeSunset = ' & $iTimeBeforeSunset & @LF & '$iTimeAfterSunset = ' & $iTimeAfterSunset)

Func _TimeCalc($sTStart, $sTEnd)
	Local $iInterval, $iHour, $iMins, $iSecs
	
	$iInterval = _DateDiff('s', '1111/11/11 ' & $sTStart, '1111/11/11 ' & $sTEnd)
	If Not _TicksToTime($iInterval * 1000, $iHour, $iMins, $iSecs) Then Return SetError(1, 0, 0)
	
	If $iMins < 30 Then
		$iMins = ($iMins >= 15) ? 30 : 0
	ElseIf $iMins > 30 Then
		If $iMins >= 45 Then
			$iMins = 0
			$iHour += 1
		Else
			$iMins = 30
		EndIf
	EndIf
	
	Return StringFormat('%02i:%02i', $iHour, $iMins)
EndFunc   ;==>_TimeCalc
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Alofa
Да я забыл указать, всё таки разрыв даты нужно тоже учитывать.
Т.е если начало 16:00, а конец 01:00, то должно быть 2 часа до заката, а 7 часов после заката.
Если начальное время позже времени заката, то $iTimeBeforeSunset = 0, а $iTimeAfterSunset = 9 (т.е равняется $iTotalHours).
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
OffTopic:
Честно, я себе мозг сломал пока думал над этой задачкой, видимо уже заржавел :stars:.
 
Автор
CreatoR

CreatoR

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

Код:
#include <Date.au3>

Local $iTotalHours, $iTimeBeforeSunset = 0, $iTimeAfterSunset = 0
Local $sTimeStart = '15:00'     ; Начало работы  | (в пределах
Local $sTimeEnd = '23:00'       ; Конец работы   | одной даты)
Local $sTimeSunset = '18:00'    ; Заход солнца

$iTotalHours = _TimeCalc($sTimeStart, $sTimeEnd)                ; Общее число часов (с округлением)

If $sTimeSunset Then
    $iTimeBeforeSunset = _TimeCalc($sTimeStart, $sTimeSunset)   ; Число часов до захода солнца (с округлением)
    $iTimeAfterSunset = _TimeCalc($sTimeSunset, $sTimeEnd)      ; Число часов после захода солнца (с округлением)
	
	If $iTimeBeforeSunset + $iTimeAfterSunset < $iTotalHours Then
		$iTimeBeforeSunset = $iTimeBeforeSunset < $iTimeAfterSunset ? $iTotalHours - $iTimeAfterSunset : $iTimeBeforeSunset
		$iTimeAfterSunset = $iTimeBeforeSunset > $iTimeAfterSunset ? $iTotalHours - $iTimeBeforeSunset : $iTimeAfterSunset
	EndIf
	
	$iTimeBeforeSunset = Number($iTimeBeforeSunset) > Number($iTotalHours) ? ($iTimeAfterSunset > 0 ? 0 : $iTotalHours) : $iTimeBeforeSunset
	$iTimeAfterSunset = Number($iTimeAfterSunset) > Number($iTotalHours) ? ($iTimeBeforeSunset > 0 ? 0 : $iTotalHours) : $iTimeAfterSunset
EndIf

MsgBox(64, '', '$iTotalHours = ' & $iTotalHours & @LF & '$iTimeBeforeSunset = ' & $iTimeBeforeSunset & @LF & '$iTimeAfterSunset = ' & $iTimeAfterSunset)

Func _TimeCalc($sTStart, $sTEnd)
    Local $iInterval, $iHour, $iMins, $iSecs, $iTDiff
    
    $iInterval = _TimeDiff('s', _TimeFormat($sTStart), _TimeFormat($sTEnd))
	 _TicksToTime($iInterval * 1000, $iHour, $iMins, $iSecs)
    $iTDiff = 30 - $iMins
    
    If $iTDiff > 0 Then
        $iMins = ($iTDiff <= 15) ? 30 : 0
    ElseIf $iTDiff < 0 Then
        If $iTDiff <= -15 Then
            $iMins = 0
            $iHour += 1
        Else
            $iMins = 30
        EndIf
    EndIf
    
	$iHour += ($sTStart > $sTEnd ? 1 : 0)
	
    Return StringFormat('%i%s', $iHour, $iMins = 30 ? '.5' : '')
EndFunc

Func _TimeFormat($sTime)
	Return StringFormat('1999/01/01 %s:00', $sTime)
EndFunc

Func _TimeDiff($sType, $sStart, $sEnd)
	Local $iDiff = _DateDiff($sType, $sStart, $sEnd)
	
	If $iDiff < 0 Then
		Return SetExtended($iDiff, _DateDiff($sType, $sStart, _TimeFormat('23:00')) + _DateDiff($sType, _TimeFormat('00:00'), $sEnd) + 1)
	EndIf
	
	Return $iDiff
EndFunc
 
A

Alofa

Гость
CreatoR сказал(а):
... если начало 16:00, а конец 01:00, то должно быть 2 часа до заката, а 7 часов после заката.
Если начальное время позже времени заката, то $iTimeBeforeSunset = 0, а $iTimeAfterSunset = 9 (т.е равняется $iTotalHours).

Вроде так:
Код:
#include <Date.au3>
Local $iTotalHours, $iTimeBeforeSunset = 0, $iTimeAfterSunset = 0

;~ Local $sTimeStart = '23:46'
Local $sTimeStart = '01:46' ; Начало работы
Local $sTimeEnd = '03:00' ; Конец работы
Local $sTimeSunset = '02:10' ; Заход солнца
Local $sMid = '23:59' ; ~ Полночь
Local $iTDecStart = _sTimeToNumber($sTimeStart), $iTDecEnd = _sTimeToNumber($sTimeEnd), $iTDecSunset

$iTotalHours = _TimeCalc($sTimeStart, $sTimeEnd) ; Общее число часов (с округлением)
If $sTimeSunset Then
	$iTDecSunset = _sTimeToNumber($sTimeSunset)
	If $iTDecStart > $iTDecEnd Then ; Если смена дат
		If ($iTDecSunset > $iTDecEnd And $iTDecSunset > $sTimeStart) Or ($iTDecSunset < $iTDecEnd And $iTDecSunset < $sTimeStart) Then
			If $iTDecSunset < _sTimeToNumber($sMid) And $iTDecSunset > $iTDecEnd Then
				$iTimeBeforeSunset = _TimeCalc($sTimeStart, $sTimeSunset) + _TimeCalc($sMid, $sTimeEnd)
				$iTimeAfterSunset = _TimeCalc($sTimeSunset, $sMid)
			Else
				$iTimeBeforeSunset = _TimeCalc($sMid, $sTimeSunset)
				$iTimeAfterSunset = _TimeCalc($sTimeStart, $sMid) + _TimeCalc($sTimeSunset, $sTimeEnd)
			EndIf
		Else
			$iTimeBeforeSunset = _TimeCalc($sTimeStart, $sMid)
			$iTimeAfterSunset = _TimeCalc($sMid, $sTimeEnd)
		EndIf
	Else
		If $iTDecSunset >= $iTDecEnd Then
			$iTimeBeforeSunset = $iTotalHours
		ElseIf $iTDecSunset <= $iTDecStart Then
			$iTimeAfterSunset = $iTotalHours
		Else
			$iTimeBeforeSunset = _TimeCalc($sTimeStart, $sTimeSunset)
			$iTimeAfterSunset = _TimeCalc($sTimeSunset, $sTimeEnd)
		EndIf
	EndIf
EndIf

MsgBox(64, '', '$iTotalHours = ' & $iTotalHours & @LF & '$iTimeBeforeSunset = ' & $iTimeBeforeSunset & @LF & '$iTimeAfterSunset = ' & $iTimeAfterSunset)

Func _TimeCalc($sTStart, $sTEnd)
	Local $iInterval, $iHour, $iMins, $iSecs
	Local $sDate_2 = (_sTimeToNumber($sTStart) > _sTimeToNumber($sTEnd)) ? '1111/11/12 ' : '1111/11/11 '
	$iInterval = _DateDiff('s', '1111/11/11 ' & $sTStart, $sDate_2 & $sTEnd)
	If Not _TicksToTime($iInterval * 1000, $iHour, $iMins, $iSecs) Then Return SetError(1, 0, 0)
	Return Round(_sTimeToNumber($iHour & ':' & $iMins) * 2) / 2
EndFunc   ;==>_TimeCalc

Func _sTimeToNumber($sTime)
	Local $asTime = StringSplit($sTime, ':', 2)
	Return Number($asTime[0] + ($asTime[1] / 60))
EndFunc   ;==>_sTimeToNumber



Добавлено:
Сообщение автоматически объединено:

CreatoR сказал(а):
Вроде вот так получилось:

CreatoR вот так не пройдет:
Код:
Local $sTimeStart = '18:00' ; Начало работы
Local $sTimeEnd = '01:00' ; Конец работы
Local $sTimeSunset = '16:00' ; Заход солнца
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Поправил пример выше, конечно получилось через ж**у, но работает :laugh:.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Alofa
Браво!!! :ok: :beer:
Вот бы ещё возвращаемый формат привести к виду 0.5, 1, 1.5... :whistle:
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
;D
Код:
Local $sTimeStart = '15:25' ; Начало работы
Local $sTimeEnd = '01:00' ; Конец работы
Local $sTimeSunset = '16:50' ; Заход солнца

$mTimeStart = _TimeInMinutes($sTimeStart)
$mTimeEnd = _TimeInMinutes($sTimeEnd)
If $mTimeEnd < $mTimeStart Then $mTimeEnd += 1440
$iTotalMinutes = $mTimeEnd - $mTimeStart
$iTotalHours = Round($iTotalMinutes/30)/2

If $sTimeSunset Then
	$mTimeSunset = _TimeInMinutes($sTimeSunset)
	$iTimeBeforeSunsetMinutes = _TimeBetween($mTimeStart, $mTimeSunset) - _TimeBetween($mTimeEnd, $mTimeSunset)
	$iTimeAfterSunsetMinutes = $iTotalMinutes - $iTimeBeforeSunsetMinutes
	$iTimeBeforeSunset = Round($iTimeBeforeSunsetMinutes/30)/2
	$iTimeAfterSunset = Round($iTimeAfterSunsetMinutes/30)/2
Else
	$iTimeBeforeSunset = 0
	$iTimeAfterSunset = 0
EndIf

MsgBox(64, '', '$iTotalHours = ' & $iTotalHours & @LF & '$iTimeBeforeSunset = ' & $iTimeBeforeSunset & @LF & '$iTimeAfterSunset = ' & $iTimeAfterSunset)

Func _TimeInMinutes($sTimeParam)
	Return Execute(StringReplace($sTimeParam, ":", "*60+"))
EndFunc

Func _TimeBetween($iTime1, $iTime2)
	If $iTime1 < $iTime2 Then Return $iTime2-$iTime1
	Return 0
EndFunc



Alofa
Код:
Local $sTimeStart = '14:00' ; Начало работы
Local $sTimeEnd = '15:00' ; Конец работы
Local $sTimeSunset = '16:00' ; Заход солнца

:(
 
A

Alofa

Гость
CreatoR сказал(а):
... Вот бы ещё возвращаемый формат привести к виду 0.5, 1, 1.5... :whistle:
Обновил Ответ #5.

C2H5OH спасибо, исправил. Ваш пример круче (отличная задумка), но только после доработки:
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Alofa

Что не устраивает в моём скрипте?

Код:
Local $sTimeStart = '01:00' ; Начало работы
Local $sTimeEnd = '03:00' ; Конец работы
Local $sTimeSunset = '05:00' ; Заход солнца

Код:
$iTotalHours = 2
$iTimeBeforeSunset = 2
$iTimeAfterSunset = 0
 

XpycT

Скриптер
Сообщения
380
Репутация
133
CreatoR

Вот мой вариант, набросал на скорую руку :whistle:

Код:
#include <Date.au3>

Local $iTotalHours, $iTimeBeforeSunset = 0, $iTimeAfterSunset = 0
Local $sTimeStart = '2016/05/26 15:00'     ; Начало работы
Local $sTimeEnd = '2016/05/27 01:00'       ; Конец работы
Local $sTimeSunset = '2016/05/26 18:00'    ; Заход солнца

$iTotalHours = _DateDiff("n", $sTimeStart, $sTimeEnd)
$iTotalHours = _TimeFormat($iTotalHours)

If $sTimeSunset Then
	$iTimeBeforeSunset = _DateDiff("n", $sTimeStart, $sTimeSunset)
	If $iTimeBeforeSunset < 0 Then $iTimeBeforeSunset = 0

	$iTimeAfterSunset = _DateDiff("n", $sTimeSunset, $sTimeEnd)
	If $iTimeAfterSunset < 0 Then $iTimeAfterSunset = 0

	$iTimeBeforeSunset = _TimeFormat($iTimeBeforeSunset)
	$iTimeAfterSunset = _TimeFormat($iTimeAfterSunset)
EndIf

MsgBox(64, '', '$iTotalHours = ' & $iTotalHours & @LF & '$iTimeBeforeSunset = ' & $iTimeBeforeSunset & @LF & '$iTimeAfterSunset = ' & $iTimeAfterSunset)




Func _TimeFormat($_vTime)
	Local $iH, $iM, $sF = "%i"

	$iH = Int($_vTime / 60)
	$iM = (Mod($_vTime, 60) >= 15) ? 5 : 0

	If $iM Then $sF = "%i.%i"

	Return StringFormat($sF, $iH, $iM)
EndFunc


P.S.
Время лучше всего указывать вместе с датой
 
A

Alofa

Гость
В очередной раз обновил скрипт в Ответ #5.
Теперь, если рабочий диапазон выпадает на смену дат, то при подсчете времени работы учитывается и переход на другую дату, т.е.:
Код:
; При:
Local $sTimeStart = '21:00' ; Начало работы
Local $sTimeEnd = '03:00' ; Конец работы
Local $sTimeSunset = '22:00' ; Заход солнца
; Мы получим:
$iTotalHours = 6 ; Общее время
$iTimeBeforeSunset = 4 ; с "21:00" до "22;00" и с "00:00" до "03:00"
$iTimeAfterSunset = 2 ; с "22:00" до "00:00"
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Alofa [?]
Теперь, если рабочий диапазон выпадает на смену дат, то при подсчете времени работы учитывается и переход на другую дату, т.е.:
Вот это как раз лишнее, всё что после заката попадает в одну категорию.

Немного поясню задумку.
Я пишу программку для подсчёта часов работы (пока для себя, очень надо), у нас в Израиле немного отличаются законы о рабочих часах от остального мира (впрочем как и всё остальное :smile:).
Например, если сегодня первый день праздника (допустим еврейская пасха - Песах), то все рабочие часы в этот день до захода солнца, являются "обычными" часами (т.е оплата 100%), а после захода - "праздничными" часами (оплата 150%).
Ну а на следующий день, всё наоборот, т.е второй день праздника как бы выходит (заканчивается), а значит часы до заката это "праздничные" часы (150%), а после - "обычные" (100%).

Данная задачка это лишь маленькая часть вычислений которые программа должна уметь делать, например, нужно будет ещё высчитывать пол часа от большей части (между до и после заката), это как бы перерыв в работе, он не оплачивается.
Также нужно высчитывать сверхурочные часы, т.е + 25% к часам переработки...

В общем всем огромное спасибо, позже всё проверю и отпишусь какой вариант взял на вооружение :beer:.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
С округлением я немного погорячился, нужно не округлять, а подсчитывать точно.
Скажем если время с 15:00 до 23:20, то это 8.3 часов, и если при этом закат в 17:00, то до заката это 2 часа, а после это 6.3.

На данный момент, вариант от C2H5OH самый атрактивный :smile:, но и тут есть проблемка:

Код:
Local $sTimeStart = '15:10'
Local $sTimeEnd = '23:20'
Local $sTimeSunset = '17:00'


В этом случае теряется пол часа в общей сумме часов.
 
Верх