15 sept. 2025·7 min de lecture
Streaks dans une app de suivi d'habitudes : définir les règles et gérer les fuseaux horaires
Définissez des règles claires pour les streaks d'un tracker d'habitudes, gérez les fuseaux horaires et les changements d'heure d'été, et évitez les réinitialisations erronées pour que les utilisateurs vous fassent confiance.

Pourquoi les streaks deviennent vite confus\n\nLes streaks semblent simples : faire l'habitude chaque jour pour garder la chaîne. En réalité, c'est émotionnel. Quand un streak se brise, les gens pensent avoir échoué — même si la logique de l'app a causé la réinitialisation. Une fois que la confiance est perdue, il est difficile de la regagner.\n\nLa plupart des confusions viennent d'une question discrète que votre app doit trancher : qu'est-ce qui compte comme "une journée" ?\n\nSi vous ne le définissez pas clairement, les utilisateurs auront des réinitialisations surprises ("je l'ai fait aujourd'hui !") ou des doubles comptages accidentels (un check-in tard le soir, puis un autre après minuit). Les voyages compliquent encore les choses. Un utilisateur coche à 23h30 à New York, prend un vol pour Los Angeles, puis ouvre l'app à 21h15 heure locale. L'a‑t‑il déjà fait "aujourd'hui" ? Ou la frontière de la journée a‑t‑elle bougé ?\n\nL'objectif n'est pas d'avoir le système de streaks le plus techniquement pur. C'est d'avoir des règles qui paraissent justes, qui se comportent de la même façon à chaque fois et qu'on peut expliquer dans l'app en une ou deux phrases.\n\nSi vous construisez avec des outils d'IA, la logique des streaks est un endroit commun où les cas limites passent à travers. Les prototypes couvrent souvent le chemin heureux à moins que vous ne forciez des scénarios comme les voyages, les check-ins tardifs, l'heure d'été et les changements d'horloge de l'appareil.\n\n## Décidez ce que signifie « une journée » dans votre app\n\nLes streaks paraissent justes seulement quand votre app est explicite sur ce qui compte comme une journée. Si vous laissez ça vague, deux personnes peuvent faire la même action et obtenir des résultats différents.\n\nD'abord, choisissez quelle horloge suivre :\n\n- Journée locale de l'utilisateur : une complétion compte sur la date calendaire locale actuelle de l'utilisateur. C'est naturel, mais les changements de fuseau horaire demandent une gestion soignée.\n- Journée UTC : une complétion compte selon la date UTC. C'est plus simple à implémenter, mais peut sembler contre‑intuitif (les check-ins du soir peuvent tomber dans le "lendemain").\n\nEnsuite, choisissez une frontière de journée. La plupart des apps utilisent minuit–minuit dans le fuseau choisi, mais il existe des alternatives raisonnables :\n\n- Minuit : familier et facile à expliquer.\n- Fenêtre glissante de 24 heures : mathématiquement consistante, mais déroutante parce que la "journée" bouge en permanence.\n- Coupure personnalisée (par exemple 3:00 AM) : plus douce pour les noctambules et les travailleurs en équipes, tant que c'est cohérent et clairement indiqué.\n\nUne coupure à minuit peut pénaliser quelqu'un qui termine une habitude à 00:30 après une longue soirée. Une coupure à 3:00 AM peut paraître plus humaine, mais seulement si vous l'expliquez clairement.\n\nÉcrivez la règle en une phrase que l'utilisateur peut répéter :\n\n"Votre streak compte une fois par jour calendaire, et votre journée va de 3:00 à 2:59 dans votre fuseau horaire actuel."\n\nSoyez strict sur ce point quand vous travaillez avec des outils d'IA. Beaucoup de prototypes générés mélangent accidentellement heure locale et UTC, ce qui mène à des réinitialisations soudaines que les utilisateurs ne pardonnent pas.\n\n## Définissez les règles de streak en langage clair\n\nLa plupart des bugs de streak commencent par des erreurs de formulation. Si deux personnes peuvent lire vos règles et ne pas être d'accord sur le résultat, votre app décevra quelqu'un.\n\nDécidez ce que signifie « complétion » :\n\n- Est‑ce un seul check‑in par jour, ou les utilisateurs peuvent-ils cocher plusieurs fois mais n'obtenir qu'un seul crédit ?\n- Si l'habitude suit une quantité (par exemple "boire 8 verres"), le progrès partiel prolonge‑t‑il le streak, ou seul un jour complètement complété compte ?\n\nPuis définissez quand le streak commence. Certaines apps commencent au moment du premier enregistrement de complétion. D'autres ne commencent qu'après le premier jour complet atteint. Les deux conviennent. Ce qui compte, c'est la cohérence entre l'onboarding, les statistiques et les notifications.\n\nUn ensemble de règles par défaut clair ressemble à ceci :\n\n- Une journée compte si l'habitude est marquée comme complète au moins une fois pendant cette journée.\n- Le progrès partiel est sauvegardé, mais n'étend pas le streak à moins que l'habitude n'atteigne 100%.\n- Le streak commence le premier jour où l'habitude est complétée.\n- Le streak se casse si une journée entière passe sans complétion.\n\nEnfin, décidez quand l'interface se met à jour. Les utilisateurs remarquent quand l'icône du streak indique 7 mais que le calendrier semble incomplet. Choisissez un moment où la valeur du streak change (souvent immédiatement après la complétion) et appliquez la même logique partout.\n\n## Choisissez un modèle : strict, flexible ou fenêtre de grâce\n\nLes streaks cessent d'être simples dès la première fois qu'un utilisateur coche à 00:05, voyage ou édite hier. Choisissez un modèle tôt, rédigez‑le et traitez‑le comme une décision produit (pas comme un détail d'implémentation de dernière minute).\n\n### 1) Streaks stricts (clairs, mais impitoyables)\n\nStrict veut dire : vous devez compléter l'habitude pendant la journée définie, et manquer un jour réinitialise le streak. Les check‑ins tardifs après minuit comptent pour le nouveau jour, pas pour le précédent.\n\nCe modèle est facile à expliquer et à calculer, mais il frustre les personnes qui font leurs habitudes la nuit.\n\n### 2) Streaks flexibles (plus adaptés à la vie réelle)\n\nFlexible signifie que l'app aide l'utilisateur à garder son élan. Approches courantes :\n\n- Une marge pour la nuit (par exemple, les check‑ins jusqu'à 2:00 AM comptent encore pour "hier").\n- Un jour de grâce limité (par exemple, un jour manqué autorisé par période roulante).\n\nCes règles réduisent les moments "je l'ai fait, mais l'app m'a puni".\n\n### Verrouillez les décisions qui créent des disputes\n\nLes conflits viennent presque toujours des mêmes choix :\n\n- Check‑ins tardifs : comptent‑ils pour la veille ou pour le jour courant ?\n- Jours manqués : réinitialisation immédiate, ou règle de "sauvegarde" limitée ?\n- Modifications/rétro‑saisie : interdites, autorisées dans une courte fenêtre, ou autorisées avec un flag explicite ?\n- Répétitions : exactement une fois par jour, ou "au moins une fois" ?\n\nQuoi que vous choisissiez, mettez‑le en évidence dans l'UI pour que personne ne soit surpris. Une courte ligne sous le chiffre du streak aide ("Les check‑ins tardifs comptent jusqu'à 2:00 AM"). Si une modification changerait un streak, affichez une confirmation au lieu de recalculer silencieusement.\n\n## Données à stocker pour rendre les streaks fiables\n\nUn streak n'est fiable que si les données qui le soutiennent le sont. Stockez des faits immuables, puis déduisez les clés de jour et les comptes de streak à partir de ces faits.\n\nCommencez par enregistrer chaque check‑in comme un événement. Chaque événement doit inclure un horodatage UTC. UTC est votre vérité de référence parce qu'il reste correct même si l'utilisateur voyage, change l'horloge de son téléphone ou traverse l'heure d'été.\n\nEnsuite, stockez le fuseau horaire de l'utilisateur et sa provenance. Le fuseau horaire n'est pas juste une étiquette — il fait partie de l'interprétation d'un même événement UTC en une date locale.\n\nUn jeu de champs simple qui évite la plupart des disputes :\n\n- checkin_at_utc (timestamp)\n- user_timezone (comme America/New_York)\n- timezone_source (device, manual, inferred)\n- local_date_key (optionnel, calculé au moment de l'écriture)\n- created_at_utc et created_by (pour l'audit)\n\nVous pouvez aussi stocker une ligne de résumé quotidien indexée par (user_id, habit_id, local_date) si vous avez besoin de vérifications rapides "l'a‑t‑il fait aujourd'hui ?". Traitez‑la comme un résumé dérivé, pas comme la source de vérité.\n\nSi vous autorisez les modifications sur des jours passés, gardez une trace d'audit. La plupart des tickets "mon streak s'est cassé !" viennent de backfills silencieux.\n\n## Le construire avec des outils d'IA sans manquer les cas limites\n\nCommencez par une petite spécification en anglais simple. Gardez‑la courte, mais précise :\n\n- Ce qui compte comme "fait"\n- Quand une journée commence et finit\n- Ce qui se passe si l'utilisateur voyage\n- Si un check‑in tardif peut encore compter\n\nCette spécification devient votre seule source de vérité.\n\nQuand vous demandez à votre outil d'IA de générer du code, demandez un modèle de données et un petit ensemble d'endpoints. Dites‑lui de garder la logique des fuseaux horaires côté serveur et de renvoyer des résultats de streak calculés par le serveur (pas quelque chose "calculé dans l'UI"). L'UI doit afficher des réponses, pas les inventer.\n\nGénérez des tests avant de construire l'écran calendrier. Couvrez :\n\n- Le franchissement de minuit\n- Le changement de fuseau horaire\n- Les changements d'heure d'été\n\nFaites d'abord échouer les tests, puis implémentez jusqu'à ce qu'ils passent. Cela évite les bugs "ça marche sur ma machine".\n\nAjoutez aussi un logging léger autour du recalcul des streaks : user ID, habit ID, fuseau horaire stocké, clé de jour calculée et valeur finale du streak. Quand quelqu'un signale "mon streak s'est réinitialisé", vous pourrez rejouer ce qui s'est passé.\n\n## Gérer les voyages et les changements de fuseau horaire\n\nLes voyages sont l'endroit où les streaks semblent souvent injustes. Un utilisateur fait l'habitude, mais l'app utilise silencieusement un fuseau horaire différent de celui auquel il s'attend, et le streak bascule.\n\nDécidez qui contrôle la règle du fuseau horaire. L'approche la plus propre est d'en faire un réglage utilisateur avec une valeur par défaut sensée.\n\n### Choisissez une règle pour les voyages (et tenez‑y vous)\n\nLa plupart des apps choisissent l'une de ces options :\n\n- Suivre l'heure locale actuelle : la "journée" est le fuseau horaire du téléphone en ce moment.\n- Verrouiller un fuseau horaire domicile : la "journée" est toujours basée sur un fuseau choisi.\n- Override manuel : l'utilisateur choisit un fuseau dans les réglages, et il reste jusqu'à changement.\n\nL'heure locale est naturelle si quelqu'un vit quelque part de façon prolongée. Un fuseau domicile évite des bizarreries sur des courts trajets, où les vols peuvent créer une journée anormalement longue ou courte.\n\n### Évitez les désaccords client vs serveur (surtout hors ligne)\n\nLes changements de fuseau peuvent créer deux réponses : ce que le téléphone affiche vs ce que le serveur accepte plus tard. Traitez chaque check‑in comme un événement avec une seule source de vérité.\n\nUne règle pratique : quand l'utilisateur appuie sur "Terminé", sauvegardez à la fois (1) l'horodatage exact et (2) le fuseau horaire utilisé pour calculer la clé de jour. Si l'utilisateur est hors ligne, utilisez la dernière règle connue et ne recalculez pas les anciens check‑ins quand l'appareil se reconnecte.\n\nDans les réglages, communiquez la règle en des mots simples :\n\n"Votre streak se réinitialise selon : Heure locale actuelle"\n\nou\n\n"Fuseau horaire domicile : America/New_York"\n\nAjoutez un avertissement d'une ligne : "Changer ceci peut déplacer les jours vers lesquels vos anciens check‑ins sont crédités."\n\n## Heure d'été et journées bizarres\n\nL'heure d'été crée des journées "bizarres" : certaines ont 23 heures (avancement) et d'autres 25 heures (retard). Si votre logique de streak suppose que chaque jour fait exactement 24 heures, vous finirez par surprendre des utilisateurs avec une réinitialisation ou un jour de streak en plus.\n\nLe plus grand piège est de calculer les streaks en soustrayant des heures depuis "maintenant" (par exemple, "le dernier check‑in était dans les 24 heures"). Lors d'une journée de 23 heures, 24 heures peut vous renvoyer à "hier" alors que l'utilisateur a bien coché le jour calendaire correct. Lors d'une journée de 25 heures, deux check‑ins qui semblent appartenir à des jours différents peuvent encore être "dans les 24 heures".\n\n### Comment éviter les bugs DST\n\nTraitez les streaks comme un problème calendaire, pas mathématique. Décidez de la "journée" de l'utilisateur en fonction d'un fuseau horaire et d'une frontière, puis comparez les dates calendaires dans ce fuseau.\n\nUne règle simple qui survit à l'heure d'été :\n\n"Une journée compte si l'utilisateur a au moins un check‑in entre 00:00 et 23:59:59 dans son fuseau horaire choisi."\n\nTestez l'heure d'été volontairement :\n\n- Jour de passage à l'heure d'été dans au moins deux zones (une qui observe DST, une qui ne l'observe pas)\n- Jour de retour à l'heure d'hiver, incluant les check‑ins autour de l'heure répétée\n- Check‑ins juste avant et juste après minuit\n\n### Rappels les jours de changement d'heure\n\nLes rappels peuvent sembler "étranges" pendant les weekends DST. Choisissez un comportement et gardez‑le cohérent. La plupart des apps conservent les rappels à la même heure locale (8:00 reste 8:00) car cela correspond aux attentes des utilisateurs.\n\n## Erreurs courantes qui cassent la confiance dans les streaks\n\nLa confiance se casse quand le calendrier ne correspond pas à ce que votre app compte. La façon la plus rapide de perdre la confiance est quand l'UI affiche "Fait aujourd'hui" mais le streak baisse quand même.\n\nCauses fréquentes :\n\n- Compter les jours en UTC côté serveur tout en affichant un calendrier local\n- Laisser le client calculer les streaks alors que le serveur stocke la vérité\n- Recalculer les streaks à plusieurs endroits (profil, écran d'accueil, job en arrière‑plan) avec des règles légèrement différentes\n- Rétro‑saisie illimitée qui rend les streaks sans valeur\n- Tests qui ne couvrent que des "semaines normales" et ignorent les dates limites\n\nLa rétro‑saisie doit avoir des limites. Une petite fenêtre (comme "vous pouvez marquer hier jusqu'à midi aujourd'hui") est raisonnable. Les modifications illimitées invitent aux disputes.\n\nNe sautez pas les dates limites dans les tests : frontières de mois, années bissextiles et les heures manquantes/répétées autour de DST.\n\n## Checklist rapide avant de livrer\n\nRendez le comportement des streaks prévisible et facile à expliquer. Si un utilisateur ne peut pas deviner si un check‑in tard compte, il cessera de faire confiance au streak.\n\nVoici la checklist pré‑livraison qui attrape la plupart des problèmes :\n\n- Une règle en une phrase qui définit ce qui "compte comme aujourd'hui", affichée dans l'UI\n- Les check‑ins stockés en UTC, plus le fuseau horaire de l'utilisateur au moment du check‑in\n- Une source unique de vérité pour le calcul des streaks (une fonction ou un service)\n- Tests pour les voyages, DST, check‑ins hors ligne, rétro‑saisie et activité tardive près de la coupure\n- Cohérence multi‑appareils : l'UI correspond aux résultats du serveur même si l'horloge d'un appareil est fausse\n\nTestez un scénario simple : un utilisateur coche à 23:58, puis à 00:05. Votre app doit se comporter de la même façon sur mobile et web, et le streak doit se mettre à jour de la même manière après un rafraîchissement.\n\n## Scénario exemple : voyager sans réinitialisation de streak\n\nUn utilisateur est à Los Angeles. Le lundi soir, il complète son habitude à 23:50 heure locale et voit : "Streak : 12 jours. Aujourd'hui est fait."\n\nIl prend un vol vers New York et atterrit tard. Après minuit, il ouvre l'app et son téléphone est déjà passé à l'heure de l'Est.\n\nSi votre règle est "une journée est basée sur la date locale actuelle de l'utilisateur" (l'attente la plus commune), lundi doit rester marqué comme complété cette nuit‑là. Le lendemain matin à New York, mardi est le nouveau jour et apparaît vide jusqu'à son check‑in.\n\nS'il coche à nouveau à 00:10 heure de New York, vous devez décider :\n\n- Un modèle strict dira que ça compte pour mardi, donc le streak devient 13.\n- Une fenêtre de grâce peut offrir un choix ("Compter pour lundi" vs "Compter pour mardi"), mais seulement si vous pouvez l'expliquer clairement.\n\nQuoi que vous choisissiez, rendez‑le débogable. Quand le support reçoit un message "mon streak s'est réinitialisé", il doit pouvoir voir :\n\n- L'horodatage en UTC et l'heure locale de l'utilisateur\n- Le fuseau horaire utilisé pour la décision (y compris l'offset)\n- La clé de jour calculée (comme 2026-01-21)\n- Si une fenêtre de grâce a été appliquée\n- Le jour final auquel le check‑in a été crédité\n\n## Étapes suivantes pour rendre un tracker d'habitudes construit par IA prêt pour la production\n\nTraitez la logique des streaks comme la logique de facturation : les petits détails comptent, et des modifications futures peuvent la casser.\n\nRédigez une spécification d'une page que vous pouvez coller dans des prompts et partager avec un coéquipier. Gardez‑la en langage clair. Incluez la frontière de journée, ce qui compte comme "fait" et ce qui se passe quand quelqu'un manque un jour.\n\nProtégez‑la ensuite avec un petit ensemble de tests (vous n'avez pas besoin de 200 tests). Choisissez 6 à 10 tests couvrant les check‑ins près de minuit, les réinitialisations pour jours manqués, les changements de fuseau, DST et la modification/rétro‑saisie (si vous l'autorisez).\n\nSi vous avez hérité d'un prototype généré par l'IA où la gestion du temps est incohérente, l'authentification cassée ou le code difficile à comprendre, FixMyMess (fixmymess.ai) peut réaliser un audit de code gratuit et aider à diagnostiquer et réparer la logique sous‑jacente pour que vous puissiez livrer en toute confiance.",
"meta_description": "Définissez des règles claires pour les streaks d'un tracker d'habitudes, gérez les fuseaux horaires et les changements d'heure d'été, et évitez les réinitialisations erronées pour que les utilisateurs vous fassent confiance.", "slug": "regles-streaks-tracker-habitudes-gestion-fuseaux-horaires",