I've read the writeups out there but I can't quite make this work for my use case. Using the timedot format in hledger, I'd like to know how to track time, bill for it, and then track the revenue using cash-basis accounting (not accrual).
time.timedot
2026/01/01
Work:Client 30m
2026/01/02
Work:Client 30m
ledger.journal
D 1.00 hr ; default commodity for unitless timedot format
include time.timedot
2026/10/01 Client ; send an invoice to Client
Work:Client -1.0 hr @ $50.00
Assets:Receivable:Client
2026/10/05 Client ; receive payment from Client
Assets:Checking $50.00
Revenue:Client
(Assets:Receivable:Client) $-50.00
It's obnoxious to have to use a virtual posting here. Is there a better way to think about this? Keep in mind that since I'm on cash basis I do not want to hit the Revenue account until the payment is posted.
That mixes timedot's unbalanced, single-entry accounting (Work:Client) with the journal's balanced double-entry accounting, which one way or another causes unbalanced entries.
I think this is what always happens when we try to combine time and money in a single journal. You could add a balancing account for time - but that seems like just boilerplate with no error checking value. Treating time amounts consistently as unbalanced seems like the pragmatic approach.
But there's another thing going on here: cash basis accounting does not have a place for tracking receivables. So if you want to track that, it too must be an unbalanced posting (or, you make up some account to balance it with).
Here's another attempt:
D 1.00 hr ; default commodity for unitless timedot format
; attach a little extra meaning
apply account Unbilled
include time.timedot
end apply account
2026/10/01 Client ; send an invoice to Client
Unbilled:Work:Client -1.0 hr @ $50 = 0 hr ; no more unbilled
Assets:Receivable:Client ; infer the amount due from time & rate
2026/10/05 Client ; receive payment from Client
(Assets:Receivable:Client) $-50 = $0 ; no more due
Revenue:Client $-50
Assets:Checking $50
In the first transaction, I was able to make the two unbalanced things balance each other; but the second transaction must use an unbalanced posting, acknowledging that cash accounting doesn't track receivables.
In my own cash-basis accounting, I balance receivables against a temporary equity account:
2026-01-01 send invoice
equity:unrecognisedrevenue -100
assets:receivable 100
2026-01-15 receive payment
assets:receivable -100
equity:unrecognisedrevenue 100
revenues -100
assets 100
This will work for me for now. Thanks for clarifying.
As always, thanks for the help Simon!