2020-03-26lisp學習-17

84/ mod,返回相除后的余數(shù)

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


85/ 日期計算函數(shù)


6 > (defconstant month
? #(0 31 59 90 120 151 181 212 243 273 304 334 365));;;設定向量,一維數(shù)組

(defconstant yzero 2000);;設定向量,單值

(defun leap? (y);;函數(shù)名及形參。判斷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的倍數(shù)的,且不是100的倍數(shù),為普通閏年。(如2004年就是閏年);

世紀閏年:公歷年份是整百數(shù)的,必須是400的倍數(shù)才是世紀閏年(如1900年不是世紀閏年,2000年是世紀閏年);

閏年(Leap Year)是為了彌補因人為歷法規(guī)定造成的年度天數(shù)與地球實際公轉周期的時間差而設立的。補上時間差的年份為閏年。閏年共有366天(1-12月分別為31天,29天,31天,30天,31天,30天,31天,31天,30天,31天,30天,31天)。

注意閏年(公歷中名詞)和閏月(農歷中名詞)并沒有直接的關聯(lián),公歷中只分閏年和平年,平年有365天,而閏年有366天(2月中多一天);平年中也可能有閏月(如2017年是平年,農歷有閏月,閏6月)。

(defun date->num (d m y);;;函數(shù)名及形參。計算y年m月d日之前已累積天數(shù)
? (+ (- d 1) (month-num m y) (year-num y)));;;表達式,天-1,

(defun month-num (m y);;;函數(shù)名及形參,月份及年份。計算y年m月之前已累積天數(shù)
? (+ (svref month (- m 1));;;month數(shù)組中取出相應位置的數(shù)值,此為當年月份的累積數(shù)值
???? (if (and (> m 2) (leap? y)) 1 0)));;;判斷月份大于2,且為閏年,兩者都真,則+1,有一個不為真則+0

(defun year-num (y);;;函數(shù)名及形參。Y年以前的累積天數(shù),從2000年1月1日起開始計算。如2001年,返回2000年全年天數(shù)
? (let ((d 0));;;變量及賦值
??? (if (>= y yzero);;;;判斷y是否大于等于yzero(2000基準年),是真,否假
??????? (dotimes (i (- y yzero) d);;;真,年份差值賦值給i
????????? (incf d (year-days (+ yzero i))));;;年份差間每年的天數(shù),從0開始累加,d為累加值存儲器
??????? (dotimes (i (- yzero y) (- d));;;假,年份差值賦值給i,逆加,即2000年之前年份的值為負向累加
????????? (incf d (year-days (+ y i)))))));;年份差間每年的天數(shù),從0開始累加,d為累加值存儲器

;incf遞增運算符,所指定的第二個參數(shù)增加整數(shù)。假設A初始值為10,(incf A 3) = 13,即在A上增加3值

(defun year-days (y) (if (leap? y) 366 365));;;函數(shù)名及形參,判斷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);;;不含當天,即當天之前的天數(shù),從2000年1.1(含)開始
367

以上為先計算某日到基準日的天數(shù)


以下為繼續(xù)計算從當日計算開始,多少天前后的日期是多少,逆轉換

1 > (defun num->date (n);;;函數(shù)名及形參
? (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);;;函數(shù)名及形參
? (if (< n 0);;判斷n是否小于0,是真,否假
????? (do* ((y (- yzero 1) (- y 1));;;真,設變量,當下值參與循環(huán)
??????????? (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 >

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容