summaryrefslogtreecommitdiff
path: root/stumpwm/modules/modeline/fuzzytime/fuzzytime.lisp
blob: 9a703a3a66e0a6637c13e3fe5b1662af269fef8b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
;;;; fuzzytime.lisp

(IN-PACKAGE #:FUZZYTIME)

(EXPORT '(*FUZZYTIME-FORMAT* *MINUTE-GRANULARITY*))

(PUSHNEW '(#\F LOCAL-TIME-TO-FUZZY) *SCREEN-MODE-LINE-FORMATTERS* :TEST 'EQUAL)

(DEFPARAMETER *MINUTE-GRANULARITY* 10
  "Minutes are rounded to the nearest multiple of *minute-granularity*")

(DEFPARAMETER *FUZZYTIME-FORMAT*
  '(:MINUTES :HOURS " in the " :PERIOD " on " :DOW
    " the " :DAY " of " :MONTH)
  "Format of the output, a list of strings and keywords. Valid keywords are:
:minutes
:hours
:period
:dow (name of the day of the week)
:udow (name of the day of the week, capitalised)
:dn (number of the day of the week)
:day (day of the month)
:mnum (number of the month)
:month (name of the month, capitalised)
:umonth (name of the month)")

(DEFVAR *MONTH-NAMES*
  (MAKE-ARRAY '(12) :INITIAL-CONTENTS
              '("january" "february" "march" "april" "may" "june" "july"
                "august" "september" "october" "november" "december")))

(DEFVAR *DOW-NAMES*
  (MAKE-ARRAY '(7) :INITIAL-CONTENTS
              '("monday" "tuesday" "wednesday"
                "thursday" "friday" "saturday"
                "sunday")))

(DEFUN MINUTES-TO-WORDS (MIN)
  (IF (OR (<= MIN 0) (>= MIN 60)) ""
      (FLET ((FRAC (M) (COND
                         ((= M 30) "half")
                         ((= M 15) "quarter")
                         (T (FORMAT NIL "~r" M)))))
        (FORMAT NIL "~a ~a " (FRAC (IF (> MIN 30) (- 60 MIN) MIN))
                (IF (> MIN 30) "to" "past")))))

(DEFUN HOUR-TO-WORDS (HOUR MIN)
  (LET ((H (MOD
            (IF (> MIN 30) (1+ HOUR) HOUR )
            12)))
    (FORMAT NIL "~r~a"
            (IF (= H 0) 12 H)
            (IF (OR (= MIN 0) (= MIN 60)) " o'clock" ""))))

(DEFUN PERIOD-INDICATOR (HOUR)
  (IF (< HOUR 12) "morning"
      (IF (< HOUR 17) "afternoon" "evening")))

(DEFUN LOCAL-TIME-TO-FUZZY (ML)
  (DECLARE (IGNORE ML))
  (MULTIPLE-VALUE-BIND (SECONDS MINUTES HOUR DAY MONTH YEAR DOW)
      (GET-DECODED-TIME)
    (DECLARE (IGNORE SECONDS) (IGNORE YEAR))
    (LET* ((MIN (* *MINUTE-GRANULARITY*
                   (ROUND (/ MINUTES *MINUTE-GRANULARITY*))))
           (MS (MINUTES-TO-WORDS MIN))
           (HS (HOUR-TO-WORDS HOUR MIN))
           (PS (PERIOD-INDICATOR HOUR))
           (DN (ELT *DOW-NAMES* DOW))
           (MN (ELT *MONTH-NAMES* (1- MONTH))))
      (APPLY #'CONCATENATE 'STRING
             (LOOP FOR E IN *FUZZYTIME-FORMAT* COLLECT
                  (CASE E
                    (:MINUTES MS)
                    (:HOURS HS)
                    (:PERIOD PS)
                    (:DOW DN)
                    (:UDOW (STRING-CAPITALIZE DN))
                    (:MONTH MN)
                    (:UMONTH (STRING-CAPITALIZE MN))
                    (:DNUM (FORMAT NIL "~a" DOW))
                    (:DAY (FORMAT NIL "~:r" DAY))
                    (:MNUM (FORMAT NIL "~a" MONTH))
                    (OTHERWISE E)))))))