hledger icon indicating copy to clipboard operation
hledger copied to clipboard

Internal representations of time entries are rounded

Open ben-denham opened this issue 1 year ago • 5 comments

Thanks very much for the great software, I've really been enjoying using it.

I've been working with timeclock files, and I believe I may have found an issue with how time entries are rounded, though I'm not sure what the correct/intended behaviour should be.

Based on this comment, it sounds like the intent is for time entries to be represented internally as seconds, but be displayed as hours rounded to 2 decimal places?

However, it looks like the current implementation (tested in versions 1.30 and 1.22 on Ubuntu) represents each time entry internally as hours to 2 decimal places, which can lead to some unintuitive results. In the example below, despite logging a total of 2 minutes against each account, the two 1-minute entries for account a result in a greater total than the single 2-minute entry for account b:

$ cat test.timeclock
i 2023-07-17 09:00:00 a
o 2023-07-17 09:01:00

i 2023-07-17 10:00:00 a
o 2023-07-17 10:01:00

i 2023-07-17 11:00:00 b
o 2023-07-17 11:02:00

$ hledger -f test.timeclock bal
               0.04h  a
               0.03h  b
--------------------
               0.07h

Version 1.21 has an issue with printing many decimal places, but version 1.20.4 appears to use internal representations with resolution in seconds, giving different (and arguably more accurate) results:

$ hledger-1.20.4 -f test.timeclock bal
               0.03h  a
               0.03h  b
--------------------
               0.07h

However, because version 1.20.4 still prints transactions in hours to 2 decimal places, there is a loss of resolution when printing transactions:

$ hledger-1.20.4 -f test.timeclock print
2023-07-17 * 09:00-09:01
    (a)           0.02h

2023-07-17 * 10:00-10:01
    (a)           0.02h

2023-07-17 * 11:00-11:02
    (b)           0.03h

$ hledger-1.20.4 -f test.timeclock print | hledger-1.20.4 -f - bal
               0.04h  a
               0.03h  b
--------------------
               0.07h

I'm not sure how simple/feasible it would be, but it seems like the desired behaviour would be to handle time entries like ledger does: representing them internally as seconds, printing transactions in seconds, and formatting in minutes/hours where appropriate:

$ ledger -f test.timeclock print
2023/07/17 ()
    (a)                                          60s

2023/07/17 ()
    (a)                                          60s

2023/07/17 ()
    (b)                                         120s

$ ledger -f test.timeclock print | ledger -f - bal
                2.0m  a
                2.0m  b
--------------------
                4.0m

It seems like this might require a reader that parses timeclock files as a seconds (s) commodity, and then with minute/hour formatting handled with something like ledger's C directive:

C 1 m = 60 s
C 1 h = 60 m

ben-denham avatar Jul 17 '23 22:07 ben-denham

Good example! It gives a strange balance report since 1.22, as you say. I welcome any help with this.

simonmichael avatar Jul 18 '23 00:07 simonmichael

Thanks @simonmichael, happy to help out if I can, though Haskell is a bit new to me :slightly_smiling_face:

Any thoughts on the direction for the fix? Does recording time in seconds instead of hours sound feasible? It looks like it would be a reasonably straightforward change to TimedotReader.hs and Timeclock.hs to create postings in seconds instead of hours, but I don't know what would need to be changed to support the C Directive to treat hours/minutes/seconds as a single commodity that can be recorded and displayed in different ways.

ben-denham avatar Jul 18 '23 01:07 ben-denham

Switching to seconds as the internal commodity does sound sensible, but I'm not exactly sure how to make it fit. Ideally the external behaviour would remain the same at least by default, except with more consistent balance reports as in 1.21. But maybe that's not practical ?

simonmichael avatar Jul 19 '23 20:07 simonmichael

Ie, will this force us to finally add some kind of C support, or some other way of displaying different units from what was parsed ? But how did 1.21 manage it ?

simonmichael avatar Jul 19 '23 20:07 simonmichael

How did 1.20 manage it I should say (ignoring 1.21 which had a decimal rendering bug).

simonmichael avatar Jul 19 '23 20:07 simonmichael