トラック
/
Common Lisp
Common Lisp
/
演習
/
ギガ秒の記念日
ギガ秒の記念日

ギガ秒の記念日

学習演習

はじめに

日付と時刻

Common Lispでは、時間は4つの方法で表現されます。ここではそのうちの2つを取り上げます。

  • ユニバーサル時間は絶対時刻で、1900-01-01T00:00:00Zからの経過秒数を表す整数です(これはUTCにおける1900年1月1日の真夜中です)。
  • デコードされた時間は9つの値からなるタプルで、それらがそろって特定の暦時刻を表します。内訳は、秒、分、時、日、月、年、曜日、夏時間フラグ、タイムゾーンです。 (詳しくは後述します。)

ユニバーサル時間

現在のユニバーサル時間を取得するには、get-universal-timeまたはget-decoded-timeを使います。 前者は1900-01-01T00:00Zからの現在の経過秒数を返し、後者は同じデータをデコードされた形式で返します。

デコードされた時間

時間を扱う主要な関数は、decode-universal-timeとencode-universal-timeです。 前者はユニバーサル時間を受け取り、複数の値としてデコードされた時間の値を返します。後者はデコードされた時間の値を引数として受け取り、ユニバーサル時間を返します。

どちらも省略可能なタイムゾーンの引数を取ります。 タイムゾーンの形式については、後述します。

デコードされた時間は、次の値の組です。

  • 秒:0から59までの整数
  • 分:0から59までの整数
  • 時:0から23までの整数
  • 日:1から31までの整数(言うまでもなく、上限は月と年によって変わります)
  • 月:1から12までの整数
  • 年:年を表す整数。
  • 曜日:0から6までの整数。0は月曜日、1は火曜日、……6は日曜日を意味します。
  • 夏時間フラグ:真の値は夏時間が適用されていることを示します。
  • タイムゾーン:UTCからのオフセットを表す、-24から24までの時間数。 この数値は有理数で、1/3600の倍数でなければなりません。
(encode-universal-time 1 2 3 4 5 2000 0) ; => 3166398121
(decode-universal-time 3166398121)       ; => 1
                                         ;    2
                                         ;    3
                                         ;    4
                                         ;    5
                                         ;    2000
                                         ;    3 (Thursday)
                                         ;    NIL
                                         ;    0
(decode-universal-time 2208988800) ; => 0
                                   ;    0
                                   ;    0
                                   ;    1
                                   ;    1
                                   ;    1970
                                   ;    3
                                   ;    NIL
                                   ;    0

複数の値

Common Lispでは、関数は1つの値だけでなく、複数の値を返すことができます。 たとえば、ゼロに向かって切り捨てるfloorは2つの値を返します。1つ目は切り捨てられた値、2つ目は余りです。

(floor 3.5) ; => 3
            ;    0.5

(複数の値が返されるときは、出力の行を分けて示します。)

複数の値を返す

関数に複数の値を返させたいときは、valuesアクセサーを使います。

(defun three-numbers () (values 1 2 3))
(three-numbers) ; => 1
                ;    2
                ;    3

複数の値を扱う

1つ目の値だけが必要なら、特別なことをする必要はありません。言語がうまく処理してくれます。

(+ (values 1 2 3) (values 10 20 30)) ; => 11

ただし、それ以外の値にアクセスしたい場合は、いくつかの関数を使う必要があります。 主なマクロはmultiple-value-listとmultiple-value-bindの2つです。 これらは、複数の値を返すものを包み込んで、すべての値を取り出します。 前者はすべての値からなるリストを作ります。 後者は個々の値に変数を束縛できます。

(multiple-value-list (values 1 2 3))                   ; => (1 2 3)
(multiple-value-bind (a b c) (values 1 2 3) 
   (+ a b c)) ; => 6

もう1つ便利な関数がnth-valueです。

説明

Lisp星人は記念日を祝うのが好きです。 彼らにとって大切な記念日が、ギガ秒です。 つまり、出来事から1,000,000,000秒後です。

1. ギガ秒の記念日を計算する

year、month、day、hour、min、secという6つの入力を受け取り、ギガ秒の記念日の日時を計算する関数fromを書いてください。 この関数は、入力と同じ順序と意味を持つ配列として日付を返すようにしてください。

(from 2000 1 1 0 0 0) ; => (2031 9 9 1 46 40)
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
Common Lisp Exercism

ギガ秒の記念日を始める準備はできましたか?

Exercismに登録すれば、27個のコンセプト92個の演習、そして本物の人間によるメンタリングとともに、Common Lispを学んでマスターできます。すべて無料です。