Skip to main content
deleted 2407 characters in body; edited tags; edited title
Source Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

Common Lisp - Calculate the weekday from a date (M-D-Y)

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. Thank you for taking a look.

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

Based on the feedback I received, I have updated the code:

(defun split (split-char string-to-split) 
  (let ((next-split-char (position split-char string-to-split)))
    (if next-split-char 
      (cons (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)
    "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"
    (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)))
      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))))

(defun read-date () (format t "Enter the gregorian date in the format (M-D-Y): ~%") (read))

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

Common Lisp - Calculate the weekday from a date (M-D-Y)

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. Thank you for taking a look.

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

Based on the feedback I received, I have updated the code:

(defun split (split-char string-to-split) 
  (let ((next-split-char (position split-char string-to-split)))
    (if next-split-char 
      (cons (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)
    "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"
    (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)))
      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))))

(defun read-date () (format t "Enter the gregorian date in the format (M-D-Y): ~%") (read))

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

Calculate the weekday from a date (M-D-Y)

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))))
added 2371 characters in body
Source Link
jaresty
  • 2.2k
  • 1
  • 25
  • 45

Based on the feedback I received, I have updated the code:

(defun split (split-char string-to-split) 
  (let ((next-split-char (position split-char string-to-split)))
    (if next-split-char 
      (cons (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)
    "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"
    (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)))
      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))))

(defun read-date () (format t "Enter the gregorian date in the format (M-D-Y): ~%") (read))

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

Based on the feedback I received, I have updated the code:

(defun split (split-char string-to-split) 
  (let ((next-split-char (position split-char string-to-split)))
    (if next-split-char 
      (cons (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)
    "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"
    (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)))
      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))))

(defun read-date () (format t "Enter the gregorian date in the format (M-D-Y): ~%") (read))

(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))))
Tweeted twitter.com/#!/StackCodeReview/status/45587998624067585
Source Link
jaresty
  • 2.2k
  • 1
  • 25
  • 45

Common Lisp - Calculate the weekday from a date (M-D-Y)

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. Thank you for taking a look.

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