Хранение рабочих часов в базе данных

87

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

Например:

У предприятия А следующие часы работы

  • Понедельник: 9.00 - 17.00
  • Вторник: 9.00 - 17.00
  • Среда: 9.00 - 17.00
  • Четверг: 9.00 - 17.00
  • Пятница: 9.00 - 17.00
  • Суббота: 9.00 - 12.00
  • Воскресенье: выходной

В настоящее время у меня есть модель данных, подобная следующей

CREATE TABLE "business_hours" (
    "id" integer NOT NULL PRIMARY KEY,
    "day" varchar(16) NOT NULL,
    "open_time" time,
    "close_time" time
)

где «день» ограничен выбором 7 дней недели в коде (через ORM). Чтобы проверить, закрыт ли бизнес в определенный день, он проверяет, равны ли значения open_time и close_time NULL. Он связан с бизнесом через промежуточную таблицу (отношение "многие ко многим").

Есть ли у кого-нибудь предложения по этой схеме базы данных? Что-то в этом мне не кажется правильным.

user128000
источник
4
Зачем вам нужна связь M-to-M между таблицей business_hours и таблицей предприятий? Если вы действительно собираетесь заставить несколько предприятий использовать одну и ту же запись в business_hours, почему? Семантически тот факт, что «компания C работает от T1 до T2 в день D» - это скорее объект-значение, чем сущность ... Единственная хорошая (?) Причина, которую я могу себе представить, это оптимизация размера хранилища (версия RDB шаблона Flyweight, так сказать), если ожидается, что количество предприятий будет огромным ...
Ярик
3
А как насчет обеденных перерывов? А как насчет государственных праздников?
Mawg требует восстановить Монику

Ответы:

58

В общем, ничего плохого в этом не вижу. Кроме...

  1. Я бы сохранил день недели как целое число, используя любую систему нумерации, которую использует ваш родной язык программирования (в своих библиотеках). Это уменьшит размер базы данных и удалит сравнения строк из вашего кода.

  2. Я бы, вероятно, поместил внешний ключ в бизнес-таблицу прямо здесь, в этой таблице. Таким образом, вам не понадобится таблица ссылок.

Думаю, я бы сделал:

CREATE TABLE "business_hours" (
     "id" integer NOT NULL PRIMARY KEY,
     "business_id" integer NOT NULL FOREIGN KEY REFERENCES "businesses",
     "day" integer NOT NULL,
     "open_time" time,
     "close_time" time
)

В моей бизнес-логике я бы установил ограничение, согласно которому каждое «предприятие» имеет не менее 7 «рабочих часов». ( По крайней мере, потому что Джон Скит прав, вам могут потребоваться праздничные часы.) Хотя вы можете ослабить это ограничение, просто отказавшись от «рабочих часов» в те дни, когда предприятие закрыто.

Франк Крюгер
источник
1
Как бы вы сделали 2? Есть все записи для всех предприятий, даже если день / время одинаковы?
Винко Врсалович,
7
Я бы сказал да. В противном случае подумайте, что произойдет, если два предприятия будут использовать одни и те же часы, но тогда одному из них потребуется изменить свое время. Вам нужно будет определить тот факт, что часы изменены, и либо создать новую запись, либо отредактировать существующую, в зависимости от того, является ли она общей или нет.
Эрик Форбс,
3
Я бы категорически не стал делить строки этой таблицы между предприятиями. Такой обмен просто приводит к боли. Бизнес-логика приложения должна просто обеспечивать соблюдение ограничения, согласно которому у каждой компании должно быть не менее 7 ссылок «business_hours».
Франк Крюгер,
1
@Vinko: Помните, что хотя значения (в настоящее время) одинаковы, часы работы двух предприятий семантически различны.
Draemon
1
Вы также можете использовать растровое изображение из 7 бит для «дня». Таким образом, вам не придется повторять одни и те же записи. Пример: все рабочие дни имеют одинаковое рабочее время, достаточно одной записи.
ZolaKt
29

Одна ситуация, не охватываемая этой схемой, - это несколько периодов открытия в день. Например, местный паб открыт с 12:00 до 14:30 и с 17:00 до 23:00.

Может быть, кассы театра открыты на утренник и вечерний спектакль.

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

А как насчет времени работы до полуночи. Допустим, бар открыт с 19:00 до 02:00. Вы не можете просто сравнить время открытия и закрытия со временем, которое вы хотите проверить.

