about summary refs log tree commit diff
path: root/emacs/.emacs.d/wpc/me-seconds.el
blob: f03e5d07d7909fd1a685c07e53b8c98ff5419c2d (plain) (blame)
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
;;; me-seconds.el --- How valuable is my time? -*- lexical-binding: t -*-
;; Author: William Carroll <wpcarro@gmail.com>

;;; Commentary:
;; Inspired by Google's concept of SWE-seconds, I decided to try and compute how
;; value my personal time is.
;;
;; This library should integrate with another library that handles currency
;; conversions using locally cached data for historial values and network
;; requests for current values.
;;
;; Context sensitivity:
;; Many of the values herein are based on my values that are a function of the
;; year, my current salary, my current company holiday policy, and my current
;; country holiday policy.  As such, many of these constants need to be updated
;; whenever changes occur in order for these functions to be useful.
;;
;; Units of time:
;; - seconds
;; - minutes
;; - hours
;; - days
;; - weeks
;; - months
;; - years
;;
;; Wish list:
;; - I should create a money.el struct to work with herein.  This module would
;;   expose basic algebra for working with money structs, which would be handy.
;; - I should create a time.el struct for working with hours in the day.  I'd
;;   like to be able to do (+ 9:15 17:45) cleanly.
;;
;; Terminology:
;; SWE hours give an order of magnitude approximation to the cost of resources
;; in dollars per hour at 2115 hours per year.
;; - SWE hour (SWEh)
;; - SWE year (SWEy)
;; - SWE nominal
;; - SWE opportunity
;;
;; Other isomorphisms include:
;; - Borg GCU
;; - Borg RAM
;; - Tape (library)
;; - Tape (vault)
;; - Spindles (low latency)
;; - Spindles (throughput)
;; - Spindles (throughput)
;; - Tape (throughput)
;; - SWE (nominal)
;; - SWE (opportunity)


;;; Code:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Dependencies
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(require 'macros)
(require 'string)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Constants
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun me-seconds/salary (amt)
  "Return the yearly rate of AMT of money in GBP.
f :: Integer -> Rate"
  (make-rate :money (make-money :whole amt :fractional 0 :currency 'GBP)
             :unit 'year))

(defconst me-seconds/salary (me-seconds/salary 80000)
  "My salary in GBP.")

;; TODO: Consider changing these into units of time.
(defconst me-seconds/months-per-year 12
  "Number of months in a year.")

(defconst me-seconds/days-per-year 365
  "Number of days in a year.")

(defconst me-seconds/hours-per-year (* 24 me-seconds/days-per-year)
  "Number of hours in a year.")

(defconst me-seconds/minutes-per-year (* 60 me-seconds/hours-per-year)
  "Number of minutes in a year.")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Vacation
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defconst me-seconds/bank-holidays-per-year 8
  "Number of bank holidays in the UK each year.")

(defconst me-seconds/pto-days-vacation-per-year 25
  "Number of days of paid-time-off I receive each year in the UK.")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Sleeping
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defconst me-seconds/sleeping-hours-per-day 8
  "An approximation of the number of hours I sleep each night on average.")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Waking
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defconst me-seconds/waking-hours-per-day
  (- 24 me-seconds/sleeping-hours-per-night)
  "An approximation of the number of hours I sleep each night on average.")

;; TODO: Adjust this for vacation time.
(defconst me-seconds/waking-hours-per-year
  (* me-seconds/waking-hours-per-day me-seconds/days-per-year)
  "The number of hours that I work each year.")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Working
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defconst me-seconds/working-hours-per-day
  (- 17 9)
  "An approximation of the number of hours I work each weekday on average.
Note that this differs from the assumed SWE hours per day calculation, which
  assumes 9 working hours.  See the discussion about this of go/rules-of-thumb.")

(defconst me-seconds/working-hours-per-year 2115
  "This number is borrowed from go/rules-of-thumb.")

;; Keep in mind that the following classifications of time:
;; - 9:00-17:00 M-F. Is this more expensive than time sleeping?
;; - Weekend
;; - Weekday
;; - Working hours
;; - Waking hours
;; - Sleeping hours
;; - Vacation hours
;;
;; TODO: Consider tax implications (i.e. after-tax amounts and pre-tax amounts).
;;
;; Should these all be treated the same since they all pull from the same pot of
;; time? Or perhaps there are multiples involved? Much to think about. How does
;; Google handle this?

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Library
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Supported currencies:
;; - GBP
;; NOTE: Amount is an integer.
(cl-defstruct money whole fractional currency)
(cl-defstruct rate money unit)

;; TODO: Add to money.el.
(defun money/to-string (x)
  "Return the string representation of X.
f :: Money -> String"
  (let ((currency (money-currency x))
        (whole (int-to-string (money-whole x)))
        (fract (int-to-string (money-fractional x))))
    (pcase currency
      ('GBP (string/concat "£" whole "." fract))
      ('USD (string/concat "$" whole "." fract))
      (_ (error (string/concat
                 "Currency: \""
                 (symbol-name currency)
                 "\" not supported"))))))

(macros/comment
 (money/to-string
  (make-money :whole 100 :fractional 99 :currency 'GBP)))

;; TODO: Add to rate.el.
(defun rate/to-string (x)
  "Message X as a rate.
f :: Rate -> String"
  (string/concat
   (money/to-string (rate-money x))
   " / "
   (pcase (rate-unit x)
     ('second "sec")
     ('minute "min")
     ('hour   "hr")
     ('day    "day")
     ('week   "week")
     ('month  "month")
     ('year   "year"))))

(macros/comment
 (rate/to-string
  (make-rate
   :money (make-money :whole 10 :fractional 10 :currency 'GBP)
   :unit 'day)))

;; TODO: Move this to math.el?
(defun ensure-float (x)
  "Ensures X is treated as a float."
  (+ 0.0 x))

;; TODO: Move these to basic time mapping module.
;; TODO: Consider making this an isomorphism.
(defun minutes/to-hours (x)
  "Convert X minutes to n hours."
  (/ x 60.0))

(defun hours/to-minutes (x)
  "Convert X hours to n minutes."
  (* x 60))

(defun days/to-minutes (x)
  "Convert X days to n minutes."
  (* x 24 60))

(defun weeks/to-minutes (x)
  "Convert X weeks to n minutes."
  (* x 7 24 60))

(defun months/to-minutes (x)
  "Convert X months to n minutes.
This approximates the number of days in a month to 30."
  (* x 30 24 60))

;; TODO: Support algebraic functions with money structs.
;; TODO: Support isomorphisms for rates to other units of time.  That would
;; subsume most of this module's use.
(defun me-seconds/value-per-minute (salary)
  "Computes my value per minute based on my current SALARY.
Signature: f :: Rate -> Rate
This is assuming that all of my time is equally valuable.  See the above
  discussion about the various classifications of my time.")

;; TODO: See note above about isomorphisms between various rates.
(defun me-seconds/value (salary x)
  "Compute the value of X minutes of my time at my current SALARY.
f :: Rate -> Integer -> Money")

(macros/comment
 (rate/to-string me-seconds/salary)
 )

(provide 'me-seconds)
;;; me-seconds.el ends here