2 points par GN⁺ 2024-07-23 | 1 commentaires | Partager sur WhatsApp
  • 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" en Timestamp
    • 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"

Installation et flux d’exécution de base

  • Jiff est disponible sur crates.io et peut être utilisé en ajoutant jiff aux dépendances du Cargo.toml d’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 avec Zoned::now().round(Unit::Second)?
    • exécution avec cargo run
  • 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 serde et 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

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
  • 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/zoneinfo et suit également le paramétrage de la variable d’environnement TZDIR
  • 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
  • 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-sys ou portable-atomic n’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

 
GN⁺ 2024-07-23
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 mal

    • Après use jiff::{Timestamp, ToSpan};, j’ai tiqué sur le fait que "2024-07-11T01:14:00Z".parse()? soit parsé en Timestamp
      Si 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 objet Timestamp
      Je 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 deux parse() aux chaînes
      Ça amène même à se demander pourquoi on n’utilise pas une syntaxe du genre Timestamp.parse(str)
    • D’accord. Personnellement, je préfère let span = 5.days() + 8.hours() + 1.minutes();
    • J’aime mieux cette version, elle paraît cohérente
      La syntaxe d’origine ressemble à quelque chose que Ruby ferait
    • D’accord. Dans mon fil de pensée, j’ai envie d’indiquer d’abord ce que je fais, puis de préciser les détails, alors que cette syntaxe fait l’inverse
      À la lecture du code, ce serait mieux de voir d’abord qu’on manipule un span
    • Pour aller plus loin, let span = Span::days(5).hours(8).minutes(1); me paraît encore mieux
  • J’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’aime beaucoup ripgrep de BurntSushi, et je l’utilise tout le temps en l’appelant directement depuis Emacs
      J’utilisais déjà ripgrep avant que Debian fournisse rg par défaut, et j’ai aussi utilisé JodaTime à l’époque où certains pensaient encore qu’Eclipse était meilleur qu’IntelliJ IDEA
      Mais 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
    • Ce n’est qu’en voyant l’expression « qui fonctionne même après ser/de » que j’ai compris pourquoi le crate Serde s’appelle ainsi
    • Merci pour le document de conception. Je l’avais manqué en parcourant rapidement le dépôt au début ; il est bien écrit et a répondu à beaucoup de questions que je me posais
    • Pour une présentation amusante et accessible de la folie des dates et heures, la conférence de Kip Cole à ElixirConf 2022 est très bien : https://www.youtube.com/watch?v=4VfPvCI901c
    • Quelqu’un qui pense que les dates et heures sont faciles ne devrait pas être autorisé à s’approcher du scheduling ni du code de traitement des dates
  • Ç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’é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 en DateTime, puis le reconvertir en DateTime, et je n’ai pas trouvé de schéma cohérent pour ces conversions
    Parfois 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

    • On peut faire ça avec 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 tracing
    C’est peut-être trop lourd. En taille de crate, ça représente presque la moitié
    log est 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

    • Je vois log comme une sorte de plus petit dénominateur commun
      Il s’intègre aussi bien avec tracing, donc c’est probablement pour ça que Jiff l’utilise
      C’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 tracing aurait aussi très bien fonctionné
  • BurntSushi est aussi la personne qui a créé tout l’écosystème des expressions régulières de Rust

    • Je me souviens m’être disputé avec quelqu’un sur Reddit à propos de quelque chose, puis avoir compris qui était mon interlocuteur et avoir dit « très bien, j’arrête »
  • 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

    • Je me demande pourquoi c’est nécessaire. Quels sont les cas d’usage réels, et pourquoi une bibliothèque scientifique spécialisée comme hifitime ne 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
  • Jiff se prononce avec un G dur, donc « Giff »

    • Je ne suis pas anglophone natif : hard G, ça veut dire quoi exactement ? Je me demande si c’est le G de go ou celui de gin
  • « Jiff se prononce comme gif avec un g doux, comme dans gem. »
    Certainement pas !

    • On a passé un bon moment en étant numéro 1 sur Hacker News pendant un instant, mais il semble maintenant qu’un défaut fatal ait été révélé
      Je vais rester sur chrono †
      † bien sûr, ça se prononce « trono », comme le ch de chase
    • https://x.com/drgonzo123/status/527520297512345600
    • Bizarre, je pensais que Jiff se prononçait avec un « J » dur
    • Donc ça ne se prononce pas GIF, mais GIF ?!
  • Alors, ça se prononce jiff, ou gif ?

    • https://github.com/BurntSushi/jiff/blob/master/DESIGN.md#why...
      « Jiff se prononce gif, avec un g doux comme dans gem. »
      Ah, je vois le genre de blague…
    • Je pense que la prononciation, c’est la personne qui l’a créé qui décide
      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 »
    • Comme c’est une bibliothèque de gestion du temps, moi je vais juste l’appeler biff