[emacs-berlin] Calculating recurring payments with Orgmode table spreadsheet
jman
emacs-berlin at city17.xyz
Sat Sep 28 13:20:23 UTC 2024
hello fellow emacs-hackers!
At the previous meetup we briefly talked offline about Orgmode. I mentioned this usecase:
----------s---------s----------
| Payment Date | Amount | is-recurrent | Total |
|------------------+--------+--------------+-------|
| <2024-10-02 Mon> | 22 | t | |
| <2024-12-02 Mon> | 15 | t | |
| <2024-10-12 Mon> | 20 | | |
| <2024-01-02 Tue> | 10 | t | |
----------e---------e----------
In this table each row is an expense item that can be a monthly recurrence or a one-time payment. I
want the "Total" column to have the amount calculated until end of the year (if it's a recurring
monthly expense) or just copy the value from the "Amount" column.
After an evening of sweat and learning a bit of orgmode, here's my solution (which I am very proud
of!). The following function will calculate how many months until end of the year starting from a
timestamp:
----------s---------s----------
#+begin_src emacs-lisp :tangle yes
(defun my/months-paid-until-end-of-year (timestamp)
"Return the number of months from TIMESTAMP until end of the year.
As a number without zero-padding."
(let* ((time (org-time-string-to-time timestamp))
(month (format-time-string "%-m" time)))
(1 + (- 12 (string-to-number month)))))
#+end_src
----------e---------e----------
And here is how I use that function in an orgmode table formula:
----------s---------s----------
| Date | Amount | is-recurrent | Total |
|------------------+--------+--------------+-------|
| <2024-10-02 Mon> | 22 | t | 88 |
| <2024-12-02 Mon> | 15 | t | 15 |
| <2024-10-12 Mon> | 20 | | 20 |
| <2024-01-02 Tue> | 10 | t | 120 |
#+TBLFM: $4='(if (string-empty-p "$3") $2 (* $2 (my/months-paid-until-end-of-year "$1")));EL
----------e---------e----------
It's probably a bit convoluted but basically I am assigning in the fourth column 4 ($4) the result
of the elisp expression. ";EL" are two modifiers: "E" returns empty strings for empty cells so I
don't have to cope with nil and "L" interprets cell content literally so I don't have to cast
strings to numbers (orgmode by default treat all cells as strings).
It works (yay!) but can this code be improved? As a side note, I've tried getting some initial
guiding from an AI assistant and it was horrible. However it suggested an orgmode function to get
the "month of the year from a timestamp":
----------s---------s----------
| Date | MOY |
|------------------+-----|
| <2024-10-12 Mon> | 10 |
#+TBLFM: $2=month($1)
----------e---------e----------
I couldn't figure out how to mix `month()` with my elisp code, something like this (if it worked):
----------s---------s----------
| Date | MOY |
|------------------+--------|
| <2024-08-02 Fri> | #ERROR |
#+TBLFM: $2='(+ 2 month($1))
----------e---------e----------
Is something like that even possible? Maybe using a temporary variable?
Thank you!
Best,
More information about the emacs-berlin
mailing list