ts
是 Emacs 的日期和時間庫。它的目標是透過提供簡單的存取器(如(ts-year (ts-now))
來比(string-to-number (format-time-string "%Y"))
等模式更方便。
為了(顯著)提高效能,格式化的日期部分是延遲計算的,而不是在實例化時間戳物件時計算的,然後快取計算出的部分以供以後訪問而無需重新計算。在幕後,這避免了不必要的(string-to-number (format-time-string...
調用,這些調用非常昂貴。
取得目前日期的部分內容:
; ; 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"
增加目前日期:
; ; 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")
兩天前是星期幾?
(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"
取得上週這個時間的時間戳記:
(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")
一些存取器具有類似於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
將字串解析為時間戳物件並重新格式化它:
(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"
設定兩個時間戳記之間的差異的格式:
(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"
直接從org-element-context
解析 Org 時間戳元素並找出它與現在之間的差異:
( 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"
解析 Org 時間戳字串(具有中繼器)並格式化年份和月份:
; ; 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"
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")
這個紀元是多久以前開始的?
(ts-human-format-duration
(ts-diff (ts-now) (make-ts :unix 0 )))
; ;=> "49 years, 227 days, 12 hours, 12 minutes, 30 seconds"
過去 100 年哪一個聖誕節是在星期六?
( 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)
舉一個更有趣的例子,時間戳記是否落在上一個日曆週?
; ; 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
的槽「month-name」。ts-H (STRUCT)
ts
struct STRUCT
的槽“hour”。ts-M (STRUCT)
ts
struct STRUCT
的槽“分鐘”。ts-S (STRUCT)
ts
struct STRUCT
的「第二個」槽。ts-Y (STRUCT)
ts
struct STRUCT
的槽“year”。ts-b (STRUCT)
ts
struct STRUCT
的槽「month-abbr」。ts-d (STRUCT)
ts
struct STRUCT
的槽「day」。ts-day (STRUCT)
ts
struct STRUCT
的槽「day」。ts-day-abbr (STRUCT)
ts
struct STRUCT
的槽「day-abbr」。ts-day-name (STRUCT)
ts
struct STRUCT
的槽「day-name」。ts-day-of-month-num (STRUCT)
ts
struct STRUCT
的槽「day」。ts-day-of-week-abbr (STRUCT)
ts
struct STRUCT
的槽「day-abbr」。ts-day-of-week-name (STRUCT)
ts
struct STRUCT
的槽「day-name」。ts-day-of-week-num (STRUCT)
ts
struct STRUCT
的槽「dow」。ts-day-of-year (STRUCT)
ts
struct STRUCT
的槽「doy」。ts-dom (STRUCT)
ts
struct STRUCT
的槽「day」。ts-dow (STRUCT)
ts
struct STRUCT
的槽「dow」。ts-doy (STRUCT)
ts
struct STRUCT
的槽「doy」。ts-hour (STRUCT)
ts
struct STRUCT
的槽“hour”。ts-internal (STRUCT)
ts
struct STRUCT
的「內部」槽。 Slot 表示 Emacs 內部時間值(例如,由current-time
傳回)。ts-m (STRUCT)
ts
struct STRUCT
的槽「month」。ts-min (STRUCT)
ts
struct STRUCT
的槽“分鐘”。ts-minute (STRUCT)
ts
struct STRUCT
的槽“分鐘”。ts-month (STRUCT)
ts
struct STRUCT
的槽「month」。ts-month-abbr (STRUCT)
ts
struct STRUCT
的槽「month-abbr」。ts-month-name (STRUCT)
ts
struct STRUCT
的槽「month-name」。ts-month-num (STRUCT)
ts
struct STRUCT
的槽「month」。ts-moy (STRUCT)
ts
struct STRUCT
的槽「month」。ts-sec (STRUCT)
ts
struct STRUCT
的「第二個」槽。ts-second (STRUCT)
ts
struct STRUCT
的「第二個」槽。ts-tz-abbr (STRUCT)
ts
struct STRUCT
的槽「tz-abbr」。ts-tz-offset (STRUCT)
ts
struct STRUCT
的槽「tz-offset」。ts-unix (STRUCT)
ts
struct STRUCT
的槽「unix」。ts-week (STRUCT)
ts
struct STRUCT
的槽「woy」。ts-week-of-year (STRUCT)
ts
struct STRUCT
的槽「woy」。ts-woy (STRUCT)
ts
struct STRUCT
的槽「woy」。ts-year (STRUCT)
ts
struct STRUCT
的槽“year”。 ts-apply (&rest SLOTS TS)
TS
傳回新時間戳記。填滿時間戳槽,覆蓋給定的槽值,並使用從新槽值派生的 Unix 時間戳值傳回新時間戳記。 SLOTS
是一個交替鍵值對的列表,就像傳遞給make-ts
那樣。ts-adjust (&rest ADJUSTMENTS)
ADJUSTMENTS
套用至TS
新時間戳記。 ADJUSTMENTS
應該是一系列交替的SLOTS
和VALUES
用於調整它們。例如,此表單傳回 47 小時後的新時間戳記: (ts-adjust 'hour -1 'day +2 (ts-now))
由於時間戳參數位於最後,因此它適合在線程巨集中使用。
ts-dec (SLOT VALUE TS)
TS
新時間戳,其SLOT
遞減VALUE
。 SLOT
應指定為普通符號,而不是關鍵字。ts-inc (SLOT VALUE TS)
TS
新時間戳,其SLOT
增加VALUE
。 SLOT
應指定為普通符號,而不是關鍵字。ts-update (TS)
TS
。非破壞性。設定插槽後使用,例如ts-fill
。破壞性的
ts-adjustf (TS &rest ADJUSTMENTS)
ADJUSTMENTS
時間戳TS
。該函數具有破壞性,因為它在TS
上呼叫setf
。 ADJUSTMENTS
應該是一系列交替的SLOTS
和VALUES
用於調整它們。例如,此表單將時間戳記調整為未來 47 小時:
(let ((ts (ts-now))) (ts-adjustf ts 'hour -1 'day +2))
ts-decf (PLACE &optional (VALUE 1))
PLACE
遞減VALUE
(預設為 1),更新其 Unix 時間戳,並傳回PLACE
的新值。ts-incf (PLACE &optional (VALUE 1))
PLACE
加入VALUE
(預設為 1),更新其 Unix 時間戳,並傳回PLACE
的新值。 ts-in (BEG END TS)
TS
在BEG
到END
範圍內(含),則傳回非零。所有參數都應該是ts
結構。ts< (AB)
A
小於時間戳B
則傳回非零。ts<= (AB)
A
<= 時間戳B
則回傳非零。ts= (AB)
A
與時間戳B
相同,則傳回非零。僅比較時間戳記的unix
插槽。請注意,時間戳的 Unix 時隙是浮點數,可能相差不到一秒,導致即使時間戳的所有格式化部分都相同,它們也會不相等。ts> (AB)
A
大於時間戳B
則傳回非零。ts>= (AB)
A
>= 時間戳B
則回傳非零。 ts-human-duration (SECONDS)
SECONDS
plist,以年、日、小時、分鐘和秒為單位。這是一個簡單的計算,沒有考慮閏年、閏秒等。ts-human-format-duration (SECONDS &optional ABBREVIATE)
SECONDS
的人類格式的字串。如果SECONDS
小於 1,則傳回"0 seconds"
。如果ABBREVIATE
不為零,則傳回較短的版本,不含空格。這是一個簡單的計算,沒有考慮閏年、閏秒等。 ts-format (&optional TS-OR-FORMAT-STRING TS)
format-time-string
設定時間戳格式。如果TS-OR-FORMAT-STRING
是時間戳記或 nil,則使用ts-default-format
的值。如果TS-OR-FORMAT-STRING
和TS
都為零,則使用目前時間。 ts-parse (STRING)
ts
結構,使用parse-time-string
解析STRING
。ts-parse-fill (FILL STRING)
ts
結構,使用parse-time-string
解析STRING
。空的小時/分鐘/秒值依FILL
填充:如果begin
,則為 0;如果end
,則小時填充為 23,分/秒填充為 59;如果為零,則當時間值為空時可能會發出錯誤訊號。請注意,當FILL
為end
時,像“12:12”這樣的時間值將填入“12:12:00”,而不是“12:12:59”。ts-parse-org (ORG-TS-STRING)
ORG-TS-STRING
的時間戳物件。請注意,呼叫了org-parse-time-string
函數,應在呼叫函數之前載入該函數。ts-parse-org-fill (FILL ORG-TS-STRING)
ORG-TS-STRING
的時間戳物件。請注意,呼叫了org-parse-time-string
函數,應在呼叫函數之前載入該函數。時/分/秒值依FILL
填充:如果begin
,則為 0;如果end
,小時填充為 23,分鐘/秒填充為 59 org-parse-time-string
ts-parse-org-element (ELEMENT)
ELEMENT
的時間戳物件。 Element 應該像org-element
解析的那樣,第一個元素是timestamp
。假設時間戳不是一個範圍。 copy-ts (TS)
TS
的副本。ts-difference (AB)
A
和B
之間的秒差。ts-diff
ts-difference
的別名。ts-fill (TS &optional ZONE)
TS
已填滿其 Unix 時間戳記的所有插槽。這是非破壞性的。 ZONE
被傳遞給format-time-string
,如下所示。ts-now
ts
結構集回傳到現在。ts-p (STRUCT)
ts-reset (TS)
TS
,清除除unix
之外的所有插槽。非破壞性。等同於: (make-ts :unix (ts-unix ts))
ts-defstruct (&rest ARGS)
cl-defstruct
類似,但具有額外的槽選項。其他插槽選項和值:
:accessor-init
:如果插槽為 nil,則初始化存取器中的插槽。符號struct
將綁定到目前結構。存取器是在結構體完全定義之後定義的,因此它可以引用結構體定義(例如,透過使用cl-struct
pcase
巨集)。
:aliases
:將作為插槽存取器的別名的符號A
,前綴為結構名稱(例如,帶有插槽year
和別名y
結構ts
將建立別名ts-y
)。
ts-human-format-duration
與format-seconds
Emacs 有一個內建函數format-seconds
,它產生類似ts-human-format-duration
的輸出。其輸出也可以透過格式字串進行控制。但是,如果ts-human-format-duration
的輸出足夠,它的性能比format-seconds
好得多。這個簡單的基準測試運行了 100,000 次,表明它運行得更快並且產生的垃圾更少:
(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 ))))
形式 | x 比下一個快 | 總運轉時間 | GC 數量 | GC 總運行時間 |
---|---|---|---|---|
ts-人類格式持續時間 | 5.82 | 0.832945 | 3 | 0.574929 |
格式秒 | 最慢的 | 4.848253 | 17 號 | 3.288799 |
(有關bench-multi-lexical
宏,請參閱 Emacs 套件開發人員手冊。)
額外
ts-fill
接受一個ZONE
參數,就像傳遞給format-time-string
參數一樣,參見。 固定的
ts-human-format-duration
傳回持續時間小於 1 秒的空字串(現在傳回"0 seconds"
)。 額外
ts-parse-fill
和ts-parse-org-fill
。ts-in
。改變了
ts-now
不再內聯。這允許在運行時使用cl-letf
進行更改,這對測試很有幫助。固定的
ts-fill
中。 (其中呼叫的函數split-string
會修改匹配資料。)ts-parse-org
中。 (其中呼叫的函數org-parse-time-string
會修改匹配資料。)文件
第一個標記發布。發佈到 MELPA。
GPLv3