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")
2日前は何曜日でしたか?
(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"
2 つのタイムスタンプの差をフォーマットします。
(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
から組織のタイムスタンプ要素を直接解析し、現在との違いを見つけます。
( 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"
組織のタイムスタンプ文字列 (リピーターを含む) を解析し、年と月をフォーマットします。
; ; 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
のスロット「月名」にアクセスします。ts-H (STRUCT)
ts
struct STRUCT
のスロット「時間」にアクセスします。ts-M (STRUCT)
ts
struct STRUCT
のスロット「分」にアクセスします。ts-S (STRUCT)
ts
struct STRUCT
のスロット「2 番目」にアクセスします。ts-Y (STRUCT)
ts
struct STRUCT
のスロット「年」にアクセスします。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
のスロット「時間」にアクセスします。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
のスロット「月名」にアクセスします。ts-month-num (STRUCT)
ts
struct STRUCT
のスロット「month」にアクセスします。ts-moy (STRUCT)
ts
struct STRUCT
のスロット「month」にアクセスします。ts-sec (STRUCT)
ts
struct STRUCT
のスロット「2 番目」にアクセスします。ts-second (STRUCT)
ts
struct STRUCT
のスロット「2 番目」にアクセスします。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
のスロット「年」にアクセスします。 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)
VALUE
だけ減分されたSLOT
を持つTS
に基づいて新しいタイムスタンプを返します。 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
までの範囲内にある場合は非 nil を返します。すべての引数はts
構造体である必要があります。ts< (AB)
A
がタイムスタンプB
より小さい場合は、非 nil を返します。ts<= (AB)
A
<= タイムスタンプB
の場合、非 nil を返します。ts= (AB)
A
がタイムスタンプB
と同じ場合は、非 nil を返します。タイムスタンプのunix
スロットのみを比較します。タイムスタンプの Unix スロットは浮動小数点数であり、その差が 1 秒未満である場合があるため、タイムスタンプのフォーマットされた部分がすべて同じであっても、それらが不等になることに注意してください。ts> (AB)
A
がタイムスタンプB
より大きい場合は、非 nil を返します。ts>= (AB)
A
>= タイムスタンプB
の場合、非 nil を返します。 ts-human-duration (SECONDS)
SECONDS
年、日、時、分、秒で記述した plist を返します。閏年や閏秒などを考慮しない単純計算です。ts-human-format-duration (SECONDS &optional ABBREVIATE)
SECONDS
を説明する人間がフォーマットした文字列を返します。 SECONDS
1 未満の場合は、 "0 seconds"
を返します。 ABBREVIATE
が非 nil の場合は、スペースを含まない短いバージョンを返します。閏年や閏秒などを考慮しない単純計算です。 ts-format (&optional TS-OR-FORMAT-STRING TS)
format-time-string
を使用してタイムスタンプをフォーマットします。 TS-OR-FORMAT-STRING
がタイムスタンプまたは nil の場合は、 ts-default-format
の値を使用します。 TS-OR-FORMAT-STRING
とTS
の両方が nil の場合は、現在の時刻を使用します。 ts-parse (STRING)
parse-time-string
でSTRING
解析して、新しいts
構造体を返します。ts-parse-fill (FILL STRING)
parse-time-string
でSTRING
解析して、新しいts
構造体を返します。空の時/分/秒の値は、 FILL
: begin
場合は 0 に従って埋められます。 end
の場合、時は 23 で埋められ、分/秒は 59 で埋められます。 nil の場合、時間値が空のときにエラーが通知される可能性があります。 FILL
がend
の場合、「12:12」のような時間値は、「12:12:59」ではなく「12:12:00」に埋められることに注意してください。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
のタイムスタンプ オブジェクトを返します。要素はorg-element
によって解析されたものと同様である必要があり、その最初の要素はtimestamp
です。タイムスタンプが範囲ではないことを前提としています。 copy-ts (TS)
TS
のコピーを返します。ts-difference (AB)
A
とB
の差を秒単位で返します。ts-diff
ts-difference
のエイリアス。ts-fill (TS &optional ZONE)
TS
を返します。これは非破壊的です。 ZONE
format-time-string
に渡されます。ts-now
ts
構造体を返します。ts-p (STRUCT)
ts-reset (TS)
unix
除くすべてのスロットをクリアしたTS
返します。非破壊的。以下と同じ: (make-ts :unix (ts-unix ts))
ts-defstruct (&rest ARGS)
cl-defstruct
と似ていますが、スロット オプションが追加されています。追加のスロット オプションと値:
:accessor-init
: スロットが nil の場合にアクセサー内のスロットを初期化する sexp。シンボルstruct
現在の構造体にバインドされます。アクセサは、構造体が完全に定義された後に定義されるため、(たとえばcl-struct
pcase
マクロを使用して) 構造体定義を参照する場合があります。
:aliases
: スロット アクセサーのエイリアスとなるシンボルのA
。先頭に構造体名が付加されます (たとえば、スロットyear
とエイリアスy
を持つ struct ts
エイリアスts-y
を作成します)。
ts-human-format-duration
とformat-seconds
の比較Emacs にはts-human-format-duration
と同様の出力を生成する組み込み関数format-seconds
があります。その出力はフォーマット文字列を使用して制御することもできます。ただし、 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 ))))
形状 | ×次よりも早い | 合計実行時間 | GC の数 | 合計 GC ランタイム |
---|---|---|---|---|
ts-human-format-duration | 5.82 | 0.832945 | 3 | 0.574929 |
フォーマット秒 | 最も遅い | 4.848253 | 17 | 3.288799 |
( bench-multi-lexical
マクロについては、『Emacs Package Developer's Handbook』を参照してください。)
追加した
ts-fill
、 format-time-string
に渡されるものと同様のZONE
引数を受け入れます。 修理済み
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
、一致データを変更します。)ドキュメント
初のタグ付きリリース。メルパに掲載されました。
GPLv3