hledger & Ledger

History

I discovered John Wiegley's Ledger in 2006, and was very happy to find this efficient command-line reporting tool with a transparent data format.

Initially, I used it to generate time reports for my job. Before long I wanted that to work differently - splitting sessions at day boundaries, reporting in hours, etc. John had got busy elsewhere and the Ledger project now stalled, with unfixed bugs, wrong documentation and a confusing release situation persisting for a long time. I did what I could to help build momentum, reporting bugs, supporting newcomers, and contributing a new domain and website. But, I didn't want to spend time learning C++.

I was learning Haskell, which I did want to spend time in. I felt Ledger could be implemented well and, in the long run, more efficiently in that language, which has some compelling advantages such as lower maintenance costs. I urgently needed a reliable accounting tool that I enjoyed using. I also wanted to see what I could do to reduce roadbumps and confusion for newcomers.

I couldn't expect John to start over - at that time he was not the Haskell fan he is now! So in 2007 I began experimenting. I built a toy parser in a few different languages, and it was easiest in Haskell. I kept tinkering. Goals included:

to get better at Haskell by building something useful to me,

to learn how well Haskell could work for real-world applications,

and eventually: to provide a new implementation focussing more on ease of use, absence of user-visible bugs, and high-quality documentation and web presence. Also to experiment with new user interfaces, APIs, etc.

Before too long I had a tool that was useful to me. With Ledger still installed, and by maintaining high compatibility, I now had two tools with different strengths, each providing a comparison for the other in case of confusion or suspected bugs, which was itself quite valuable.

Happily, the Ledger project later revived and has attracted new active contributors. I have remained active in that community, sharing discoveries and design discussions, and we have seen many ideas travelling in both directions. hledger shared #ledger's IRC channel until 2014, when I added #hledger to allow us more space.

I think having independent but compatible implementations has been quite helpful for troubleshooting, exploring the design space, and growing the "Ledger-likes" community. My other projects in that direction include the ledger-cli.org site, LedgerTips, IRC support on #ledger, and now plaintextaccounting.org.

Compared to hledger, Ledger has additional power-user features such as the built in value expressions language, and it remains faster and more memory efficient on large files (for now).

We currently support:

Ledger's journal format, mostly

csv format

timeclock format

regular journal transactions

multiple commodities

fixed transaction prices

varying market prices

virtual postings

some basic output formatting

the print, register & balance commands

report filtering, using a different query syntax

automated postings

periodic transactions

budget reports

We do not yet support:

-X/--exchange

generation of revaluation transactions (--revalued)

capital gain/loss reporting (--gain)

value expressions

And we add some new commands, such as:

add

balancesheet

cashflow

close

incomestatement

irr

interest

ui

web

File formats

hledger's journal file format is very close to Ledger's. Some unsupported Ledger syntax is parsed but ignored; some is not parsed and will cause an error (eg value expressions). There can also be subtle differences in parser behaviour, such as with hledger comments vs Ledger comments, or balance assertions.

It's quite possible (and useful) to keep a journal file that works with both hledger and Ledger, if you avoid the more exotic syntax. Or, you can keep the hledger- and Ledger-specific bits in separate files, which include a common file compatible with both:

hledger splits multi-day time sessions at midnight by default (Ledger does this with an option)

hledger's output follows the decimal point character, digit grouping, and digit group separator character used in the journal (or specified with commodity directives)

hledger print ignores the --date2 flag, always showing both dates. ledger print shows only the secondary date with --aux-date, but not vice versa.

hledger's default commodity directive (D) sets the commodity to be used for subsequent commodityless amounts, and also sets that commodity's display settings if such an amount is the first seen. Ledger uses D only for commodity display settings and for the entry command.

hledger's include directive does not support shell glob patterns (eg include *.journal ), as Ledger's does.

when checking balance assertions hledger sorts the account's postings first by date and then (for postings with the same date) by parse order. Ledger checks assertions in parse order, ignoring dates.

Ledger allows amounts to have a fixed lot price (the {} syntax ?) and a regular price in any order (and uses whichever appears first). hledger requires the fixed lot price to come last (and ignores it).

hledger's -p option doesn't combine nicely with -b/-e/-D/-W/-M/-Q/-Y. Basically if there's a -p, all those others are ignored. There's an open issue. With hledger you can also specify start and/or end dates with a query argument, like date:START-END

in hledger version 1.3 onward, the "uncleared" status has been renamed to "unmarked", it is matched by the -U/--unmarked flag. Also, the --unmarked/--pending/--cleared flags can be combined, so eg -UP matches unmarked and pending, similar to Ledger's --uncleared flag. (#564)

hledger's -P flag is short for --pending. Ledger uses it for grouping by payee.

Future ?

There is a ledger4 repo on github; this is John's 2012/2013 rewrite of some parts of Ledger 3, including the parser, in Haskell. We have a plan to add this parser to hledger in 2015/2016, increasing its ability to read Ledger's files.

UI surprises

Why does it complain about missing amounts even though I wrote one ?

This is an easy mistake at first. This journal entry:

1/1
a 1
b

will give a parse error (...can't have more than one real posting with no amount...).

There must always be at least two spaces between the account name and amount. So instead, it should be:

1/1
a 1
b

Why do some amounts appear on their own line with no account name ?

When hledger needs to show a multi-commodity amount, each commodity is displayed on its own line, one above the other (like Ledger).

Here are some examples. With this journal, the implicit balancing amount drawn from the b account will be a multicommodity amount (a euro and a dollar):

2015/1/1
a EUR 1
a USD 1
b

the print command shows the b posting's amount on two lines, bottom-aligned: