Memorizzazione dell'orario di lavoro in un database


87

Attualmente sto cercando di trovare il modo migliore per memorizzare l'orario di apertura di un'azienda in un database.

Per esempio:

L'attività A ha i seguenti orari di apertura

  • Lunedì: 9:00 - 17:00
  • Martedì: 9:00 - 17:00
  • Mercoledì: 9:00 - 17:00
  • Giovedì: 9:00 - 17:00
  • Venerdì: 9:00 - 17:00
  • Sabato: 9:00 - 12:00
  • Domenica: chiuso

Attualmente ho un modello di dati simile al seguente

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

dove il "giorno" è limitato alla scelta dei 7 giorni della settimana in codice (tramite ORM). Per verificare se un'attività viene chiusa in un determinato giorno, controlla se open_time e close_time sono NULL. È correlato al business tramite una tabella intermedia (relazione molti a molti).

Qualcuno ha dei suggerimenti per questo schema di database? Qualcosa al riguardo non mi sembra giusto.


4
Perché è necessaria una relazione M-a-M tra la tabella business_hours e la tabella business? Se vuoi davvero fare in modo che più aziende condividano lo stesso record in business_hours, perché? Semanticamente, il fatto che "l'azienda C lavora dal T1 al T2 il giorno D" è piuttosto un oggetto valore che un'entità ... L'unica buona (?) Ragione che posso immaginare è l'ottimizzazione delle dimensioni di archiviazione (versione RDB del modello Flyweight, per così dire) se il numero di aziende dovrebbe essere enorme ...
Yarik

3
E le pause pranzo? E i giorni festivi?
Mawg dice di reintegrare Monica il

Risposte:


58

Nel complesso, non vedo niente di sbagliato in questo. Tranne ...

  1. Memorizzerei il giorno della settimana come numero intero utilizzando qualsiasi sistema di numerazione utilizzato dal linguaggio di programmazione nativo (nelle sue librerie). Ciò ridurrà la dimensione del database e rimuoverà i confronti di stringhe dal codice.

  2. Probabilmente metterei la chiave esterna al tavolo business proprio qui in questo tavolo. In questo modo non avrai bisogno di una tabella di collegamento.

Quindi immagino che farei:

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
)

Nella mia logica aziendale, vorrei imporre un vincolo che ogni "azienda" abbia almeno 7 "ore lavorative". ( Almeno perché Jon Skeet ha ragione, potresti volere orari di ferie.) Anche se potresti voler allentare questo vincolo semplicemente interrompendo gli "orari di lavoro" per i giorni in cui l'attività è chiusa.


1
Come faresti 2? Avere tutte le voci per tutte le attività anche quando il giorno / gli orari sono gli stessi?
Vinko Vrsalovic

7
Direi di si. Altrimenti, considera cosa accadrebbe se due aziende condividessero gli stessi orari, ma poi una di loro ha bisogno di cambiare l'orario. Dovresti rilevare il fatto che le ore sono cambiate e creare un nuovo record o modificare quello esistente, a seconda che sia condiviso o meno.
Erik Forbes

3
Non condividerei assolutamente le righe di questa tabella tra le aziende. Quel tipo di condivisione porta solo al dolore. La logica aziendale dell'app dovrebbe semplicemente imporre il vincolo che ogni azienda ha almeno 7 riferimenti "business_hours".
Frank Krueger

1
@Vinko: Ricorda che mentre i valori sono (attualmente) gli stessi, gli orari di apertura di due attività sono semanticamente distinti.
Draemon

1
Puoi anche usare una bitmap di 7 bit per "giorno". In questo modo non è necessario ripetere le stesse voci Esempio tutti i giorni lavorativi hanno gli stessi orari di lavoro, una voce è sufficiente.
ZolaKt

29

Una situazione che non è coperta da questo schema è rappresentata da diversi periodi di apertura in un giorno. Ad esempio, il pub locale è aperto dalle 12:00 alle 14:30 e dalle 17:00 alle 23:00.

Forse un botteghino del teatro è aperto per una matinée e uno spettacolo serale.