Дэвидшелдон
источник
В итоге я сделал что-то вроде предложения @JordanFeldstein. Я храню массивы «изменений состояния», которые включают изменение (открытие или закрытие), день недели и время суток. Я могу вносить столько «изменений», сколько захочу для каждого дела и каждый день. Бизнес может открываться один день и закрываться на следующий, открываться дважды (или x раз) в день, быть открытым 24 часа, но закрытым по понедельникам, независимо от того. Это сложно реализовать, но очень гибко.
ironcito
Следуя подходу наилучшего ответа, я бы предпочел добавить два столбца в business_hours: break_timeи break_duration. Очень редко бывает два перерыва в один день.
Frondor
13

Это как бы зависит от того, для чего вам нужно их хранить и как могут выглядеть реальные данные.
Если вам нужно определить, открыт ли бизнес в определенный момент, может быть немного неудобно запрашивать схему, как она изложена. Но что еще важнее: вам когда-нибудь понадобится закрытие в середине дня?

Некоторые варианты включают;

  • Схема, как у вас, но с возможностью иметь несколько периодов в один и тот же день. Он будет обслуживать перерыв на обед, но сделает неудобным выполнение запроса, который дает вам часы работы в данный день, скажем, для презентации пользователю.
  • Подход в стиле растрового изображения; «000000000111111110000000» для 9-5. Обратной стороной этого подхода является то, что вам нужно выбрать конкретную степень детализации, то есть целые часы, полчаса или, действительно, минуты. Чем мельче детализация, тем труднее читать данные человеку. Вы можете использовать побитовые операторы, чтобы сохранить это значение как одно число, а не как строку целых чисел, но это опять же ухудшает читаемость.
Франс
источник
11

Я узнал, что если вы хотите, чтобы разметка данных Google распознавала ваши данные, вы должны следовать этим правилам:

https://schema.org/openingHours

http://schema.org/OpeningHoursSpecification Содержит «действительные даты», что очень полезно для некоторых предприятий.

https://schema.org/docs/search_results.html#q=hours

У вас должно быть все в порядке без первичного ключа, если только вы не разрешаете предприятиям использовать одни и те же часы с таблицей соединения - что интересно, в конечном итоге у вас будет конечное количество комбинаций; Я не уверен, сколько это будет: p

В одном из своих проектов я использовал столбцы:

[uInt] business_id, [uTinyInt] день, [char (11)] timeRange

Если вы хотите поддерживать спецификацию OpeningHoursSpecification, вам необходимо добавить validFrom и validThrough.

Временной диапазон имеет формат: чч: мм-чч: мм.

Вот функция, которая его анализирует, вы также можете изменить эту функцию для анализа только одного открытия / закрытия, если вы сохраните их как отдельные столбцы в БД.

Исходя из моего опыта, я бы порекомендовал вам разрешать несколько раз в течение дня, чтобы можно было определить, закрыты ли они в этот день явно или открыты 24 часа или 24/7. Я сказал, что если в БД пропущен день, то в этот день бизнес закрывается.

/**
 * parseTimeRange
 * parses a time range in the form of
 * '08:55-22:00'
 * @param $timeRange 'hh:mm-hh:mm' '08:55-22:00'
 * @return mixed ['hourStart'=>, 'minuteStart'=>, 'hourEnd'=>, 'minuteEnd'=>]
 */
function parseTimeRange($timeRange)
{
    // no validating just parsing
    preg_match('/(?P<hourStart>\d{1,2}):(?P<minuteStart>\d{2})-(?P<hourEnd>\d{1,2}):(?P<minuteEnd>\d{2})/', $timeRange, $matches);

    return $matches;
}
CTS_AE
источник
1

Большинство результатов работает нормально для данного сценария, но он не будет столь же эффективным, если у вас есть периоды, длящиеся несколько дней, например. 8:00 ~ 2:00, тогда я рекомендую использовать многопериодный дизайн.

   0: [
         id: 1,
         business_id: 1,
         open: true,
         day: 1,
         periods: [
             0: { open: 08:00, close: 23:59 }
         ]
      ],
   1: [
         id: 2,
         business_id: 1,
         open: true,
         day: 2,
         periods: [
             0: { open: 00:00, close: 02:00 }
             1: { open: 08:00, close: 23:59 }
         ]
      ]
Махмуд Али Кассем
источник
0

Можно подумать об учете праздников, включив дополнительные поля для месяца года / дня месяца / недели месяца. Неделя месяца имеет некоторые незначительные нюансы, «последней» может быть, например, 4 или 5 неделя в зависимости от года.

Эйнштейн
источник