Question

Nous construisons une application qui stocke les " heures de fonctionnement " pour diverses entreprises. Quel est le moyen le plus simple de représenter ces données afin de pouvoir facilement vérifier si un élément est ouvert?

Quelques options:

  • Segmentez les blocs (toutes les 15 minutes) que vous pouvez marquer "ouvert / fermé". La vérification implique de voir si le message "ouvert" le bit est défini pour le temps souhaité (un peu comme un horaire de train).
  • Stocker une liste de plages horaires (11h-14h, 17h-19h, etc.) et vérifier si l’heure actuelle se situe dans une plage spécifiée (c’est ce que fait notre cerveau lors de l’analyse des chaînes ci-dessus).

Quelqu'un at-il de l'expérience en matière de stockage et de consultation des informations sur les horaires et des conseils à donner?

(Il y a toutes sortes d’affaires délirantes comme "nous avons fermé le premier mardi du mois", mais nous la laisserons un autre jour).

Était-ce utile?

La solution

stocke chaque bloc de temps contigu comme une heure de début et une durée; cela facilite la vérification du moment où les heures franchissent les limites de la date

si vous êtes certain que les heures d'ouverture ne franchiront jamais les limites de la date (c'est-à-dire qu'il n'y aura jamais de vente ouverte toute la nuit ni de marathon de 72 heures, etc.), les heures de début et de fin suffiront

Autres conseils

La solution la plus flexible pourrait être l’approche par bits. Il y a 168 heures dans une semaine, donc il y a 672 périodes de 15 minutes. Cela ne représente que 84 octets d’espace, ce qui devrait être tolérable.

Je voudrais utiliser un tableau comme celui-ci:

BusinessID | weekDay | OpenTime | CloseTime 
---------------------------------------------
     1          1        9           13
     1          2        5           18
     1          3        5           18
     1          4        5           18
     1          5        5           18
     1          6        5           18
     1          7        5           18

Ici, notre entreprise a des horaires réguliers de 5 à 6 heures, mais moins le dimanche.

Une requête pour if open serait (psuedo-sql)

SELECT @isOpen = CAST
   (SELECT 1 FROM tblHours 
       WHERE BusinessId = @id AND weekDay = @Day 
       AND CONVERT(Currentime to 24 hour) IS BETWEEN(OpenTime,CloseTime)) AS BIT;

Si vous devez stocker des cas périphériques, ne disposez que de 365 entrées, une par jour ... ce n'est pas tellement grave, placez un index sur la colonne jour et la colonne businessId.

N'oubliez pas de stocker le fuseau horaire des entreprises dans un tableau séparé (normaliser!) et effectuez une transformation entre votre temps et celui-ci avant d'effectuer ces comparaisons.

Je pense que je choisirais personnellement une heure de début et de fin, car cela rendrait tout plus flexible. Une bonne question serait: quelle est la probabilité que la taille du bloc change à un moment donné? Ensuite, choisissez la solution qui correspond le mieux à votre situation (si elle est susceptible de changer, je choisirais définitivement les délais).

Vous pouvez les stocker sous forme de période et utiliser des segments dans votre application. De cette façon, vous avez une entrée facile en utilisant des blocs, tout en gardant la possibilité de changer de magasin de données.

Pour ajouter à ce que Johnathan Holland a déclaré , je permettrais plusieurs entrées pour le même jour.

J'autoriserais également le temps décimal ou une autre colonne pour les minutes.

Pourquoi? de nombreux restaurants et certaines entreprises, et de nombreuses entreprises du monde entier ont des pauses déjeuner et / ou après-midi. En outre, de nombreux restaurants (2 que je connais près de chez moi sont proches de l’heure), l’un ferme à 21h40 le dimanche et l’autre à 1h40.

Il existe également le problème des heures de congés, telles que les magasins qui ferment tôt le jour de Thanksgiving, par exemple, vous devez donc définir une substitution basée sur un calendrier.

Ce qui peut être fait, c’est une date / heure ouverte, une date / heure proche, comme celle-ci:

businessID  | datetime              | type
==========================================
        1     10/1/2008 10:30:00 AM    1
        1     10/1/2008 02:45:00 PM    0
        1     10/1/2008 05:15:00 PM    1
        1     10/2/2008 02:00:00 AM    0
        1     10/2/2008 10:30:00 AM    1

etc. (tapez: 1 étant ouvert et 0 fermé)

