https://pro.userland.fr/
Ruby, Rails, et les dates
Le temps, c’est rageant.
Goulven Champenois
Goulven Champenois
Développeur Ruby on Rails indépendant
Quelques croyances erronées
à propos du temps…
https://in
fi
niteundo.com/post/25326999628/falsehoods-programmers-believe-about-time
Le 31 mars, une insomnie…
1:59 3:00
📱
L’heure d’été !
🏊😎🚵
Appel du client
Mes évènements sont décalés d’1h !
- date + début
- date +
fi
n
Bug au passage
à l’heure d’été
Saisie simplifiée
Fusionner Date et Time
# DON'T DO THAT!
- date.change(hour: time.hour, min: time.min)
# OR
- Time.local(date.year, date.month, date.day, time.hour,
time.min, time.sec)
# DO THIS INSTEAD
+ time.change(year: date.year, month: date.month, day: date.day)
# OR
+ Time.utc(date.year, date.month, date.day, time.hour, time.min)
Quand du code manipule les heures,
toujours véri
fi
er qu’il gère l’heure d’été.
👀
Moralité
freeze_time
travel, travel_to, travel_back
ActiveSupport::Testing::TimeHelpers
🫶
En parlant d’été…
L’Australie
Fun fact :
3 fuseaux en « été »
5 fuseaux en « hiver »
🤦
J’ai bien lu +9,5 !?
24 38 fuseaux horaires
Décalés de 60, 45, 30,
ou 15 minutes
Et tout sauf linéaires…
Mais pourquoi 38 fuseaux ?
Parce que le temps c’est de l’argent,
—et de la politique, aussi.
Tout ça, c’est
à cause des rails
(et des trains)
Besoin d’horaires (départ et
arrivée)
Besoin que les villes aient toutes
la même heure
Quand les utilisateurs
vivent à di
ff
érents endroits,
toujours prendre en compte
les fuseaux horaires.
👀
Moralité
TimeWithZone ~= Time
Utilise la gemme TZ-info
Gère les fuseaux horaires
Gère aussi l’heure d’été
ActiveSupport::TimeWithZone
🫶
Manipuler les dates et les heures
# DON'T DO THAT!
- Time.now
- Time.parse
# DO THIS INSTEAD
+ Time.zone.now
+ Time.zone.parse
https://thoughtbot.com/blog/its-about-time-zones
Afficher une date ou une heure
# DON'T DO THAT!
- I18n.l(time)
# DO THIS INSTEAD
+ I18n.l(time.in_time_zone(current_user.time_zone))
# OR, in ApplicationController
+ around_action :use_time_zone, if: :current_user
+ def use_time_zone(&block)
+ Time.use_zone(current_user.time_zone, &block)
+ end
Convertit les timestamps côté client
Facilite la gestion du cache
Gère l’I18N côté client
Permet d’écrire « il y a X secondes,
minutes… »
local_time
https://github.com/basecamp/local_time
Je parle trop vite ?
Faut que je boive alors 😊
Année solaire ou sidérale ?
Année solaire : 1 tour de soleil
Année sidérale : 365 rotations
Di
ff
érence : environ 5 heures !
-> années bissextiles
Un peu d’histoire…
✦ Calendrier Julien
✦ Mis en place par Jules César
✦ Introduit en 46 avant JC
(l’autre)
✦ Décalage : 11 minutes/an !
Le calendrier
Grégorien
✦ Introduit en 1582
✦ Par le pape Grégoire XIII
✦ Durée : 365,2422 jours/an
✦ C’est celui qu’on utilise !
✦ 350 ans pour que tout le
monde l’applique !
Les années bissextiles
Multiple de 4
Mais PAS de 100
SAUF multiple de 400
Exemples : 2000, 2020, 2024… 2100
2070 et 503 années bissextiles plus tard…
Le 29 février 2024…
Nouvelle-Zélande : pas d’essence
Suède : pas de CB au supermarché
Japon : pas de permis de conduire
Chine : pas de mariage
Paris : pas de lampadaires
Etc…
Quand du code manipule les dates,
toujours penser aux années bissextiles.
👀
Moralité
Modifier une date
# DON'T DO THAT!
- Date.new(2024, 2, 29).change(year: 2023)
# => Date::Error: invalid date
# WARNING
Time.new(2024, 2, 29).change(year: 2023)
# => 01 March 2023
# DO THIS INSTEAD
+ Date.new(2024, 2, 29).advance(years: -1)
# OR
+ Date.new(2024, 2, 29) - 1.year
# => 28 February 2023
Étend Numeric et Date/Time
Ajoute Date/Time.advance
Permet 1.month.ago, et
3.weeks.from_now
ActiveSupport::Duration
🫶
Jours, heures… secondes !
✦ Décalage du calendrier grégorien : 26 secondes/an
✦ Décalage année solaire/sidérale : variable
Du coup, on ajoute des
secondes intercalaires.
Qu’est-ce qui pourrait mal se passer ?
🫣
TL;DR
# DON'T DO THAT!
- t2 - t1
# => -1s
# DO THIS INSTEAD
+ (t2 - t1).clamp(0, t2)
# => 0
# Et attention aux divisions par zéro !
Quand du code manipule des durées,
toujours s’attendre à l’absurde.
Le temps informatique
n’est pas linéaire.
👀
Moralité
Étend Date et Time
date + 1.month
3.weeks_ago
before? et after?
Ajoute aussi all_day, all_week, all_month…
Et même on_weekend?
DateAndTime::Calculations
🫶
Les formats de dates
AAAA/MM/JJ
MM-JJ-AAAA
JJ/MM/AA
mois/JJ
AAAA/ jour de l’année
AA-W15-6
Calendrier bouddhiste (+543 ans) 🧘
Calendriers di
ff
érents
Conventions par pays
Préférences personnelles
Décalages entre machines
Le temps, c’est une langue
Temps du serveur / de la VM
Temps de la base de données
Temps de Rails (UTC par défaut)
Temps navigateur
Le temps est relatif
select_date / select_datetime
date_select / datetime_select
time_tag
time_ago_in_words
ActionView::Helpers::DateHelpers
🫶
Pour manipuler dates, heures ou durées
toujours utiliser les méthodes disponibles !
Et ne jamais faire con
fi
ance
aux utilisateurs 😉
👀
Moralité
One more thing?
Standard international
Interoperable (JS, PHP,
Java…)
Lisible, triable, non ambigu
Parfait pour les APIs !
ISO 8601
require 'time'
Time.zone.now.iso8601
Time.iso8601(string)
L’heure d’été
Les fuseaux horaires
Les années bissextiles
Les formats de dates
Les « failles » temporelles
👀
Toujours tester…
https://thoughtbot.com/blog/its-about-
time-zones
https://github.com/basecamp/local_time
https://codeofmatt.com/list-of-2024-leap-
day-bugs/
https://blog.cloud
fl
are.com/how-and-why-
the-leap-second-a
ff
ected-cloud
fl
are-dns/
https://in
fi
niteundo.com/post/
25326999628/falsehoods-programmers-
believe-about-time
Un peu de lecture
https://mastodon.social/@goulvench
https://pro.userland.fr/
https://www.linkedin.com/in/
goulvenchampenois/
Merci pour votre temps !

Ruby, Rails, et les dates —le temps, c'est rageant