about summary refs log blame commit diff
path: root/emacs/.emacs.d/wpc/me-seconds.el
blob: f03e5d07d7909fd1a685c07e53b8c98ff5419c2d (plain) (tree)




















































































































































































































































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