从出生日期起共同LISP的年龄计算

时间:2013-12-10 11:15:30

标签: lisp common-lisp date-arithmetic

我正在尝试使用给定的出生日期(YYYY-MM-DD形式的字符串)计算Common Lisp中的人的年龄,但我收到以下错误:

  

错误:"2013-12-10"' is not of the expected type号码'

我的代码如下

(defun current-date-string ()
  "Returns current date as a string."
  (multiple-value-bind (sec min hr day mon yr dow dst-p tz)
                       (get-decoded-time)
    (declare (ignore sec min hr dow dst-p tz))
    (format nil "~A-~A-~A" yr mon day)))

(defvar (dob  1944-01-01))
  (let ((age (- (current-date-string) dob))))

有人能在这方面给我帮助吗?我怀疑当前日期是字符串格式,如我的输入,但我们如何将其转换为与我的输入相同的日期格式?

2 个答案:

答案 0 :(得分:6)

您的代码

有两个直接问题:

  1. 减法函数-数字作为参数。您传递了(current-date-string)的结果,这是由(format nil "~A-~A-~A" yr mon day)生成的字符串
  2. 此代码没有任何意义:

    (defvar (dob  1944-01-01))
      (let ((age (- (current-date-string) dob))))
    

    一方面,它没有正确缩进。它有两种形式,第一种形式是(defvar (dob 1944-01-01))。这不是defvar的正确语法。 1944-01-01是一个符号,它没有绑定,所以即使你已经完成(defvar dob 1944-01-01),在评估定义时也会出错。虽然(let ((age (- (current-date-string) dob))))在语法上是正确的,但在绑定年龄后,您并没有任何事情。您可能想要(let ((age (- (current-date-string) dob))) <do-something-here>)

  3. 日期算术

    无论如何,通用时间是的整数值:

      

    25.1.4.2 Universal Time

         

    世界时是一个单独表示的绝对时间   非负整数---自1月午夜以来的秒数   1,1900 GMT(忽略闰秒)。因此,时间1是00:00:01(那个   是格林威治标准时间1900年1月1日凌晨12:00(凌晨1点)。

    这意味着您可以采用两个通用时间并从另一个中减去一个以获得持续时间(以秒为单位)。不幸的是,Common Lisp不提供操作这些持续时间的功能,并且由于闰年等原因而转换它们并非易事。 Common Lisp Cookbook提到了这一点:

      

    Dates and Times

         

    由于世界时代只是数字,因此它们更容易,更安全   操纵比日历时间。日期和时间应始终如此   如果可能则存储为通用时间,并且仅转换为字符串   用于输出目的的表示。例如,它是   直截了当地知道两个日期中的哪一个出现在另一个之前   简单地将两个相应的通用时间与&lt;另一个   典型的问题是如何计算两者之间的“时间距离”   给定日期。让我们看一下如何用一个例子来做到这一点:具体来说,   我们将计算第一次着陆之间的时间距离   月亮(美国东部时间下午4点17分,1969年7月20日)和最后一次起飞   穿梭挑战者(1986年1月28日美国东部时间上午11:38)。

    * (setq *moon* (encode-universal-time 0 17 16 20 7 1969 4))
    2194805820
    
    * (setq *takeoff* (encode-universal-time 0 38 11 28 1 1986 5))
    2716303080
    
    * (- *takeoff* *moon*)
    521497260
    
         

    这有点超过5200万秒,相当于6035天,20   小时21分钟(您可以通过将该数字除以来验证这一点   60,60和24连续)。超越几天有点困难   因为几个月和几年没有固定的长度,但以上是   大约16年半。

    阅读日期字符串

    听起来您还需要从YYYY-MM-DD形式的字符串中读取日期。如果您确信您收到的价值合法,您可以做一些简单的事情

    (defun parse-date-string (date)
      "Read a date string of the form \"YYYY-MM-DD\" and return the 
    corresponding universal time."
      (let ((year (parse-integer date :start 0 :end 4))
            (month (parse-integer date :start 5 :end 7))
            (date (parse-integer date :start 8 :end 10)))
        (encode-universal-time 0 0 0 date month year)))
    

    这将返回一个通用时间,你可以按上述方法进行算术运算。

    懒惰

    作为一个懒惰的程序员,这通常是一种很好的做法。在这种情况下,我们可能会因为不自己实现这些类型的函数而变得懒惰,而是使用一个可以为我们处理它的库。一些Common Lisp实现可能已经提供了日期和时间函数,并且有many time libraries listed on Cliki。我不知道哪些是最广泛使用的,或者是否覆盖了你需要的各种函数,而且库建议对于StackOverflow来说是偏离主题的,所以你可能需要试验一些才能找到适用于它的函数。你。

答案 1 :(得分:2)

不,不能只从另一个字符串中减去一个字符串,并期望计算机神奇地知道这些字符串是一个日期并相应地处理它们。无论是什么给了你这个想法?

使用库local-time

使用Quicklisp进行安装:

(ql:quickload "local-time").

解析日期:

(local-time:parse-timestring "2013-12-10")

这会生成一个timestamp对象。

获取当前时间戳:

(local-time:now)

以秒为单位获得差异:

(local-time:timestamp-difference one-timestamp another-timestamp)

获得年数差异(向下舍入):

(local-time:timestamp-whole-year-difference one-timestamp another-timestamp)