Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » PowerShell - Посчитать время с учётом рабочих часов

Ответить
Настройки темы
PowerShell - Посчитать время с учётом рабочих часов

Новый участник


Сообщения: 22
Благодарности: 0

Профиль | Отправить PM | Цитировать


Изображения
Тип файла: png Screenshot 2022-12-21 at 12.10.14.png
(17.8 Kb, 6 просмотров)
Всем привет!

Стоит задача посчитать сколько было затрачено времени в текущей задаче. В целом всё просто, использовал командлет Timespan, взял время старта, время конца, сложил и получил ответ:

Код: Выделить весь код
$FIRST_RESPONSE_TIME = New-TimeSpan -Start "$START_TIME_TICKET" -End "$END_TIME_TICKET"
Во вложении вывод.

Однако, есть нюанс, который заключается в SLA. Время останавливается на нерабочих часах. То есть должно на 19:00 время остановиться и в 9:00 следующего дня утром снова возобновиться. По итогу вывод должен быть не на 2 часа 17 минут, а просто на 1 час 32 минуты. Следовательно, если время будет начинаться, скажем с 20:00 часов, то считать он должен с 9:00 и до времени, когда будет $END_TIME_TICKET (например конечная дата 12:00 и того 3 часа итог, а не 16 часов, как он посчитается всё время).

И вот как посчитать время с учётом рабочих часов, вообще никаких идей нет, может у кого будут мысли как это сделать.

Заранее спасибо!!!

p.s. а и да, ещё нужно как-то учесть производственный календарь... в общем время должно считать строго в пороге от 9:00 до 19:00 буднего дня, а оставшееся выкидывать

Отправлено: 12:22, 21-12-2022

 

Аватара для YuS_2

Crazy


Contributor


Сообщения: 1218
Благодарности: 509

Профиль | Отправить PM | Цитировать


Для будних дней:
Код: Выделить весь код
$k = new-timespan -h 14
if (($x = $END_TIME_TICKET.day - $START_TIME_TICKET.day)){
    $END_TIME_TICKET - $START_TIME_TICKET - $x*$k
} else {
    $END_TIME_TICKET - $START_TIME_TICKET
}
где $x - разница дней, $k - период с 19:00 до 9:00

Цитата Njem:
ещё нужно как-то учесть производственный календарь... »
Для выходных и праздничных дней надо будет добавить условный блок с коэффициентом, учитывающим выходные... с праздничными - сложнее, придется составлять календарь с праздничными днями, учитывать год, день недели и если праздничный выпадает на будний день, то вычитать 24 часа... в общем, по аналогии составляйте алгоритм и реализуйте его в код... ничего сложного

-------
scio me nihil scire. Ѫ

Это сообщение посчитали полезным следующие участники:

Отправлено: 13:12, 21-12-2022 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.


Новый участник


Сообщения: 22
Благодарности: 0

Профиль | Отправить PM | Цитировать


Цитата YuS_2:
где $x - разница дней, $k - период с 19:00 до 9:00 »
хм... то есть получается $k - период, который, он не явно с 19:00 до 9:00, а просто делается всегда отнимание 14 часов, если $END_TIME_TICKET +1 день от $START_TIME_TICKET

