Доброго всем времени. Поискал по форуму похожие топики, но не нашел, поэтому делаю новый. Наверное задача тривиальная и совсем для новичков, но все же попытаю счастья, может кто-то уже делал и знает элегантное решение, потому-что все, что приходит в голову мне - очень громоздкое и кривое ) Стоит задача сделать проверку работы заведений по указанному для каждого дня расписанию. Расписание хранится в виде ЧЧ:ММ - ЧЧ:ММ для каждого дня недели отдельно (например пн => 10:00 - 22:45, вт => 13:00 - 02:30, ср => 10:00 - 23:00) Загвоздка для меня состоит в том, чтобы учесть случаи, когда заведение начинает работать в одну дату, а закрывается в другую (то-есть уже наступил новый день, и текущая дата будет уже для расписания следующего "цикла" работы заведения, но заведение еще работает). На примере: в расписании для вторника заведение закрывается в 3 часа ночи, а в среду начинает работать в 12 дня. Если я в час ночи среды проверяю расписание - заведение начинает работу только в 12, но оно еще не закрылось по расписанию вторника. Как написал выше, пока в голову приходят громоздкие идеи с каскадныим проверками или с составлением массива рабочих промежутков на несколько дней без привязки к дню недели перед каждой проверкой. PS понимаю, что это больше похоже на школьную задачку на логику, но хочтеся написать грамотную проверку, а не кривой костыль))
Лично мне непонятно что значит "сделать проверку работы заведений". Или "в час ночи среды проверяю расписание". Уточни пожалуйста, это проверка работает ли заведение в конкретный момент времени datetime? Или может быть это вычисление промежутка(ов) времени когда заведение работает в указанную дату? Что именно?
Ок если в контексте, то есть список заведений, для которых указано расписание на каждый день недели. Проверить нужно в конкретный (текущий) момент времени какие заведения работают.
Вам же посоветовали переводить даты а UNIX формат. Дату начала сравнивайте с окончанием. Если начало больше, то к окончанию прибавьте сутки(в секундах). И уже с этим промежутком сравнивайте время работы. Тоже в Юниксе.
В общем проверка все равно получается громоздкой, как ни крути. Нашел такое решение, что в общем не сильно отличается от моего текущего решения: Код (Text): $start_work = "08:00"; $end_work = "02:00"; $currentTime = "01:00"; //текущее время с датой, даже если оно у вас 12:00 все равно имеет дату $currentDateTime = strtotime(date('Y-m-d') ." ". $currentTime); //Дата и время во сколько мы закрылись вчера $previousDayEnd; //Дата и время во сколько мы открылись сегодня $startDateTime; //Дата и время во сколько мы закрылись сегодня $endDateTime; $startDateTime = strtotime(date('Y-m-d') ." ". $start_work); if (strtotime($start_work) <= strtotime($end_work)){ $endDateTime = strtotime(date('Y-m-d') ." ". $end_work); $previousDayEnd = strtotime(date('Y-m-d') ." ". $end_work . "-1 days"); } else{ $endDateTime = strtotime(date('Y-m-d') ." ". $end_work . "+1 days"); $previousDayEnd = strtotime(date('Y-m-d') ." ". $end_work ); } //проверить полученные результаты echo "Мы закрылись в : " . date("Y-m-d H:i:s", $previousDayEnd). "\n"; echo "Открытие : " . date("Y-m-d H:i:s", $startDateTime) . "\n"; echo "Закрытие : " . date("Y-m-d H:i:s", $endDateTime). "\n"; if ($currentDateTime >= $startDateTime && $currentDateTime <= $endDateTime) { echo "Сейчас рабочее время : " . date("Y-m-d H:i:s", $currentDateTime) ."\n"; } else if($currentDateTime < $startDateTime && $currentDateTime < $previousDayEnd ){ echo "Сейчас рабочее время : " . date("Y-m-d H:i:s", $currentDateTime) ."\n"; } else { echo "Мы закрыты в это время : " . date("Y-m-d H:i:s", $currentDateTime) ."\n"; }
PHP: <?php $start_work = "08:00"; $end_work = "02:00"; $currentTime = "13-01-2022 01:00"; // корректная текущая дата $status = 'закрыто'; $ustart = date_format(date_create($start_work), 'U'); $ustop = date_format(date_create($end_work), 'U'); $ucurrent = date_format(date_create($currentTime), 'U'); if($ustop < $ustart) { $ustop += 60*60*24; } if($ucurrent > $ustart && $ucurrent < $ustop) { $status = 'открыто'; } echo $status; ?> $start_work и $end_work так же задавать с датой. Иначе после полуночи статус будет выдавать как "закрыто"
Спасибо. Только один нюанс есть - в этих примерах (моем и Вашем) подразумевается, что расписание на все дни одинаковое, что в реальности не так. Поэтому без проверки окончания работы в предыдущий день не обойтись.
Вот вариант https://php.ru/forum/threads/privesti-massiv-v-pravilnyj-vid.88742/ или вот https://php.ru/forum/threads/podskazhite-kak-sdelat-vyvod-tajmslotov-ne-zanjatogo-vremeni.88999/
Ребята, мне кажется до сих пор ваше обсуждение имело не много смысла. Можно резко повыстить ценность темы, если написать SQL запрос, решающий поставленную задачу. И для быстрой проверки завести таблицу с правдоподобными данными. Всё это можно сделать на db-fiddle.com Начну с такого: https://www.db-fiddle.com/f/wguqsccbc7QALHSHDMV3wA/0 а вы форкайте и дополняйте, если надо. Идея в том, чтобы хранить данные в удобном для эффективной работы виде. А преобразовать при вводе и выводе можно как угодно. Можно не высчитывать дата + время_с, (время_по < время_с ? дата + 1 день + время_по : дата + время_по) при каждой проверке, а сделать это один раз при сохранении данных. Я приспособил данные под операцию BETWEEN, она, как известно, подразумевает что промежуток с-по включает в себя границы. Поэтому там время конца без одной секунды. Компренде? Код (SQL): SELECT * FROM timesheet WHERE '2021-01-16 00:30:00' BETWEEN dt_from AND dt_to --- Добавлено --- Из личного опыта работы с расписанием: есть расписание по умолчанию или шаблон, а есть заранее запланированные нерабочие дни и есть возможность вручную поправить некоторые дни. Отсюда следует, что админка должна иметь, как минимум два раздела — шаблон расписания и реальный календарь. И операцию "накатить шаблон с даты по дату". Но это уже оффтоппик, к алгоритму не относится --- Добавлено --- Задача "найти заведения, работающие в определённый день и показать их время работы в этот день" была бы посложнее, но тоже пишется в один SQL запрос.
Мне думается вряд ли у него нагенерированы в БД все эти метки времени, на все дни. Скорее просто запись о неделе. Я бы все это перевел в систему счисления, в минуты с начала недели, и по этим промежуткам уже шустрил Только тут нужно от неопределенности избавиться, ваш формат позволяет запись типа вт => 01:00 - 02:30 , а второе значение можно понимать и как день текущий и как день следующий
Более логичным вижу не запись в виде промежутка(точнее не только лишь в нем), а запись с промежутком и с заранее вычисленным временем работы, в секундах. Это существенно упростит код для промежутка с окончанием работы в следующих сутках - для операций будет достаточно только время начала работы и продолжительность рабочего дня. А собственно "промежуток" понадобится только для отображения.
А такой вариант не устроит? PHP: $start_work = '08:00'; $end_work = '02:00'; $c = new DateTime(); $b = new DateTime($start_work); $e = new DateTime($end_work . ($start_work > $end_work ? ' +1 day' : '')); $isOpen = ($c >= $b and $c <= $e);