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))))