а если время будет начинаться с 7:00 утра, он ведь всё равно посчитает его с 7:00, а не с 9:00 как должен((

p.s. причём вот, есть живой пример сейчас: время начинается с 16:37, а заканчивается на следующий день в 19:37. Считает 13 часов, так как отнимает 14 часов, НО, 37 минут же идут вне рабочего временни, значит должно быть 12 часов 23 минуты. И вот как сделать, чтобы он когда достигал 19:00 понимал, что это уже стоп...

Последний раз редактировалось Njem, 21-12-2022 в 15:57.


Отправлено: 13:47, 21-12-2022 | #3


Аватара для YuS_2

Crazy


Contributor


Сообщения: 1218
Благодарности: 509

Профиль | Отправить PM | Цитировать


Цитата Njem:
причём вот, есть живой пример сейчас: время начинается с 16:37, а заканчивается на следующий день в 19:37. Считает 13 часов, так как отнимает 14 часов, НО, 37 минут же идут вне рабочего временни, значит должно быть 12 часов 23 минуты. И вот как сделать, чтобы он когда достигал 19:00 понимал, что это уже стоп... »
Научитесь составлять словесный алгоритм, в котором будут учитываться все возможные ситуации, после этого реализуйте его в код...
Пример для одного дня, без перехода на новую дату:
Код: Выделить весь код
$start = new-timespan -h 9
$end = new-timespan -h 19
$k = new-timespan -h 14
$time = new-timespan

if (!($x = $END_TIME_TICKET.day - $START_TIME_TICKET.day)){
	if($END_TIME_TICKET.timeofday.totalhours -ge $end.totalhours -and $START_TIME_TICKET.timeofday.totalhours -lt $start.totalhours){
		$time = $end - $start
	} elseif ($END_TIME_TICKET.timeofday.totalhours -ge $end.totalhours -and $START_TIME_TICKET.timeofday.totalhours -ge $start.totalhours){
		$time = $end - $START_TIME_TICKET.timeofday
	} elseif ($END_TIME_TICKET.timeofday.totalhours -le $end.totalhours -and $START_TIME_TICKET.timeofday.totalhours -lt $start.totalhours){
		$time = $END_TIME_TICKET.timeofday - $start
	} elseif ($END_TIME_TICKET.timeofday.totalhours -le $end.totalhours -and $START_TIME_TICKET.timeofday.totalhours -ge $start.totalhours) {
		$time = $END_TIME_TICKET.timeofday - $START_TIME_TICKET.timeofday
	}
}
$time
- Здесь не учтена ситуация, когда и старт, и стоп, до начала рабочего дня, либо оба после окончания, но в этом случае, $time будет 0, только надо описать это в условиях...
В общем, остальные возможные комбинации, предлагаю обдумывать самостоятельно...

-------
scio me nihil scire. Ѫ


Последний раз редактировалось YuS_2, 21-12-2022 в 17:47.

Это сообщение посчитали полезным следующие участники:

Отправлено: 17:12, 21-12-2022 | #4


Аватара для YuS_2

Crazy


Contributor


Сообщения: 1218
Благодарности: 509

Профиль | Отправить PM | Цитировать



Njem,
В общем, накидал тут пример реализации логики для будней:
script.ps1
Код: Выделить весь код
param (
	[datetime]$stime = $(get-date("21.12.2022 8:00")),
	[datetime]$etime = $(get-date("22.12.2022 8:00")),
	[timespan]$startwork = $(new-timespan -h 9),
	[timespan]$endwork = $(new-timespan -h 19),
	[timespan]$fullwork = $(new-timespan -h 10)
)
function get-timework {
	param (
		[datetime]$stt, # старт
		[datetime]$ett, # стоп
		[timespan]$start, # начало рабочего периода
		[timespan]$end , # конец рабочего периода
		[timespan]$m # полный рабочий период
	)
	$x = $ett.day - $stt.day # количество дней между стартом и стопом
	$w, $h = @(1,2,3,4,5), @(6,0) # будни, выходные
	$sdw,$edw = $stt.dayofweek.value__,$ett.dayofweek.value__ # номер дня недели для старт и стоп
	# укорачиваем код до названия переменных:
	$rs,$re = $stt.timeofday.totalminutes,$ett.timeofday.totalminutes
	$s,$e = $start.totalminutes,$end.totalminutes
	$minutes = $m.totalminutes
	# Реализация логики подсчета для будней:
	if (!$x -and $re -le $rs) {
		write-host Ошибка! Проверьте данные '$stt - старт/ $ett - стоп' -for red
		break
	}
	if (!$x -and $sdw -notin $h -and $edw -notin $h -and $re -gt $rs){
		if($rs -lt $s -and $re -gt $e){
			$time = new-timespan -min ($minutes)
		} elseif (($rs -ge $s -and $rs -le $e) -and $re -gt $e){
			$time = new-timespan -min ($e - $rs)
		} elseif (($rs -gt $e -and $re -gt $e) -or ($rs -lt $s -and $re -lt $s)){
			$time = new-timespan
		} elseif ($rs -lt $s -and ($re -ge $s -and $re -le $e)) {
			$time = new-timespan -min ($re - $s)
		} elseif (($rs -ge $s -and $rs -le $e) -and ($re -ge $s -and $re -le $e)){
			$time = new-timespan -min ($re - $rs)
		}
	} elseif ($x -and $sdw -notin $h -and $edw -notin $h) {
		if ($rs -lt $s -and $re -gt $e){
			$time = new-timespan -min ($minutes * ($x+1))
		} elseif (($rs -ge $s -and $rs -le $e) -and $re -gt $e){
			$time = new-timespan -min ($e - $rs + $minutes*$x)
		} elseif (($rs -gt $e -and $re -gt $e) -or ($rs -lt $s -and $re -lt $s)){
			$time = new-timespan -min ($minutes * $x)
		} elseif ($rs -lt $s -and ($re -ge $s -and $re -le $e)){
			$time = new-timespan -min ($re - $s + $minutes*$x)
		} elseif (($rs -ge $s -and $rs -le $e) -and ($re -ge $s -and $re -le $e)){
			$time = new-timespan -min ($re - $s + $e - $rs + $minutes*($x-1))
		} elseif ($rs -gt $e -and ($re -ge $s -and $re -le $e)) {
			$time = new-timespan -min ($re - $s + $minutes*($x-1))
		} elseif (($rs -ge $s -and $rs -le $e) -and $re -lt $s){
			$time = new-timespan -min ($e - $rs + $minutes*($x-1))
		} elseif ($rs -gt $e -and $re -lt $s) {
			$time = new-timespan -min ($minutes*($x-1))
		} 
	} else {
		write-host Условия не сработали... для будущей разработки. -for cyan
	}
	return $time
}

get-timework -stt $stime -ett $etime -start $startwork -end $endwork -m $fullwork


Пример запуска:
Код: Выделить весь код
.\script.ps1 -stime $(get-date("21.12.2022 19:50")) -etime $(get-date("22.12.2022 17:00"))
Для ориентирования, как реализуется логика, приведу табличку:
2022-12-22 16-1-39.png

Выходные и праздники не учитываются... попробуйте их реализовать, отталкиваясь от логики будней...

-------
scio me nihil scire. Ѫ


Последний раз редактировалось YuS_2, 22-12-2022 в 14:40. Причина: Исправил номера дней недели от 0 до 6

Это сообщение посчитали полезным следующие участники:

Отправлено: 13:03, 22-12-2022 | #5


Новый участник


Сообщения: 22
Благодарности: 0

Профиль | Отправить PM | Цитировать


Цитата YuS_2:
В общем, накидал тут пример реализации логики для будней: »
ВООУУ, ничего себе!!! господи, спасибо Вам большое!!
а я тут сижу второй день пытаясь математически всё это рассчитать) пока что логика тяжело даётся) думаю с этим намного проще будет!)