Et que tous les jours des 1 ou 2 prochaines années soient précalculés 1 à 2 ans à l’avance. Notez que vous n’auriez que 3 colonnes: int, date / heure / bit, la consommation de données devrait donc être minimale.

Cela vous permettra également de modifier des dates spécifiques pour les heures impaires pour des jours spéciaux, au fur et à mesure qu'elles sont connues.

Il prend également en charge les passages au-dessus de minuit, ainsi que les conversions au format 12/24 heures.

Il est également indépendant du fuseau horaire. Si vous enregistrez l'heure de début et la durée, lorsque vous calculez l'heure de fin, votre machine va-t-elle vous donner l'heure ajustée TZ? Est-ce que c'est ce que tu veux? Plus de code.

jusqu'à la recherche d'un statut ouvert-fermé: interrogez la date et l'heure en question,

select top 1 type from thehours where datetimefield<=somedatetime and businessID = somebusinessid order by datetime desc

puis regardez "type". si elle est ouverte, si elle est 0, elle est fermée.

PS: Je suis dans le commerce de détail depuis 10 ans. Je connais donc bien les problèmes de petites heures dans les petites entreprises.

OK, je vais ajouter à cela pour ce que ça vaut.

Je dois gérer pas mal de choses.

  • Requête Rapide / Performante
  • Tous les incréments de temps, 21h01, 12h14, etc.
  • International (?) - Je ne suis pas sûr que ce soit un problème, même en ce qui concerne les fuseaux horaires, du moins dans mon cas, mais quelqu'un de plus expérimenté ici ne craint pas de donner son avis
  • Ouvert - Fermeture du lendemain (ouverture à midi, fermeture à 2h00)
  • Plusieurs périodes / jour
  • Possibilité de remplacer des jours spécifiques (vacances, peu importe)
  • Possibilité que les remplacements soient récurrents
  • Possibilité d'interroger un point quelconque dans le temps et d'ouvrir les entreprises (maintenant, à l'avenir, l'heure passée)
  • Possibilité d'exclure facilement les résultats des entreprises qui ferment leurs portes bientôt (filtrez les entreprises qui se ferment en 30 minutes, vous ne voulez pas que les utilisateurs soient comme ceux qui apparaissent 5 minutes avant de fermer dans le secteur des produits alimentaires et des boissons)

J'aime beaucoup les approches présentées et j'emprunte certaines d'entre elles. Sur mon site Web, projet, quels que soient mes besoins, je peux avoir des millions d’entreprises et quelques-unes des approches proposées ici ne semblent pas bien évoluer pour moi personnellement.

Voici ce que je propose pour un algorithme et une structure.

Nous devons formuler des hypothèses concrètes, partout dans le monde, n'importe où, n'importe quand: Il y a 7 jours dans une semaine. Il y a 1440 minutes dans une journée. Il existe un nombre fini de permutations de minutes d'ouverture / fermeture possibles.

Pas des hypothèses concrètes mais décentes: De nombreuses permutations de minutes ouvertes / fermées seront partagées entre les entreprises, réduisant ainsi le nombre total de permutations réellement stockées. Il fut un temps dans ma vie où je pouvais facilement calculer les combinaisons possibles de cette approche, mais si quelqu'un pouvait aider / pensait que ce serait utile, ce serait formidable.

Je propose 3 tables: Avant d'arrêter de lire, considérez que dans le monde réel, 2 de ces tables seront suffisamment petites pour que le cache soit parfaitement. Cette approche ne conviendra pas à tout le monde non plus en raison de la complexité du code nécessaire pour interpréter une interface utilisateur au modèle de données et inversement si nécessaire. Votre kilométrage et vos besoins peuvent varier. C’est une tentative de solution raisonnable au niveau de l’entreprise, peu importe ce que cela signifie.

Table HoursOfOperations

ID | OUVERTURE (minute de la journée) | CLOSE (minute de la journée)

1 | 360 | 10 h 20 (exemple: 9 h à 17 h)

2 | 365 | 1021 (exemple: Edge-Case 9h05 - 17h01 (bizarre))

etc.

