ついカッっとなって

書いてしまいました。

これで「あの人は今日で n 歳と m ヶ月なのかな」という疑問にすぐに答えらます :)

emacs lisp です。

(defun combined-date-number (&optional year month day)
  (string-to-int
   (format-time-string "%Y%m%d"
		       (when (and year month day)
			 (encode-time 0 0 0 day month year)))))

(defun how-old (birth:year birth:month birth:day)
  "返り値はリストです。
car が 年齢、cadr が誕生日からの経過月になっています。

経過月の計算には `birth:day' が `today:day' 未満かどうかの
判定が含まれています。

例えば 1 月 15 日生まれの場合、2 月 15 日を越えてはじめて
\"誕生日から 1 箇月経過\"となります。"

  (let
      ((today:num (combined-date-number))
       (birthday:num (combined-date-number
		  birth:year birth:month birth:day))
       (today:month (nth 4 (decode-time)))
       (today:day (nth 3 (decode-time))))

    (list
     (truncate (/ (- today:num birthday:num) 10000.0))
     (+ (- today:month birth:month)
	(if (< today:month birth:month)
	    (if (>= today:day birth:day) 12 11) 0)))))

(defun time-of-the-child (birth:year birth:month birth:day
				     &optional base:old)
  (let
      ((old (how-old birth:year birth:month birth:day))
       (base:old (or
		  (if base:old
		      (or (and
			   (listp base:old)
			   (remove nil (mapcar #'(lambda (arg)
						   (when (numberp arg)
						     arg)) base:old)))
			  (and
			   (atom base:old)
			   (numberp base:old)
			   (list base:old))))
		  (list 4 6 17)))) ;; default
    (concat
     (format-time-string "%Y 年 %m 月 %d 日現在, ")
     (mapconcat #'(lambda (arg)
		    (when (numberp arg)
		      (format "%s 歳と %s 箇月" arg
			      (+ (* (- (car old) arg) 12)
				 (cadr old))))) base:old ", ")
     "です.")))
(time-of-the-child 1973 5 29) ;;=> 2008 年 01 月 30 日現在, 4 歳と 368 箇月, 6 歳と 344 箇月, 17 歳と 212 箇月です.

基準値を与えられます。

(time-of-the-child 1973 5 29 20) ;;=> 2008 年 01 月 30 日現在, 20 歳と 176 箇月です.

基準値にはリストも渡せます。

(time-of-the-child 1973 5 29 (list 10 20 30)) ;;=> 2008 年 01 月 30 日現在, 10 歳と 296 箇月, 20 歳と 176 箇月, 30 歳と 56 箇月です.

無効な optional 引数が渡された場合は、初期値を用いて計算します。

(time-of-the-child 1973 5 29 'a) ;;=> 2008 年 01 月 30 日現在, 4 歳と 368 箇月, 6 歳と 344 箇月, 17 歳と 212 箇月です.
  • 年齢計算に「今日の日付を連結した数字から、誕生日に連結した数字を引いて 10000 で割る」を使ってみました。
    • 初めて使いました。便利なような。
  • and や or を重ねるのが好きです。
  • remove と mapcar で要らない子を削るのも好きです。
  • symbol-name に : を含められるのを思い出して使ってみました。
    • 慣習を知らないので格好悪いことになっているかも。

そうそう、ぼくは 1973 年生まれではありません*1ので、あしからず :)

*1:じゃあ誰なの