Цитата YuS_2:
Выходные и праздники не учитываются... попробуйте их реализовать, отталкиваясь от логики будней... »
да я думаю выходные как-нить попытаюсь сделать, а-ля в какой нить csv запихнуть дни (выходные все), где он туда будет ссылаться с проверкой, мол если день есть, то -24 часа делать сходу... как-нить по такому принципу думал

сейчас всё посмотрю, спасибо ещё раз!!!) работа с числами всегда тяжело даётся для меня

Отправлено: 13:19, 22-12-2022 | #6


Аватара для YuS_2

Crazy


Contributor


Сообщения: 1218
Благодарности: 509

Профиль | Отправить PM | Цитировать


Цитата Njem:
а-ля в какой нить csv запихнуть дни (выходные все), где он туда будет ссылаться с проверкой, мол если день есть, то -24 часа делать сходу... как-нить по такому принципу думал »
В csv для выходных не надо, там есть начало реализации... надо учитывать номер дня недели и если старт/стоп выпадает на выходные, то формула будет изменяться, а также при переходе через выходные, т.е. для ситуации:
Код: Выделить весь код
($x -gt 0 -and $x -lt 7) -and ($sdw -gt $edw) -and ($sdw -in $w) -and ($edw -in $w)
- выполнение условия будет означать переход через выходные, кроме того и старт, и стоп были осуществлены в будний день... только при реализации, надо учесть все нюансы (один или два выходных, момент старта и стопа и т.д.), в общем поле для размышлений есть...
А вот для праздников, возможно, придется использовать какой-либо список, тот же csv, либо прямо в скрипте его организовать...

-------
scio me nihil scire. Ѫ