HoursOfOperations ne se soucie pas de quels jours, ouvrez et fermez et unique. Il ne peut y avoir qu'une seule entrée par combinaison d'ouverture / fermeture. Maintenant, en fonction de votre environnement, cette table entière peut être mise en cache ou bien pour l'heure en cours de la journée, etc. Quoi qu'il en soit, vous ne devriez pas avoir à interroger cette table pour chaque opération. En fonction de votre solution de stockage, toutes les colonnes de cette table sont considérées comme indexées en termes de performances. À mesure que le temps passe, cette table a probablement une probabilité inverse exponentielle de INSERT (s). Vraiment cependant, traiter avec cette table devrait être principalement une opération en cours de processus (RAM).

Business2HoursMap

Remarque: dans mon exemple, je stocke " Jour " en tant que champ / colonne de bit-flag. Ceci est dû en grande partie à mes besoins et à l'avancement de LINQ / Flags Enums en C #. Rien ne vous empêche d'élargir ce champ aux champs 7 bits. Les deux approches doivent être relativement similaires dans la logique de stockage et dans la requête.

Autre remarque: je n’entre pas dans un argument de sémantique sur "chaque table a besoin d’une colonne d’ID PK", veuillez trouver un autre forum pour cela.

BusinessID | HeuresID | Journée (ou, si vous préférez, divisée en: BIT lundi, BIT mardi, ...)

1 | 1 | 1111111 (cette entreprise est ouverte de 9h à 17h tous les jours de la semaine)

