2020-03-26lisp学习-17

84/ mod,返回相除后的余数

5 > (mod 27 5)
2
5 > (mod 35 5)
0


85/ 日期计算函数


6 > (defconstant month
  #(0 31 59 90 120 151 181 212 243 273 304 334 365));;;设定向量,一维数组

(defconstant yzero 2000);;设定向量,单值

(defun leap? (y);;函数名及形参。判断y年是否为闰年,是T,否nil
  (and (zerop (mod y 4));;;判断实参/4的余值是否为0,是真,否假。闰年的必要条件
       (or (zerop (mod y 400));;;判断实参/400的余值是否为0,是真,否假,与后一个表达式并列或的关系。世纪闰年的必要条件
           (not (zerop (mod y 100)))   ;;判断实参/100的余值是否为0,是假,否真,与前一个表达式并列或的关系。普通闰年的必要条件

        )))

闰年是公历中的名词。闰年分为普通闰年和世纪闰年。

普通闰年:公历年份是4的倍数的,且不是100的倍数,为普通闰年。(如2004年就是闰年);

世纪闰年:公历年份是整百数的,必须是400的倍数才是世纪闰年(如1900年不是世纪闰年,2000年是世纪闰年);

闰年(Leap Year)是为了弥补因人为历法规定造成的年度天数与地球实际公转周期的时间差而设立的。补上时间差的年份为闰年。闰年共有366天(1-12月分别为31天,29天,31天,30天,31天,30天,31天,31天,30天,31天,30天,31天)。

注意闰年(公历中名词)和闰月(农历中名词)并没有直接的关联,公历中只分闰年和平年,平年有365天,而闰年有366天(2月中多一天);平年中也可能有闰月(如2017年是平年,农历有闰月,闰6月)。

(defun date->num (d m y);;;函数名及形参。计算y年m月d日之前已累积天数
  (+ (- d 1) (month-num m y) (year-num y)));;;表达式,天-1,

(defun month-num (m y);;;函数名及形参,月份及年份。计算y年m月之前已累积天数
  (+ (svref month (- m 1));;;month数组中取出相应位置的数值,此为当年月份的累积数值
     (if (and (> m 2) (leap? y)) 1 0)));;;判断月份大于2,且为闰年,两者都真,则+1,有一个不为真则+0

(defun year-num (y);;;函数名及形参。Y年以前的累积天数,从2000年1月1日起开始计算。如2001年,返回2000年全年天数
  (let ((d 0));;;变量及赋值
    (if (>= y yzero);;;;判断y是否大于等于yzero(2000基准年),是真,否假
        (dotimes (i (- y yzero) d);;;真,年份差值赋值给i
          (incf d (year-days (+ yzero i))));;;年份差间每年的天数,从0开始累加,d为累加值存储器
        (dotimes (i (- yzero y) (- d));;;假,年份差值赋值给i,逆加,即2000年之前年份的值为负向累加
          (incf d (year-days (+ y i)))))));;年份差间每年的天数,从0开始累加,d为累加值存储器

;incf递增运算符,所指定的第二个参数增加整数。假设A初始值为10,(incf A 3) = 13,即在A上增加3值

(defun year-days (y) (if (leap? y) 366 365));;;函数名及形参,判断y是否闰年,是取值366,否365

MONTH
6 > YZERO
6 > LEAP?
6 > DATE->NUM
6 > MONTH-NUM
6 > YEAR-NUM
6 > YEAR-DAYS

验证:

5 > month
#(0 31 59 90 120 151 181 212 243 273 304 334 365)

6 > (year-num 2001)
366
6 > (year-num 2000)
0
6 > (year-num 2002)
731
6 > (year-num 1999)
-365

6 > (month-num 1 2020)

0

6 > (month-num 2 2020)

31

6 > (month-num 3 2020)

60

5 > (leap? 2200)

NIL

5 > (leap? 2400)

T

6 > (date->num 1 1 2001)
366
6 > (date->num 31 12 2000)
365
6 > (date->num 2 1 2001);;;不含当天,即当天之前的天数,从2000年1.1(含)开始
367

以上为先计算某日到基准日的天数


以下为继续计算从当日计算开始,多少天前后的日期是多少,逆转换

1 > (defun num->date (n);;;函数名及形参
  (multiple-value-bind (y left) (num-year n)
    (multiple-value-bind (m d) (num-month left y)
      (values d m y))))

(defun num-year (n);;;函数名及形参
  (if (< n 0);;判断n是否小于0,是真,否假
      (do* ((y (- yzero 1) (- y 1));;;真,设变量,当下值参与循环
            (d (- (year-days y)) (- d (year-days y))))
           ((<= d n) (values y (- n d))));;;条件语句,
      (do* ((y yzero (+ y 1));;;假
            (prev 0 d)
            (d (year-days y) (+ d (year-days y))))
           ((> d n) (values y (- n prev))))))

(defun num-month (n y)
  (if (leap? y)
      (cond ((= n 59) (values 2 29))
            ((> n 59) (nmon (- n 1)))
            (t        (nmon n)))
      (nmon n)))

(defun nmon (n)
  (let ((m (position n month :test #'<)))
    (values m (+ 1 (- n (svref month (- m 1)))))))

(defun date+ (d m y n)
  (num->date (+ (date->num d m y) n)))
NUM->DATE
1 > NUM-YEAR
1 > NUM-MONTH
1 > NMON
1 > DATE+

验证:

1 > (multiple-value-list (date+ 17 12 1997 60))
(15 2 1998)
1 > (multiple-value-list (date+ 17 12 1997 30))
(16 1 1998)
1 >

你可能感兴趣的:(2020-03-26lisp学习-17)