Это сообщение посчитали полезным следующие участники:

Отправлено: 13:36, 22-12-2022 | #7


Новый участник


Сообщения: 22
Благодарности: 0

Профиль | Отправить PM | Цитировать


Цитата YuS_2:
выполнение условия будет означать переход через выходные, кроме того и старт, и стоп были осуществлены в будний день... только при реализации, надо учесть все нюансы (один или два выходных, момент старта и стопа и т.д.), в общем поле для размышлений есть... »
о как, понял, хорошо, тогда так и сделаю, спасибо ещё раз за помощь)

Цитата YuS_2:
А вот для праздников, возможно, придется использовать какой-либо список, тот же csv, либо прямо в скрипте его организовать... »
а тут проще, в инете есть производственный календарь как раз на 2023 год. Его можно как csv, так и json формата скачать)

Отправлено: 13:40, 22-12-2022 | #8


Аватара для YuS_2

Crazy


Contributor


Сообщения: 1218
Благодарности: 509

Профиль | Отправить PM | Цитировать


Njem, небольшая поправка
неправильно был указан номер воскресенья... должен был быть 0, т.е. 6 - суббота, 0 - воскресенье
в скрипте исправил...

-------
scio me nihil scire. Ѫ

Это сообщение посчитали полезным следующие участники:

Отправлено: 14:44, 22-12-2022 | #9


Аватара для YuS_2

Crazy


Contributor


Сообщения: 1218
Благодарности: 509

Профиль | Отправить PM | Цитировать