A quel punto devi decidere se puoi avere più voci per lo stesso giorno, o se devi rappresentare orari diversi nella stessa riga.

Che dire degli orari di apertura che attraversano la mezzanotte. Supponiamo che un bar sia aperto dalle 19:00 alle 02:00. Non puoi semplicemente confrontare gli orari di apertura e chiusura con il tempo che vuoi testare.


Ho finito per fare qualcosa come suggerito da @JordanFeldstein. Memorizzo array di "cambiamenti di stato", che includono il cambiamento (aperto o chiuso), il giorno della settimana e l'ora del giorno. Posso avere tutti i "cambiamenti" che voglio per ogni attività e ogni giorno. Un'attività può aprire un giorno e chiudere il successivo, aprire due volte (o x volte) al giorno, essere aperta 24 ore su 24 ma chiusa il lunedì, qualunque sia. È difficile da implementare, ma molto flessibile.
ironcito

Seguendo l'approccio di risposta migliore, preferirei aggiungere due colonne a business_hours: break_timee break_duration. È davvero raro avere 2 pause nello stesso giorno.
Frondor

13

In un certo senso dipende da cosa è necessario archiviarlo e da come potrebbero apparire i dati del mondo reale.
Se è necessario essere in grado di determinare se l'attività è aperta a un certo punto, potrebbe essere un po 'imbarazzante interrogare lo schema così come stabilito. La cosa più importante, però, è: avresti mai bisogno di provvedere a una chiusura a metà giornata?

Alcune opzioni includono;

  • Uno schema come quello che hai, ma con la possibilità di avere più periodi per lo stesso giorno. Sarebbe adatto per la pausa pranzo, ma renderebbe scomodo eseguire una query che fornisce gli orari di apertura per un determinato giorno, ad esempio per la presentazione a un utente.
  • Un approccio in stile bitmap; "000000000111111110000000" per 9-5. Lo svantaggio di questo approccio è che devi scegliere una granularità specifica, cioè ore intere o mezze ore o, appunto, minuti. Maggiore è la granularità, più difficile è la lettura dei dati per un essere umano. È possibile utilizzare operatori bit per bit per memorizzare questo valore come un singolo numero anziché come una stringa di numeri interi, ma di nuovo danneggia la leggibilità.

11

Ho imparato che se desideri che il markup dei dati di Google riconosca i tuoi dati, devi seguire queste linee guida:

https://schema.org/openingHours

http://schema.org/OpeningHoursSpecification Contiene "date valide", che è molto utile per alcune aziende.

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

Dovresti stare bene senza una chiave primaria, a meno che tu non permetta alle aziende di condividere le stesse ore con la tabella di join - è interessante notare che alla fine avresti un numero finito di combinazioni; Non sono sicuro di quanti sarebbero: p

Con uno dei miei progetti ho utilizzato le colonne:

[uInt] business_id, [uTinyInt] giorno, [char (11)] timeRange

Se vuoi supportare OpeningHoursSpecification, dovrai aggiungere validFrom e validThrough.

L'intervallo di tempo è formattato come: hh: mm-hh: mm

Ecco una funzione che lo analizza, puoi anche modificare questa funzione per analizzare solo una singola apertura / chiusura, se le mantieni come colonne separate nel DB.

In base alla mia esperienza, consiglierei di consentire più volte in un giorno, di consentire un modo per sapere se sono esplicitamente chiusi in quel giorno o aperti 24 ore su 24, 7 giorni su 7. Il mio ha detto che se mancava un giorno nel DB, l'attività sarebbe stata chiusa quel giorno.

/**
 * 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;
}

1

La maggior parte dei risultati funziona bene per lo scenario dato, ma non sarà altrettanto efficace se si hanno periodi che durano più giorni, ad es. 8:00 AM ~ 2:00 AM, quindi consiglio di utilizzare un design multi periodo.

   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

Potrei pensare di considerare le vacanze includendo campi aggiuntivi per mese dell'anno / giorno del mese / settimana del mese. La settimana del mese ha alcune sottigliezze minori "ultima" potrebbe ad esempio essere la settimana 4 o 5 a seconda dell'anno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.