これらの関数は、時刻値(Time of Dayを参照)をLispのタイムスタンプや暦情報に変換し、またその逆の変換も行います。
多くのオペレーティングシステムでは、秒のカウントに64ビット符号付き整数を使用しており、遥か過去や未来の時刻を表現できます。しかし、中にはより制約の多いものもあります。例えば、32ビット符号付き整数を使用する旧式のオペレーティングシステムでは、通常、協定世界時で1901-12-13 20:45:52から2038-01-19 03:14:07までの時刻しか扱えません。
暦変換関数は、グレゴリオ暦が導入される前の日付や、グレゴリオ暦では精度が著しく低く、ユリウス暦の年長を用いる天文学や古生物学といった科学分野の慣行とも一致しない遥か過去や未来の日付に対しても、グレゴリオ暦を使用する。年号は紀元前1年から数えられ、従来のグレゴリオ暦のように0を飛ばすことはない。例えば、年号 −37 はグレゴリオ暦の紀元前38年を表す。
この関数は、時刻値をLispのタイムスタンプに変換します。
引数 form は、返されるタイムスタンプの形式を指定します。form がシンボル integer
の場合、この関数は秒単位の整数値を返します。form
が正の整数の場合、それはクロック周波数を指定し、この関数は整数ペアのタイムスタンプ (ticks . form) を返します。form が t
の場合、この関数はそれをタイムスタンプの表現に適した正の整数として扱います。例えば、time が
nil であり、プラットフォームのタイムスタンプがナノ秒単位の分解能を持つ場合、それは
1000000000 として扱われます。form が list の場合、この関数は整数リスト (high low micro pico) を返します。現在、nil form は list と同様に動作しますが、これは将来の Emacs
バージョンで変更される予定であるため、リスト形式のタイムスタンプを必要とする呼び出し元は、list
を明示的に渡す必要があります。
time が時刻値でない場合、この関数はエラーを通知します。そうでない場合、time を正確に表現できないときは、変換によって負の無限大方向に切り捨てられます。form が t
である場合、変換は常に正確であるため切り捨ては発生せず、返されるクロック分解能は time
の分解能以上となります。対照的に、float-time
もエラーを通知することなく任意の時刻値を変換できますが、結果が正確にならない場合があります。Time of Day を参照してください。
効率性の観点から、この関数は eq から time
までの値、あるいはそれ以外の time と構造を共有する値を返す場合があります。
(time-convert nil nil) は (current-time) と同等ですが、後者の方がわずかに高速な場合があります。
(setq a (time-convert nil t)) ⇒ (1564826753904873156 . 1000000000)
(time-convert a 100000) ⇒ (156482675390487 . 100000)
(time-convert a 'integer) ⇒ 1564826753
(time-convert a 'list) ⇒ (23877 23681 904873 156000)
この関数は、時刻値を暦情報に変換します。time を指定しない場合は現在時刻をデコードし、同様に zone はデフォルトで現在のタイムゾーンルールが適用されます。タイムゾーンルール を参照してください。オペレーティングシステムにより、時刻およびゾーン値の範囲が制限されています。
form 引数は、以下に説明するように、返される seconds 要素の形式を制御します。戻り値は、次のような9つの要素からなるリストです。
(seconds minutes hour day month year dow dst utcoff)
各要素の意味は以下の通りです。
分経過後の秒数。形式については以下に記述する。
正時からの経過分数(0から59までの整数)。
0から23までの整数で表される時刻。
月の日付を1から31までの整数で。
1月から12までの整数で表される月の番号。
年。通常は1900より大きい整数。
曜日を0から6までの整数で表したもの。ただし、0は日曜日を指す。
t 夏時間が適用されている場合、nil
適用されていない場合、および −1 この情報が利用できない場合。
協定世界時との時差を秒単位で示す整数。すなわち、グリニッジから東に何秒離れているかを示す。
seconds 要素は Lisp のタイムスタンプであり、非負かつ 61
未満です。正の閏秒の期間を除き(オペレーティングシステムが閏秒をサポートしている場合)、60 未満となります。オプションの form 引数が t の場合、seconds は time と同じ精度を用います。form が integer の場合、seconds は整数に切り捨てられます。例えば、time
がタイムスタンプ (1566009571321 . 1000)
であり、これが閏秒のない一般的なシステムにおいて 2019-08-17 02:39:31.321 UTC を表す場合、(decode-time time t t) は ((31321 . 1000) 39 2 17 8 2019 6 nil 0) を返し、一方で (decode-time time t 'integer) は
(31 39 2 17 8 2019 6 nil 0) を返します。form が省略されるか nil の場合、現在はデフォルトで
integer となりますが、このデフォルトは今後の Emacs
リリースで変更される可能性があるため、特定の形式を必要とする呼び出し元は form を指定すべきです。
Common Lispに関する注記: Common Lispでは、dow、dst、utcoffはそれぞれ異なる意味を持ち、secondは0以上59以下の整数となります。
暦情報内の要素にアクセス(または変更)するには、decoded-time-second、decoded-time-minute、decoded-time-hour、decoded-time-day、decoded-time-month、decoded-time-year、decoded-time-weekday、decoded-time-dst、およびdecoded-time-zoneのアクセサを使用できます。
この関数は time を Lisp のタイムスタンプに変換します。decode-time の逆関数として機能します。
通常、第1引数は decode-time 形式のデコード済み時刻を指定するリスト (second minute
hour day month year ignored dst zone) となります。これらのリスト要素の意味については、decode-time の下にある表を参照してください。特に dst
は、タイムスタンプが重複している場合のサマータイム・フォールバック時におけるタイムスタンプの解釈方法を規定しています。dst が −1 の場合は DST 値が推測され、t
または nil の場合はその DST
値を持つタイムスタンプが返されます。そのようなタイムスタンプが存在しない場合はエラーが通知されます。残念ながら、dst の値が t または nil であっても、TZDB
ベースのタイムゾーンがグリニッジよりさらに西へ移動した際に重複するタイムスタンプの曖昧さを解消することはできません。例えば、zone が ‘"Europe/Volgograd"’ であり、同日の 02:00
にグリニッジ東で標準時が 4 時間から 3 時間に変更された場合、2つの標準時タイムスタンプ 2020-12-27 01:30
の曖昧さを解消することはできません。このような状況に対処する必要がある場合は、代わりに数値の zone
を使用して曖昧さを解消できます。
第1引数にはリスト (second minute hour day month year) を指定することもでき、この場合はリスト (second minute hour day month year nil -1 nil)
と同様に扱われます。
旧式の呼び出し規約であるため、この関数には6つ以上の引数を渡すことができます。最初の6つの引数 second、minute、hour、day、month、および year
は、デコードされた時刻の構成要素の大部分を指定します。引数が6つを超える場合、最後の引数が zone として使用され、それ以外の余分な引数は無視されるため、(apply
#'encode-time (decode-time ...)) が機能します。この旧式の規約では、dst は −1 となり、zone
は現在のタイムゾーンルールがデフォルトで適用されます(タイムゾーンルール
を参照)。旧式の呼び出し元を現代化する際は、より現代的なリスト形式の対応物に、nil ではなく
−1 となる dst 要素を含む9つの要素が含まれていることを確認してください。
100未満の年号は特別な扱いを受けません。1900年以降、あるいは2000年以降の年号として扱いたい場合は、encode-timeを呼び出す前にご自身で修正する必要があります。オペレーティングシステムは、時刻およびタイムゾーンの値の範囲を制限しています。ただし、エポックから近い将来までのタイムスタンプは常にサポートされています。
encode-time 関数は、decode-time
の大まかな逆関数として機能します。例えば、後者の出力を次のように前者に渡すことができます。
(encode-time (decode-time ...))
seconds、minutes、hour、day、month に範囲外の値を指定することで、簡単な日付演算を行うことができます。例えば、day 0 は指定された月の前日を意味します。ただし、場合によっては失敗することがよくあるため、操作の際はご注意ください。例えば:
;; Try to compute the time one month from now.
;; Watch out; this might not work as expected.
(let ((time (decode-time)))
(setf (decoded-time-month time)
(+ (decoded-time-month time) 1))
time)
残念ながら、月の日数の違い、夏時間の切り替え、タイムゾーンの変更、あるいは閏日や閏秒の欠落などにより、結果の時刻が無効な場合、このコードは期待通りに動作しない可能性があります。例えば、1月30日に実行すると、このコードは存在しない日付である2月30日を返しますが、encode-time
はこれを3月上旬に調整します。同様に、2096年2月29日に4年を加えると、存在しない日付である2100年2月29日になります。また、ニューヨーク時間で2022年3月13日の01:30に1時間を加えると、タイムスタンプ
02:30
になりますが、この日は時計が02:00から03:00に進んだため、この時刻は存在しません。こうした問題の一部(すべてではありませんが)を回避するには、影響を受ける単位の中間点を基準に計算を行う方法があります。例えば、月を加算する場合は月の15日から開始するといった方法です。あるいは、calendar や time-date
ライブラリを使用することもできます。