2 | 2 | 1111110 (cette entreprise est ouverte de 9h05 à 17h01 (lundi = jour 1)

La raison pour laquelle il est facile d'interroger est que nous pouvons toujours déterminer assez facilement le MOTD (minute du jour) que nous recherchons. Si je veux savoir ce qui est ouvert à 17 heures demain, je saisis tous les HoursOfOperations IDS WHERE Close > = = 1020. À moins que je ne cherche une plage horaire, Open devient insignifiant. Si vous ne souhaitez pas que les entreprises qui ferment leurs portes soient fermées dans la prochaine demi-heure, ajustez simplement votre heure d'arrivée en conséquence (recherchez 17h30) et non 17h00 (10h20). La deuxième requête serait naturellement «donnez-moi toutes les affaires avec HoursID IN (1, 2, 3, 4, 5), etc.». Cela devrait probablement déclencher un drapeau rouge car cette approche présente des limites. Cependant, si quelqu'un peut répondre à la question ci-dessus sur les permutations, nous pourrons peut-être baisser le drapeau rouge. Considérez que nous n'avons besoin que des permutations possibles d'un côté ou de l'autre de l'équation à la fois, ouvertes ou fermées.

Considérant que nous avons notre première table mise en cache, c’est une opération rapide. La deuxième opération consiste à interroger cette table potentiellement très volumineuse, mais nous recherchons de très petites colonnes (SMALLINT), espérons-le indexées.

Maintenant, vous voyez peut-être la complexité du côté du code. Je cible principalement les bars de mon projet. Il est donc très prudent de supposer que j'aurai un nombre considérable d’entreprises ayant des horaires tels que "11 h 00 - 02 h 00 (le lendemain)". . Ce serait en effet 2 entrées dans la table HoursOfOperations ainsi que dans la table Business2HoursMap. Par exemple. un bar ouvert de 11h00 à 2h00 aura 2 références au tableau HeuresOpOpérations 660 - 1440 (11h00 - Minuit) et 0 - 120 (Minuit - 2h00). Ces références seraient reflétées dans les jours réels dans le tableau Business2HoursMap sous la forme de 2 entrées dans notre cas simpliste, 1 entrée = tous les jours Référence n ° 1, une autre référence tous les jours n ° 2. J'espère que cela a du sens, la journée a été longue.

Annuler certains jours / jours fériés / peu importe. Les dérogations sont par nature, basées sur la date et non sur le jour de la semaine. Je pense que c’est là que certaines approches tentent d’enfoncer la proverbiale rondelle dans un trou carré. Nous avons besoin d’une autre table.

HeuresID | BusinessID | Jour | Mois | Année

1 | 2 | 1 | 1 | NULL

Cela peut certainement devenir plus complexe si vous aviez besoin de quelque chose comme "un mardi sur deux, cette entreprise va pêcher pendant 4 heures". Cependant, cela nous permettra de faire assez facilement, c’est autoriser 1 - dérogations, 2 - dérogations récurrentes raisonnables. PAR EXEMPLE. Si l'année est nulle, chaque année le jour du Nouvel An, ce bar bizarre est ouvert de 9h00 à 17h00, conformément aux exemples de données ci-dessus. C'est à dire. - Si l'année a été définie, c'est uniquement pour 2013. Si le mois est nul, c'est tous les premiers jours du mois. Encore une fois, cela ne gérera pas tous les scénarios de planification en utilisant uniquement des colonnes NULL, mais en théorie, vous pouvez tout faire en vous fiant à une longue séquence de dates absolues, si nécessaire.

Encore une fois, je mettrais cette table en cache jour par jour. Je ne peux tout simplement pas voir de manière réaliste que les lignes de cette table dans un instantané de la journée sont très volumineuses, du moins pour mes besoins. Je vérifierais d’abord cette table, car c’est bien, une substitution et je sauverais une requête par rapport à la table beaucoup plus grande de Business2HoursMap du côté du stockage.

Problème intéressant. Je suis vraiment surpris que ce soit la première fois que j'ai vraiment besoin de réfléchir à cela. Comme toujours, je tiens beaucoup à différentes idées, approches ou défauts de mon approche.

Les blocs de segments sont meilleurs, assurez-vous simplement de donner à l'utilisateur un moyen facile de les définir. Cliquez et glissez c'est bien.

Tout autre système (comme les gammes) sera vraiment ennuyeux lorsque vous dépasserez la limite de minuit.

Pour ce qui est de la manière dont vous les stockez, les champs de bits en C ++ seraient probablement les meilleurs. Dans la plupart des autres langues, les tableaux pourraient être meilleurs (beaucoup d’espace perdu, mais ils seraient plus rapides et plus faciles à comprendre).

Je penserais un peu à ces cas marginaux en ce moment, car ils vont indiquer si vous avez une configuration de base plus une superposition ou un stockage statique complet des heures d'ouverture ou autre.

Il y a tellement d'exceptions - et régulièrement (comme les jours de neige, les vacances irrégulières comme Pâques et le vendredi saint), si on s'attend à ce que cela soit une représentation fiable de la réalité (par opposition à une bonne supposition), vous Il va falloir y remédier bientôt dans l'architecture.

Que diriez-vous de quelque chose comme ça:

Tableau des heures de magasin

Business_id (int)
Start_Time (time)
End_Time (time)
Condition varchar/string
Open bit

'Condition' est une expression lambda (texte d'une clause 'where'). Construisez la requête de manière dynamique. Donc, pour une entreprise particulière, vous sélectionnez toutes les heures d'ouverture / fermeture

Let Query1 = select count(open) from store_hours where @t between start_time and end_time and open  = true and business_id = @id and (.. dynamically built expression)

Let Query2 = select count(closed) from store_hours where @t between start_time and end_time and open = false and business_id = @id and (.. dynamically built expression)

Alors finissez par vouloir quelque chose comme:

select cast(Query1 as bit) & ~cast(Query2 as bit)

Si le résultat de la dernière requête est 1, le magasin est ouvert à l'heure t, sinon il est fermé.

Vous avez maintenant besoin d'une interface conviviale capable de générer pour vous vos clauses where (expressions lambda).

Le seul autre cas auquel je puisse penser est ce qui se passe si un magasin est ouvert de 7 heures à 2 heures du matin, par exemple, mais ferme à 23 heures le jour suivant. Votre système devrait également pouvoir gérer cela en répartissant intelligemment les temps entre les deux jours.

Il n’est sûrement pas nécessaire de conserver la mémoire, mais peut-être un code propre et compréhensible. " Bit twiddling " n'est pas, à mon humble avis, la voie à suivre.

Nous avons besoin d'un conteneur d'ensemble ici, qui contient un nombre quelconque d'éléments uniques et peut déterminer rapidement et facilement si un élément est un membre ou non. La configuration demande du temps, mais en routine, utiliser une seule ligne de code simplement comprise détermine si vous êtes ouvert ou fermé

Concept: Attribuez un numéro d’indice à chaque bloc de 15 minutes à partir de, disons, dimanche à minuit.

Initialiser: Insérez dans un ensemble le numéro d'index de chaque bloc de 15 minutes lorsque vous êtes ouvert. (En supposant que vous êtes ouvert moins d'heures que vous êtes fermé.)

Utiliser: Soustrayez du temps intéressant, en minutes, minuit le dimanche précédent et divisez-le par 15. Si ce nombre est présent dans l'ensemble, vous êtes ouvert.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top