Ещё вариант, в котором поправлены ошибки и добавлен учет выходных:
script.ps1
Код: Выделить весь код
# Пример работы со временем. Учет времени только в рабочее время (9:00 - 19:00),
# исключая выходные (суб., вск.).
# .\script.ps1 -stime $(get-date("21.12.2022 19:50")) -etime $(get-date("22.12.2022 17:00"))
param (
	[datetime]$stime = $(get-date("21.12.2022 8:00")),
	[datetime]$etime = $(get-date("22.12.2022 8:00")),
	[timespan]$startwork = $(new-timespan -h 9 -min 0),
	[timespan]$endwork = $(new-timespan -h 19 -min 0)
)
function get-timework {
	param (
		[datetime]$stt, # старт
		[datetime]$ett, # стоп
		[timespan]$start, # начало рабочего периода
		[timespan]$end # конец рабочего периода
	)
	function get-weekend {
		param (
			[datetime]$sd,
			[datetime]$ed,
			[int[]]$weekend = @(6,0)
		)
		$sub = ($ed.date - $sd.date).days
		$arr = @()
		for ($i = 0; $i -le $sub;$i++){
			#формируем массив выходных за период, для дальнейшего подсчета пар
			if ($sd.adddays($i).dayofweek.value__ -in $weekend){
				$arr += $sd.adddays($i).dayofweek.value__
			}
		}
		if ($arr){
			$out = ($arr.where({$_ -eq $weekend[0]},5)|%{$_.count}|sort -d)[0]
		} else {$out = 0}
		return $out
	}
	if ($ett -le $stt) {
		write-host Ошибка! Проверьте данные '$stt - старт/ $ett - стоп' -for red
		break
	}
	$m = new-timespan -h ($end - $start).totalhours
	$x = ($ett.date - $stt.date).days # количество дней между стартом и стопом
	$w, $h = @(1,2,3,4,5), @(6,0) # будни, выходные (суббота и воскресенье)
	# укорачиваем код до названия переменных:
	$sdw,$edw = $stt.dayofweek.value__,$ett.dayofweek.value__ # номер дня недели для старт и стоп
	$rs,$re = $stt.timeofday.totalminutes,$ett.timeofday.totalminutes
	$s,$e = $start.totalminutes,$end.totalminutes
	$minutes = $m.totalminutes

	# Для выходных:
	if ($edw -in $h){
		# Если стоп в выходной день (перенос стопа на пон. 0:00)
		if (!$edw){$ds = 1} else {$ds = 2}
		$ett = $ett.addminutes(-$ett.timeofday.totalminutes)
		$ett = $ett.adddays($ds)
		$edw,$re = $ett.dayofweek.value__,$ett.timeofday.totalminutes
		$x = ($ett.date - $stt.date).days
	}
	if ($sdw -in $h){
		# Если старт в выходной день (перенос старта на пон. 0:00)
		if (!$sdw){$ds = 1} else {$ds = 2}
		$stt = $stt.addminutes(-$stt.timeofday.totalminutes)
		$stt = $stt.adddays($ds)
		$sdw,$rs = $stt.dayofweek.value__,$stt.timeofday.totalminutes
		$x = ($ett.date - $stt.date).days
	}
	$kw = get-weekend $stt $ett # количество пар выходных между стартом и стопом
	if ($stt.dayofweek.value__ -in $h -and $kw){$kw--}
	if ($x -and $sdw -in $w -and $edw -in $w){
		# Если есть полный переход через выходные, 
		# старт/стоп в рабочие дни, вычитаем выходные полностью:
		$x = $x - 2*$kw
	}

	# Реализация логики подсчета для будней:
	if (!$x -and $sdw -in $w -and $edw -in $w -and $re -ge $rs){
		# Если и старт, и стоп в один день
		if($rs -lt $s -and $re -gt $e){
			$time = new-timespan -min ($minutes)
		} elseif (($rs -ge $s -and $rs -le $e) -and $re -gt $e){
			$time = new-timespan -min ($e - $rs)
		} elseif (($rs -gt $e -and $re -gt $e) -or ($rs -lt $s -and $re -lt $s)){
			$time = new-timespan
		} elseif ($rs -lt $s -and ($re -ge $s -and $re -le $e)) {
			$time = new-timespan -min ($re - $s)
		} elseif (($rs -ge $s -and $rs -le $e) -and ($re -ge $s -and $re -le $e)){
			$time = new-timespan -min ($re - $rs)
		}
	} elseif ($x -and $sdw -in $w -and $edw -in $w) {
		# Если старт и стоп в разные дни,
		if ($rs -lt $s -and $re -gt $e){
			$time = new-timespan -min ($minutes * ($x+1))
		} elseif (($rs -ge $s -and $rs -le $e) -and $re -gt $e){
			$time = new-timespan -min ($e - $rs + $minutes*$x)
		} elseif (($rs -gt $e -and $re -gt $e) -or ($rs -lt $s -and $re -lt $s)){
			$time = new-timespan -min ($minutes * $x)
		} elseif ($rs -lt $s -and ($re -ge $s -and $re -le $e)){
			$time = new-timespan -min ($re - $s + $minutes*$x)
		} elseif (($rs -ge $s -and $rs -le $e) -and ($re -ge $s -and $re -le $e)){
			$time = new-timespan -min ($re - $s + $e - $rs + $minutes*($x-1))
		} elseif ($rs -gt $e -and ($re -ge $s -and $re -le $e)) {
			$time = new-timespan -min ($re - $s + $minutes*($x-1))
		} elseif (($rs -ge $s -and $rs -le $e) -and $re -lt $s){
			$time = new-timespan -min ($e - $rs + $minutes*($x-1))
		} elseif ($rs -gt $e -and $re -lt $s) {
			$time = new-timespan -min ($minutes*($x-1))
		} 
	} else {
		write-host Условия не сработали... для будущей разработки. -for cyan
	}
	return $time
}

get-timework -stt $stime -ett $etime -start $startwork -end $endwork

-------
scio me nihil scire. Ѫ


Последний раз редактировалось YuS_2, 24-12-2022 в 11:39.

Это сообщение посчитали полезным следующие участники:

Отправлено: 18:58, 23-12-2022 | #10



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » PowerShell - Посчитать время с учётом рабочих часов

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
2019 - [решено] Excel. Неправильное суммирование рабочих часов Tolea3 Microsoft Office (Word, Excel, Outlook и т.д.) 12 28-04-2020 17:20
[решено] Как посчитать время работа программы vk_k14m@vk Хочу все знать 6 04-06-2019 15:47
Flash - Как посчитать время записи файлов на флешку alleclf Накопители (SSD, HDD, USB Flash) 1 01-11-2016 18:39
Слетает дата и время на рабочих станциях Diman1989_19 Microsoft Windows NT/2000/2003 7 09-07-2014 09:45
сбрасывается время РОВНО на 9 часов назад! whattaff Непонятные проблемы с Железом 4 15-10-2010 21:26




 
Переход