Jiff, une bibliothèque de date et heure pour Rust
(github.com/BurntSushi)- Jiff est une bibliothèque de date et heure pour Rust, qui vise des types primitifs de date et heure de haut niveau difficiles à mal utiliser, avec des performances raisonnables
- Ses fonctions clés incluent l’intégration automatique à la Time Zone Database, l’arithmétique et l’arrondi tenant compte du DST, le formatage et le parsing sans perte des dates et heures avec fuseau horaire, ainsi qu’une prise en charge optionnelle de Serde
- La conception de l’API est fortement influencée par Temporal, la proposition du TC39 visant à améliorer la gestion des dates et heures en JavaScript
- La sortie de Jiff 1.0 était initialement visée pour l’été 2025, mais le calendrier a glissé en avril 2026 et il n’existe actuellement aucune échéance pour la version 1.0
- Les performances sont un objectif important, mais la compréhensibilité de l’API et la précision priment, avec une politique prudente sur les dépendances qui maintient volontairement zéro dépendance sur Unix
Le modèle de date et heure proposé par Jiff
- Jiff est une bibliothèque destinée à manipuler les dates et heures en Rust, centrée sur la fourniture de types primitifs de haut niveau difficiles à utiliser de manière incorrecte
- Principales fonctionnalités prises en charge
- intégration automatique et fluide avec la Time Zone Database
- arithmétique et arrondi tenant compte du DST
- formatage et parsing sans perte des dates et heures avec fuseau horaire
- prise en charge optionnelle de
serde
- La conception de l’API est fortement influencée par Temporal, la proposition du TC39 visant à améliorer la gestion des dates et heures en JavaScript
- La licence est une double licence MIT ou UNLICENSE
Documentation et exemples d’utilisation
- Documentation et ressources associées
- documentation de l’API sur docs.rs
- documentation comparative avec
chrono,time,hifitime,icu - document expliquant les choix de conception de l’API de Jiff
- documentation sur la prise en charge des plateformes
- journal des modifications
- L’exemple de base parse une chaîne temporelle RFC 3339, la convertit en date et heure avec fuseau horaire, ajoute une durée, puis l’affiche sous forme de chaîne sans perte
- parse
"2024-07-11T01:14:00Z"enTimestamp - conversion vers le fuseau horaire
America/New_York - ajout de
1.month().hours(2) - la chaîne résultante est
"2024-08-10T23:14:00-04:00[America/New_York]" - l’heure UTC au format RFC 3339 est
"2024-08-11T03:14:00Z"
- parse
Installation et flux d’exécution de base
- Jiff est disponible sur crates.io et peut être utilisé en ajoutant
jiffaux dépendances duCargo.tomld’un projet Rust - La commande d’ajout simple est
cargo add jiff - Flux complet de l’exemple dans le README
- création d’un nouveau projet avec
cargo new jiff-example - ajout de la dépendance avec
cargo add jiff - dans
src/main.rs, arrondi de l’heure actuelle à la seconde avecZoned::now().round(Unit::Second)? - exécution avec
cargo run
- création d’un nouveau projet avec
- La sortie d’exemple montre une forme incluant le fuseau horaire,
2024-07-10T19:54:20-04:00[America/New_York] - Lors de la première exécution, la sortie de compilation est plus abondante, mais les exécutions suivantes n’ont pas besoin de recompiler les dépendances
Feature flags et plan pour la version 1.0
- Jiff propose plusieurs fonctionnalités de crate permettant d’ajuster la prise en charge de la bibliothèque standard Rust, le support de
serdeet l’intégration ou non de la Time Zone Database dans le binaire - La liste complète des feature flags pris en charge figure dans la section « crate features » de la documentation
- Le plan de sortie initial de Jiff 1.0 visait l’été 2025, mais en avril 2026 le calendrier avait déjà glissé et il n’existe actuellement aucune échéance de sortie
- Après la sortie de la version 1.0, l’objectif est de maintenir l’API indéfiniment, afin que les utilisateurs puissent s’appuyer sur Jiff comme base stable de leur API publique
- Même après la sortie de Jiff 1.0, Jiff 0.2 devrait continuer à recevoir pendant un an des mises à jour de correction de bogues importants
- aucun développement actif de nouvelles fonctionnalités
- l’idée est d’offrir une période de transition aux nombreux utilisateurs déjà sur Jiff 0.2
Performances et voie de formatage avancée
- L’objectif de conception le plus important est de faire de Jiff une bibliothèque de date et heure de haut niveau difficile à mal utiliser
- Les performances sont le deuxième objectif, avec la recherche de performances raisonnables, même si certains domaines peuvent encore être améliorés
- Les benchmarks se trouvent dans le répertoire
bench - Certaines zones ont été optimisées, mais beaucoup ne le sont pas encore
- L’amélioration des performances est un objectif, mais en règle générale la compréhensibilité de l’API et la précision passent avant les performances
- Les sous-modules de Jiff, notamment
jiff::fmt, servent d’échappatoire vers des API plus complexes lorsqu’un contrôle plus fin est nécessaire- l’implémentation de
std::fmt::DisplaypourZonedpeut compliquer l’écriture dans un tampon réutilisable jiff::fmt::temporal::DateTimePrinter::print_zonedpermet d’écrire unZoneddans unStringou unVec<u8>existant
- l’implémentation de
Gestion des fuseaux horaires selon les plateformes
- Les problèmes de prise en charge des plateformes pour une bibliothèque de date et heure concernent principalement la prise en charge des fuseaux horaires
- Interactions avec la plateforme gérées par Jiff
- méthode pour trouver les données de transition d’un identifiant de fuseau horaire IANA comme
Antarctica/Troll - méthode pour trouver le fuseau horaire par défaut du système actuel
- méthode pour trouver les données de transition d’un identifiant de fuseau horaire IANA comme
- Les données de transition des fuseaux horaires dépendent de la IANA Time Zone Database
- Sur Unix, Jiff utilise généralement
/usr/share/zoneinfoet suit également le paramétrage de la variable d’environnementTZDIR - Sur Windows, une copie de la Time Zone Database est automatiquement intégrée à la bibliothèque compilée
- Méthodes de détection du fuseau horaire système
- sur Unix, lecture de
/etc/localtime - sur Windows, lecture de l’identifiant de fuseau horaire propre à Windows via
GetDynamicTimeZoneInformation, puis correspondance avec un identifiant IANA à l’aide des données XML CLDR d’Unicode
- sur Unix, lecture de
- La prise en charge d’autres plateformes devrait s’étendre avec le temps, mais pour les plateformes rares difficiles à tester, elle dépendra probablement des pull requests de contributeurs
Politique de dépendances et MSRV
- Le fait que Jiff ait zéro dépendance sur Unix est un choix de conception délibéré
- Les critères d’ajout d’une nouvelle dépendance à Jiff, crate de l’écosystème, sont prudents
- lorsqu’elle est réellement nécessaire pour interagir avec la plateforme
- lorsqu’elle est nécessaire pour l’interopérabilité, par exemple
serde
- Même les dépendances destinées à l’interopérabilité sont traitées avec prudence, avec une préférence générale pour celles qui publient moins souvent des breaking changes que Jiff
- Le découpage de Jiff en plusieurs crates pourrait introduire de nouvelles dépendances, mais ce n’est pas prévu actuellement
- L’objectif est de conserver un petit nombre de crates, l’expérience montrant qu’il existe un coût de maintenance élevé à gérer de nombreuses frontières d’API semver
- La version minimale du compilateur Rust prise en charge par Jiff est MSRV 1.70.0
- Jiff lui-même et les dépendances de Jiff présentes dans le dépôt n’utilisent pas de versions de Rust nécessitant un compilateur publié dans l’année précédente
- Les crates du dépôt qui dépendent de Jiff, comme
jiff-icu, peuvent utiliser une MSRV plus récente, mais sans exiger une MSRV plus récente que celle des crates avec lesquelles elles s’intègrent - La MSRV de dépendances externes comme
windows-sysouportable-atomicn’est pas sous le contrôle de Jiff - Conformément aux usages de l’écosystème Rust, Jiff ne considère pas une hausse de MSRV comme un changement incompatible semver, mais la limite à une mise à jour de version mineure
1 commentaires
Avis sur Hacker News
Dans l’ensemble, ça a l’air bien, mais j’ai tiqué sur la syntaxe ToSpan
let span = 5.days().hours(8).minutes(1);Le fait que seul le premier nombre soit placé devant, tandis que les autres passent en arguments de fonction, me paraît étrange
Si on n’aime pas ça, on peut écrire
let span = Span::new().days(5).hours(8).minutes(1);, et comme ça n’ajoute que quelques caractères, ce n’est pas si maluse jiff::{Timestamp, ToSpan};, j’ai tiqué sur le fait que"2024-07-11T01:14:00Z".parse()?soit parsé en TimestampSi je me souviens bien, Rust utilise quelque chose comme des interfaces plutôt que des classes, mais je me demande pourquoi l’import de la bibliothèque fait soudain apparaître une méthode
parse()sur les chaînes, et pourquoi cette méthode au nom aussi générique crée un objetTimestampJe me demande aussi si c’est le type à gauche qui détermine le sens de
str.parse(), et ce qui se passe si une bibliothèque de dates et une bibliothèque d’expressions Lisp ajoutent toutes deuxparse()aux chaînesÇa amène même à se demander pourquoi on n’utilise pas une syntaxe du genre
Timestamp.parse(str)let span = 5.days() + 8.hours() + 1.minutes();La syntaxe d’origine ressemble à quelque chose que Ruby ferait
À la lecture du code, ce serait mieux de voir d’abord qu’on manipule un span
let span = Span::days(5).hours(8).minutes(1);me paraît encore mieuxJ’ai souvent vu des gens sous-estimer la complexité des bibliothèques date/heure
On entend sans cesse des phrases comme « il suffit d’utiliser UTC/Unix time comme représentation interne », « les durées peuvent être exprimées en nanosecondes », « il suffit d’utiliser des offsets au lieu des fuseaux horaires »
Si vous pensez ainsi, lire le document de conception de Jiff vaut le coup : https://github.com/BurntSushi/jiff/blob/master/DESIGN.md
Comme on peut s’y attendre de BurntSushi, c’est excellent et détaillé
La comparaison avec chrono, la bibliothèque date/heure de facto standard en Rust, vaut aussi la lecture : https://docs.rs/jiff/latest/jiff/_documentation/comparison/i...
Des éléments comme l’arithmétique DST qui reste correcte après sérialisation/désérialisation, les durées arrondissables, l’arithmétique calendaire tenant compte des fuseaux horaires, ou la détection des conflits de fuseaux horaires historiques, rendent la bibliothèque exacte, utile et agréable à utiliser
chrono est une bibliothèque complète et « correcte », mais elle était rigide et pas vraiment facile à utiliser
J’utilisais déjà ripgrep avant que Debian fournisse
rgpar défaut, et j’ai aussi utilisé JodaTime à l’époque où certains pensaient encore qu’Eclipse était meilleur qu’IntelliJ IDEAMais nulle part dans ce document je ne vois de réfutation de « les durées peuvent être exprimées en nanosecondes »
Les utilisateurs doivent voir l’heure correcte selon leur fuseau horaire et le DST, mais les programmes, en général, non
Tant qu’on ne manipule pas directement plusieurs fuseaux horaires, représenter les durées en millisecondes/nanosecondes est généralement très sûr
Ce n’est pas parce que les humains ont inventé les fuseaux horaires et le DST que cela change le phénomène physique d’une horloge interne de CPU qui tic-tac des milliards de fois par seconde
Il suffit de regarder les noyaux de systèmes d’exploitation qui n’ont pas explosé sur la moitié de la planète il y a quelques jours : beaucoup de timeouts dans le code y sont exprimés en millisecondes
On pourrait comprendre à tort que, pour implémenter un « cooldown de 30 secondes », il faut ajouter 30 secondes à l’heure locale actuelle, l’enregistrer sous forme de chaîne incluant fuseau horaire, DST et format 12/24 h, puis vérifier jusqu’aux secondes intercalaires
Il suffit d’utiliser un timeout/cooldown de 30 secondes exprimé en millisecondes, et même s’il se déclenche 29 secondes plus tard du point de vue de l’utilisateur, on n’a pas à se soucier des secondes intercalaires
Ça a l’air d’être une super bibliothèque
Je me demande pourquoi BurntSushi crée une nouvelle bibliothèque
Je n’ai pas beaucoup manipulé les dates et heures en Rust, mais j’aimerais savoir si les bibliothèques existantes ont des problèmes de performance, si leurs API sont pénibles à utiliser, si c’est juste pour le fun, ou s’il y a une autre raison
L’implémentation de la bibliothèque standard Java n’était pas bonne, et JodaTime est apparu pour résoudre ce problème
Ensuite, Java 8 a intégré une nouvelle API DateTime fortement influencée par JodaTime, et comme elle faisait partie de la bibliothèque standard, les auteurs de bibliothèques ont pu l’adopter plus largement
https://www.joda.org/joda-time/
https://www.baeldung.com/java-8-date-time-intro
https://github.com/BurntSushi/jiff/blob/master/DESIGN.md
https://github.com/BurntSushi/jiff/blob/master/COMPARE.md
En résumé, c’est surtout pour l’API et la prise en charge des fuseaux horaires IANA
L’état des bibliothèques de calendrier en Rust n’est pas vraiment idéal
Dans Pandas, il y a
.tz_convert()et.tz_localize(), et les conversions de fuseau horaire s’arrêtent pratiquement làL’opération que je prends comme référence est « obtenir en UTC la première heure d’une journée CET/CEST pour une date donnée », et avec Pandas c’est très simple
Avec Chrono, il faut créer un
NaiveDate, le convertir enDateTime, puis le reconvertir enDateTime, et je n’ai pas trouvé de schéma cohérent pour ces conversionsParfois c’est une fonction membre, parfois une méthode statique de l’objet fuseau horaire
J’espère que quelqu’un remettra ça d’aplomb un jour. Jiff semble être un pas dans la bonne direction, mais sa syntaxe est parfois bizarre, donc j’aimerais quelque chose de plus prévisible
date(y, m, d).intz("Europe/Rome")?Si tu veux ensuite obtenir l’UTC, il suffit d’ajouter
with_time_zone(TimeZone::UTC)J’aimerais bien que tu expliques davantage en quoi Jiff pourrait être amélioré, et ce que tu trouves bizarre dans la syntaxe
« Chéri(e), réveille-toi, un nouveau BurntSushi vient de sortir »[0]
Plus sérieusement, je me demande si quelqu’un parmi les utilisateurs de Rust ici sait pourquoi ce crate n’utilise pas quelque chose comme
tracingC’est peut-être trop lourd. En taille de crate, ça représente presque la moitié
logest bien sûr très bien aussi, et je ne sais pas si tracer jusqu’aux appels d’opérations sur les fuseaux horaires est un cas d’usage courant, mais je me demandais s’il y avait une raison particulière[0] https://knowyourmeme.com/memes/wake-up-babe
logcomme une sorte de plus petit dénominateur communIl s’intègre aussi bien avec
tracing, donc c’est probablement pour ça que Jiff l’utiliseC’est aussi quelque chose qui est utilisé depuis les tout débuts de crates.io
Jiff n’a pas d’exigences au-delà de l’émission de messages à certains niveaux de log
Bien sûr, je pense que
tracingaurait aussi très bien fonctionnéBurntSushi est aussi la personne qui a créé tout l’écosystème des expressions régulières de Rust
Ce qui me manque le plus dans les bibliothèques de temps existantes, en Rust comme dans les autres écosystèmes, c’est la prise en charge des secondes intercalaires
C’est généralement parce qu’elles utilisent en interne des timestamps UNIX plutôt que le TAI, et cette bibliothèque ne fait malheureusement pas exception
Il semble y avoir un moyen de les prendre en charge dans une certaine mesure via les fichiers tzif, mais ce n’est pas une prise en charge de premier ordre
Il y a plus de détails dans l’issue Jiff correspondante : https://github.com/BurntSushi/jiff/issues/7
Le timestamp UNIX n’utilise pas la définition SI de la seconde, mais 1/86000 de la journée courante ; toutes les secondes UNIX n’ont donc pas la même durée, ce qui casse les calculs de durée corrects
Je comprends que c’était un compromis pour hériter de la compatibilité avec d’anciens systèmes de suivi du temps et accélérer le formatage calendaire, mais je ne pense pas que ce soit le bon compromis
Le timestamp UNIX mélange des préoccupations de représentation avec les données
À mon avis, les secondes intercalaires devraient être traitées exactement de la même manière que le 29 février ou les fuseaux horaires
hifitimene conviendrait-elle pas ?Chaque fois que les secondes intercalaires sont évoquées, la discussion semble généralement rester abstraite
Elles sont très rarement reliées à des cas d’usage du monde réel
Je comprends les cas d’usage scientifiques, et je pense que les bibliothèques spécialisées les gèrent bien
Pour le reste, je ne sais pas trop s’il faut davantage
Jiffse prononce avec un G dur, donc « Giff »goou celui degin« Jiff se prononce comme
gifavec un g doux, comme dansgem. »Certainement pas !
Je vais rester sur chrono †
† bien sûr, ça se prononce « trono », comme le
chdechaseAlors, ça se prononce jiff, ou gif ?
« Jiff se prononce
gif, avec un g doux comme dansgem. »Ah, je vois le genre de blague…
GIF s’est toujours prononcé « jif » selon son créateur, donc pour éviter la confusion, ce serait bien que le créateur de ce nouvel outil prononce Jiff « gif »