This Common Lisp exercise is to write a program that can calculate the weekday given a string of the format "M-D-Y." It was more challenging than I expected. If you have suggestions about how to simplify this code, I will be very grateful.
;; 2.7 Day of Week. A program for converting Gregorian dates in the form month-day-year to day of the
;; week is the following. Let the Gregorian date be represented by M-D-Y where we have the following
;; definitions:
;; M is the month of the year. Let m be the month number derived from M by the rule m is M - 2 if M >= 3
;; and m is M + 10 otherwise.
;; d is the day of the month.
;; y is the year of the century.
;; c is the number of the previous century.
;; The algorithm is as follows:
;; (a) A is the integer part of (13m - 1)/5.
;; (b) B is the integer parg of y/4.
;; (c) C is the integer part of c/4.
;; (d) D = A + B + C + d + y - 2c.
;; (e) Make R equal to the remainder of D/7.
;; (f ) Interpret R as Sunday if R = 0, Monday if R is 1, etc
(defun read-date () (format t "Enter the gregorian date in the format (M-D-Y): ~%") (read))
(defun flatten (the-list)
(cond ((null the-list) nil)
((atom the-list) (list the-list))
(t (concatenate 'list (flatten (car the-list)) (flatten (cdr the-list))))))
(defun split (split-char string-to-split)
(let ((next-split-char (position split-char string-to-split)))
(if next-split-char (flatten (list (safely-read-from-string (subseq string-to-split 0 next-split-char))
(split split-char (subseq string-to-split (+ 1 next-split-char)))))
(list (safely-read-from-string string-to-split)))))
(defun weekday-code (bigM bigD bigY)
(let* ((m (if (>= bigM 3) (- bigM 2) (+ bigM 10)))
(y (mod bigY 100))
(littleC (/ (- bigY y) 100))
(A (floor (- (* 13 m) 1) 5))
(B (floor y 4))
(C (floor littleC 4))
(D (- (+ A B C bigD y) (* 2 littleC)))
(R (mod D 7)))
(format t "m: ~a y: ~a c: ~a A: ~a B: ~a C: ~a D: ~a R: ~a ~%" m y littleC A B C D R)
R))
(defun check-date-format (bigM bigD bigY)
(cond ((or (< bigM 1) (> bigM 12)) (error "The month (~a) is not in the range 1-12." bigM))
((< bigY 0) (error "The year (~a) is less than 0." bigY))
((or (< bigD 1) (> bigD 31)) (error "The day (~a) is not in the range 1-31." bigD))))
(let ((gregorian-date (read-date)))
(destructuring-bind (bigM bigD bigY) (split #\- gregorian-date)
(check-date-format bigM bigD bigY)
(format t "~a was (or will be) a ~[Sunday~;Monday~;Tuesday~;Wednesday~;Thursday~;Friday~;Saturday~]." gregorian-date (weekday-code bigM bigD bigY))))