ts
est une bibliothèque de date et d'heure pour Emacs. Il vise à être plus pratique que les modèles comme (string-to-number (format-time-string "%Y"))
en fournissant des accesseurs simples, comme (ts-year (ts-now))
.
Pour améliorer les performances (de manière significative), les parties de date formatées sont calculées paresseusement plutôt que lorsqu'un objet d'horodatage est instancié, et les parties calculées sont ensuite mises en cache pour un accès ultérieur sans recalcul. En coulisses, cela évite les appels inutiles (string-to-number (format-time-string...
, qui sont étonnamment coûteux.
Obtenez des parties de la date actuelle :
; ; When the current date is 2018-12-08 23:09:14 -0600:
(ts-year (ts-now)) ; => 2018
(ts-month (ts-now)) ; => 12
(ts-day (ts-now)) ; => 8
(ts-hour (ts-now)) ; => 23
(ts-minute (ts-now)) ; => 9
(ts-second (ts-now)) ; => 14
(ts-tz-offset (ts-now)) ; => "-0600"
(ts-dow (ts-now)) ; => 6
(ts-day-abbr (ts-now)) ; => "Sat"
(ts-day-name (ts-now)) ; => "Saturday"
(ts-month-abbr (ts-now)) ; => "Dec"
(ts-month-name (ts-now)) ; => "December"
(ts-tz-abbr (ts-now)) ; => "CST"
Incrémentez la date actuelle :
; ; By 10 years:
( list :now (ts-format)
:future (ts-format (ts-adjust 'year 10 (ts-now))))
; ;=> ( :now "2018-12-15 22:00:34 -0600"
; ; :future "2028-12-15 22:00:34 -0600")
; ; By 10 years, 2 months, 3 days, 5 hours, and 4 seconds:
( list :now (ts-format)
:future (ts-format
(ts-adjust 'year 10 'month 2 'day 3
'hour 5 'second 4
(ts-now))))
; ;=> ( :now "2018-12-15 22:02:31 -0600"
; ; :future "2029-02-19 03:02:35 -0600")
Quel jour de la semaine était il y a 2 jours ?
(ts-day-name (ts-dec 'day 2 (ts-now))) ; => "Thursday"
; ; Or, with threading macros:
( thread-last (ts-now) (ts-dec 'day 2 ) ts-day-name) ; => "Thursday"
(-> > (ts-now) (ts-dec 'day 2 ) ts-day-name) ; => "Thursday"
Obtenez l'horodatage pour cette heure la semaine dernière :
(ts-unix (ts-adjust 'day -7 (ts-now)))
; ;=> 1543728398.0
; ; To confirm that the difference really is 7 days:
( / ( - (ts-unix (ts-now))
(ts-unix (ts-adjust 'day -7 (ts-now))))
86400 )
; ;=> 7.000000567521762
; ; Or human-friendly as a list:
(ts-human-duration
(ts-difference (ts-now)
(ts-dec 'day 7 (ts-now))))
; ;=> (:years 0 :days 7 :hours 0 :minutes 0 :seconds 0)
; ; Or as a string:
(ts-human-format-duration
(ts-difference (ts-now)
(ts-dec 'day 7 (ts-now))))
; ;=> "7 days"
; ; Or confirm by formatting:
( list :now (ts-format)
:last-week (ts-format (ts-dec 'day 7 (ts-now))))
; ;=> ( :now "2018-12-08 23:31:37 -0600"
; ; :last-week "2018-12-01 23:31:37 -0600")
Certains accesseurs ont des alias similaires aux constructeurs format-time-string
:
(ts-hour (ts-now)) ; => 0
(ts-H (ts-now)) ; => 0
(ts-minute (ts-now)) ; => 56
(ts-min (ts-now)) ; => 56
(ts-M (ts-now)) ; => 56
(ts-second (ts-now)) ; => 38
(ts-sec (ts-now)) ; => 38
(ts-S (ts-now)) ; => 38
(ts-year (ts-now)) ; => 2018
(ts-Y (ts-now)) ; => 2018
(ts-month (ts-now)) ; => 12
(ts-m (ts-now)) ; => 12
(ts-day (ts-now)) ; => 9
(ts-d (ts-now)) ; => 9
Analysez une chaîne dans un objet d'horodatage et reformatez-la :
(ts-format (ts-parse " sat dec 8 2018 12:12:12 " )) ; => "2018-12-08 12:12:12 -0600"
; ; With a threading macro:
(-> > " sat dec 8 2018 12:12:12 "
ts-parse
ts-format) ; ;=> "2018-12-08 12:12:12 -0600"
Formatez la différence entre deux horodatages :
(ts-human-format-duration
(ts-difference (ts-now)
(ts-adjust 'day -400
'hour -2 'minute -1 'second -5
(ts-now))))
; ; => "1 years, 35 days, 2 hours, 1 minutes, 5 seconds"
; ; Abbreviated:
(ts-human-format-duration
(ts-difference (ts-now)
(ts-adjust 'day -400
'hour -2 'minute -1 'second -5
(ts-now)))
'abbr )
; ; => "1y35d2h1m5s"
Analysez un élément d'horodatage d'organisation directement à partir de org-element-context
et trouvez la différence entre celui-ci et maintenant :
( with-temp-buffer
( org-mode )
( save-excursion
( insert " <2015-09-24 Thu .+1d> " ))
(ts-human-format-duration
(ts-difference (ts-now)
(ts-parse-org-element ( org-element-context )))))
; ;=> "3 years, 308 days, 2 hours, 24 minutes, 21 seconds"
Analysez une chaîne d'horodatage d'organisation (qui a un répéteur) et formatez l'année et le mois :
; ; Note the use of `format' rather than `concat' , because `ts-year'
; ; returns the year as a number rather than a string.
( let* ((ts (ts-parse-org " <2015-09-24 Thu .+1d> " )))
( format " %s , %s " (ts-month-name ts) (ts-year ts)))
; ;=> "September, 2015"
; ; Or, using dash.el:
(-- > (ts-parse-org " <2015-09-24 Thu .+1d> " )
( format " %s , %s " (ts-month-name it) (ts-year it)))
; ;=> "September, 2015"
; ; Or, if you remember the format specifiers:
(ts-format " %B, %Y " (ts-parse-org " <2015-09-24 Thu .+1d> " ))
; ;=> "September, 2015"
À quand remonte cette date, en 1970 ?
( let* ((now (ts-now))
(then (ts-apply :year 1970 now)))
( list (ts-format then)
(ts-human-format-duration
(ts-difference now then))))
; ;=> ("1970-08-04 07:07:10 -0500"
; ; "49 years, 12 days")
Depuis quand cette époque a-t-elle commencé ?
(ts-human-format-duration
(ts-diff (ts-now) (make-ts :unix 0 )))
; ;=> "49 years, 227 days, 12 hours, 12 minutes, 30 seconds"
Au cours de laquelle des 100 dernières années Noël a-t-il eu lieu un samedi ?
( let ((ts (ts-parse " 2019-12-25 " ))
(limit ( - (ts-year (ts-now)) 100 )))
( cl-loop while ( >= (ts-year ts) limit)
when ( string= " Saturday " (ts-day-name ts))
collect (ts-year ts)
do (ts-decf (ts-year ts))))
; ;=> (2010 2004 1999 1993 1982 1976 1971 1965 1954 1948 1943 1937 1926 1920)
Pour un exemple plus intéressant, un horodatage se situe-t-il dans la semaine civile précédente ?
; ; First, define a function to return the range of the previous calendar week.
( defun last-week-range ()
" Return timestamps (BEG . END) spanning the previous calendar week. "
( let* ( ; ; Bind `now' to the current timestamp to ensure all calculations
; ; begin from the same timestamp. (In the unlikely event that
; ; the execution of this code spanned from one day into the next,
; ; that would cause a wrong result.)
(now (ts-now))
; ; We start by calculating the offsets for the beginning and
; ; ending timestamps using the current day of the week. Note
; ; that the `ts-dow' slot uses the "%w" format specifier, which
; ; counts from Sunday to Saturday as a number from 0 to 6.
(adjust-beg-day ( - ( + 7 (ts-dow now))))
(adjust-end-day ( - ( - 7 ( - 6 (ts-dow now)))))
; ; Make beginning/end timestamps based on `now' , with adjusted
; ; day and hour/minute/second values. These functions return
; ; new timestamps, so `now' is unchanged.
(beg ( thread-last now
; ; `ts-adjust' makes relative adjustments to timestamps.
(ts-adjust 'day adjust-beg-day)
; ; `ts-apply' applies absolute values to timestamps.
(ts-apply :hour 0 :minute 0 :second 0 )))
(end ( thread-last now
(ts-adjust 'day adjust-end-day)
(ts-apply :hour 23 :minute 59 :second 59 ))))
( cons beg end)))
(-let* ( ; ; Bind the default format string for `ts-format' , so the
; ; results are easy to understand.
(ts-default-format " %a, %Y-%m-%d %H:%M:%S %z " )
; ; Get the timestamp for 3 days before now.
(check-ts (ts-adjust 'day -3 (ts-now)))
; ; Get the range for the previous week from the function we defined.
((beg . end) (last-week-range)))
( list :last-week-beg (ts-format beg)
:check-ts (ts-format check-ts)
:last-week-end (ts-format end)
:in-range-p (ts-in beg end check-ts)))
; ;=> (:last-week-beg "Sun, 2019-08-04 00:00:00 -0500"
; ; :check-ts "Fri, 2019-08-09 10:00:34 -0500"
; ; :last-week-end "Sat, 2019-08-10 23:59:59 -0500"
; ; :in-range-p t)
ts-B (STRUCT)
ts
struct STRUCT
.ts-H (STRUCT)
ts
struct STRUCT
.ts-M (STRUCT)
ts
struct STRUCT
.ts-S (STRUCT)
ts
struct STRUCT
.ts-Y (STRUCT)
ts
struct STRUCT
.ts-b (STRUCT)
ts
struct STRUCT
.ts-d (STRUCT)
ts
struct STRUCT
.ts-day (STRUCT)
ts
struct STRUCT
.ts-day-abbr (STRUCT)
ts
struct STRUCT
.ts-day-name (STRUCT)
ts
struct STRUCT
.ts-day-of-month-num (STRUCT)
ts
struct STRUCT
.ts-day-of-week-abbr (STRUCT)
ts
struct STRUCT
.ts-day-of-week-name (STRUCT)
ts
struct STRUCT
.ts-day-of-week-num (STRUCT)
ts
struct STRUCT
.ts-day-of-year (STRUCT)
ts
struct STRUCT
.ts-dom (STRUCT)
ts
struct STRUCT
.ts-dow (STRUCT)
ts
struct STRUCT
.ts-doy (STRUCT)
ts
struct STRUCT
.ts-hour (STRUCT)
ts
struct STRUCT
.ts-internal (STRUCT)
ts
struct STRUCT
. Slot représente une valeur de temps interne à Emacs (par exemple telle que renvoyée par current-time
).ts-m (STRUCT)
ts
struct STRUCT
.ts-min (STRUCT)
ts
struct STRUCT
.ts-minute (STRUCT)
ts
struct STRUCT
.ts-month (STRUCT)
ts
struct STRUCT
.ts-month-abbr (STRUCT)
ts
struct STRUCT
.ts-month-name (STRUCT)
ts
struct STRUCT
.ts-month-num (STRUCT)
ts
struct STRUCT
.ts-moy (STRUCT)
ts
struct STRUCT
.ts-sec (STRUCT)
ts
struct STRUCT
.ts-second (STRUCT)
ts
struct STRUCT
.ts-tz-abbr (STRUCT)
ts
struct STRUCT
.ts-tz-offset (STRUCT)
ts
struct STRUCT
.ts-unix (STRUCT)
ts
struct STRUCT
.ts-week (STRUCT)
ts
struct STRUCT
.ts-week-of-year (STRUCT)
ts
struct STRUCT
.ts-woy (STRUCT)
ts
struct STRUCT
.ts-year (STRUCT)
ts
struct STRUCT
. ts-apply (&rest SLOTS TS)
TS
avec de nouvelles valeurs d'emplacement. Remplissez les emplacements d'horodatage, écrasez les valeurs d'emplacement données et renvoyez le nouvel horodatage avec la valeur d'horodatage Unix dérivée des nouvelles valeurs d'emplacement. SLOTS
est une liste de paires clé-valeur alternées comme celle transmise à make-ts
.ts-adjust (&rest ADJUSTMENTS)
ADJUSTMENTS
à TS
. ADJUSTMENTS
doivent être une série d’ SLOTS
et VALUES
alternés permettant de les ajuster. Par exemple, ce formulaire renvoie un nouvel horodatage correspondant à 47 heures dans le futur : (ts-adjust 'hour -1 'day +2 (ts-now))
Puisque l’argument timestamp est le dernier, il peut être utilisé dans une macro de thread.
ts-dec (SLOT VALUE TS)
TS
avec son SLOT
décrémenté de VALUE
. SLOT
doit être spécifié sous forme de symbole simple et non de mot-clé.ts-inc (SLOT VALUE TS)
TS
avec son SLOT
incrémenté de VALUE
. SLOT
doit être spécifié sous forme de symbole simple et non de mot-clé.ts-update (TS)
TS
après avoir mis à jour son horodatage Unix à partir de ses autres emplacements. Non destructif. À utiliser après avoir défini les emplacements avec, par exemple ts-fill
.Destructeur
ts-adjustf (TS &rest ADJUSTMENTS)
TS
ayant appliqué ADJUSTMENTS
. Cette fonction est destructrice, car elle appelle setf
sur TS
. ADJUSTMENTS
doivent être une série d’ SLOTS
et VALUES
alternés permettant de les ajuster. Par exemple, ce formulaire ajuste un horodatage à 47 heures dans le futur :
(let ((ts (ts-now))) (ts-adjustf ts 'hour -1 'day +2))
ts-decf (PLACE &optional (VALUE 1))
PLACE
de VALUE
(par défaut 1), mettez à jour son horodatage Unix et renvoyez la nouvelle valeur de PLACE
.ts-incf (PLACE &optional (VALUE 1))
PLACE
de VALUE
(par défaut 1), met à jour son horodatage Unix et renvoie la nouvelle valeur de PLACE
. ts-in (BEG END TS)
TS
est compris entre BEG
et END
, inclus. Tous les arguments doivent être des structures ts
.ts< (AB)
A
est inférieur à l'horodatage B
.ts<= (AB)
A
est <= horodatage B
.ts= (AB)
A
est le même que l'horodatage B
. Compare uniquement les emplacements unix
des horodatages. Notez que l'emplacement Unix d'un horodatage est un flottant et peut différer de moins d'une seconde, ce qui les rend inégaux même si toutes les parties formatées de l'horodatage sont identiques.ts> (AB)
A
est supérieur à l'horodatage B
.ts>= (AB)
A
est >= horodatage B
. ts-human-duration (SECONDS)
SECONDS
en années, jours, heures, minutes et secondes. Il s’agit d’un calcul simple qui ne prend pas en compte les années bissextiles, les secondes bissextiles, etc.ts-human-format-duration (SECONDS &optional ABBREVIATE)
SECONDS
. Si SECONDS
est inférieur à 1, renvoie "0 seconds"
. Si ABBREVIATE
n'est pas nul, renvoie une version plus courte, sans espaces. Il s’agit d’un calcul simple qui ne prend pas en compte les années bissextiles, les secondes bissextiles, etc. ts-format (&optional TS-OR-FORMAT-STRING TS)
format-time-string
. Si TS-OR-FORMAT-STRING
est un horodatage ou nul, utilisez la valeur de ts-default-format
. Si TS-OR-FORMAT-STRING
et TS
sont nuls, utilisez l’heure actuelle. ts-parse (STRING)
ts
, en analysant STRING
avec parse-time-string
.ts-parse-fill (FILL STRING)
ts
, en analysant STRING
avec parse-time-string
. Les valeurs heures/minutes/secondes vides sont remplies selon FILL
: if begin
, avec 0 ; si end
, l'heure est remplie de 23 et la minute/seconde de 59 ; si nul, une erreur peut être signalée lorsque les valeurs de temps sont vides. Notez que lorsque FILL
est end
, une valeur temporelle telle que « 12:12 » est remplie jusqu'à « 12:12:00 », et non « 12:12:59 ».ts-parse-org (ORG-TS-STRING)
ORG-TS-STRING
. Notez que la fonction org-parse-time-string
est appelée et doit être chargée avant d'appeler cette fonction.ts-parse-org-fill (FILL ORG-TS-STRING)
ORG-TS-STRING
. Notez que la fonction org-parse-time-string
est appelée et doit être chargée avant d'appeler cette fonction. Les valeurs heure/minute/seconde sont remplies selon FILL
: if begin
, avec 0 ; si end
, hour est rempli avec 23 et minute/seconde avec 59. Notez que org-parse-time-string
ne prend pas en charge les horodatages contenant des secondes.ts-parse-org-element (ELEMENT)
ELEMENT
. L'élément doit ressembler à celui analysé par org-element
, dont le premier élément est timestamp
. Suppose que l'horodatage n'est pas une plage. copy-ts (TS)
TS
.ts-difference (AB)
A
et B
.ts-diff
ts-difference
.ts-fill (TS &optional ZONE)
TS
ayant rempli tous les emplacements de son horodatage Unix. Ceci est non destructif. ZONE
est transmis à format-time-string
, qui voit.ts-now
ts
struct défini à maintenant.ts-p (STRUCT)
ts-reset (TS)
TS
avec tous les emplacements effacés sauf unix
. Non destructif. Le même que : (make-ts :unix (ts-unix ts))
ts-defstruct (&rest ARGS)
cl-defstruct
, mais avec des options d'emplacement supplémentaires.Options et valeurs d'emplacement supplémentaires :
:accessor-init
: un sexp qui initialise le slot dans l'accesseur si le slot est nul. La struct
du symbole sera liée à la structure actuelle. L'accesseur est défini une fois la structure entièrement définie, il peut donc faire référence à la définition de la structure (par exemple en utilisant la macro cl-struct
pcase
).
:aliases
: A
liste de symboles qui seront alias pour l'accesseur de slot, précédés du nom de la structure (par exemple, une struct ts
avec year
du slot et l'alias y
créerait un alias ts-y
).
ts-human-format-duration
vs format-seconds
Emacs a une fonction intégrée, format-seconds
, qui produit une sortie similaire à celle de ts-human-format-duration
. Sa sortie est également contrôlable avec une chaîne de format. Cependant, si la sortie de ts-human-format-duration
est suffisante, elle fonctionne bien mieux que format-seconds
. Ce test simple, exécuté 100 000 fois, montre qu'il s'exécute beaucoup plus rapidement et génère moins de déchets :
(bench-multi-lexical :times 100000
:forms (( " ts-human-format-duration " (ts-human-format-duration 15780.910933971405 t ))
( " format-seconds " ( format-seconds " %yy%dd%hh%mm%ss%z " 15780.910933971405 ))))
Formulaire | x plus vite que le suivant | Durée totale d'exécution | # de GC | Durée totale d'exécution du GC |
---|---|---|---|---|
ts-humain-format-durée | 5,82 | 0,832945 | 3 | 0,574929 |
format-secondes | le plus lent | 4.848253 | 17 | 3.288799 |
(Voir le manuel du développeur de packages Emacs pour la macro bench-multi-lexical
.)
Ajouté
ts-fill
accepte un argument ZONE
, comme celui passé à format-time-string
, qui voit. Fixé
ts-human-format-duration
a renvoyé une chaîne vide pour des durées inférieures à 1 seconde (renvoie désormais "0 seconds"
). Ajouté
ts-parse-fill
et ts-parse-org-fill
.ts-in
.Modifié
ts-now
n'est plus intégrée. Cela permet de le modifier au moment de l'exécution avec, par exemple, cl-letf
, ce qui est utile pour les tests.Fixé
ts-fill
. (La fonction split-string
, qui y est appelée, modifie les données de correspondance.)ts-parse-org
. (La fonction org-parse-time-string
, qui y est appelée, modifie les données de correspondance.)Documentation
Première version étiquetée. Publié sur MELPA.
GPLv3