timelog: support the description field (fix #247)
This commit is contained in:
parent
fb37e99bc8
commit
5102eca9c3
@ -738,21 +738,39 @@ The original order of same-day entries will be preserved, usually.
|
|||||||
|
|
||||||
### Timelog
|
### Timelog
|
||||||
|
|
||||||
hledger can also read time log files. These are (a subset of) timeclock.el's
|
hledger can also read timelog files.
|
||||||
format, containing clock-in and clock-out entries like so:
|
[As with Ledger](http://ledger-cli.org/3.0/doc/ledger3.html#Time-Keeping),
|
||||||
|
these are (a subset of)
|
||||||
|
[timeclock.el](http://www.emacswiki.org/emacs/TimeClock)'s format,
|
||||||
|
containing clock-in and clock-out entries like so:
|
||||||
|
|
||||||
i 2009/03/31 22:21:45 projects:A
|
i 2015/03/30 09:00:00 some:account name optional description after two spaces
|
||||||
o 2009/04/01 02:00:34
|
o 2015/03/30 09:20:00
|
||||||
|
i 2015/03/31 22:21:45 another account
|
||||||
|
o 2015/04/01 02:00:34
|
||||||
|
|
||||||
hledger treats the clock-in description ("projects:A") as an account name,
|
The date is a [simple date](#simple-dates), so hyphen (-) and period
|
||||||
and creates a virtual transaction (or several - one per day) with the
|
(.) are also allowed as separators, leading zeroes are optional, the
|
||||||
appropriate amount of hours. From the time log above, hledger print gives:
|
year may be omitted (and a [default year directive](#default-year) can
|
||||||
|
be used to set it).
|
||||||
|
|
||||||
2009/03/31 * 22:21-23:59
|
The time format is HH:MM[:SS][+-ZZZZ]. Seconds and timezone are optional.
|
||||||
(projects:A) 1.64h
|
The timezone, if present, must be four digits and is ignored
|
||||||
|
(currently the time is always interpreted as a local time).
|
||||||
|
|
||||||
2009/04/01 * 00:00-02:00
|
hledger treats each clock-in/clock-out pair as a transaction posting
|
||||||
(projects:A) 2.01h
|
some number of hours to a (single) account. Or, several transactions
|
||||||
|
if the session spans more than one day. Eg for the above time log,
|
||||||
|
hledger print gives:
|
||||||
|
|
||||||
|
2015/03/30 * optional description after two spaces
|
||||||
|
(some:account name) 0.33h
|
||||||
|
|
||||||
|
2015/03/31 * 22:21-23:59
|
||||||
|
(another account) 1.64h
|
||||||
|
|
||||||
|
2015/04/01 * 00:00-02:00
|
||||||
|
(another account) 2.01h
|
||||||
|
|
||||||
Here is a
|
Here is a
|
||||||
[sample.timelog](https://raw.github.com/simonmichael/hledger/master/data/sample.timelog) to
|
[sample.timelog](https://raw.github.com/simonmichael/hledger/master/data/sample.timelog) to
|
||||||
|
|||||||
@ -28,7 +28,7 @@ import Hledger.Data.Posting
|
|||||||
import Hledger.Data.Transaction
|
import Hledger.Data.Transaction
|
||||||
|
|
||||||
instance Show TimeLogEntry where
|
instance Show TimeLogEntry where
|
||||||
show t = printf "%s %s %s" (show $ tlcode t) (show $ tldatetime t) (tlcomment t)
|
show t = printf "%s %s %s %s" (show $ tlcode t) (show $ tldatetime t) (tlaccount t) (tldescription t)
|
||||||
|
|
||||||
instance Show TimeLogCode where
|
instance Show TimeLogCode where
|
||||||
show SetBalance = "b"
|
show SetBalance = "b"
|
||||||
@ -54,7 +54,7 @@ timeLogEntriesToTransactions now [i]
|
|||||||
| odate > idate = entryFromTimeLogInOut i o' : timeLogEntriesToTransactions now [i',o]
|
| odate > idate = entryFromTimeLogInOut i o' : timeLogEntriesToTransactions now [i',o]
|
||||||
| otherwise = [entryFromTimeLogInOut i o]
|
| otherwise = [entryFromTimeLogInOut i o]
|
||||||
where
|
where
|
||||||
o = TimeLogEntry (tlsourcepos i) Out end ""
|
o = TimeLogEntry (tlsourcepos i) Out end "" ""
|
||||||
end = if itime > now then itime else now
|
end = if itime > now then itime else now
|
||||||
(itime,otime) = (tldatetime i,tldatetime o)
|
(itime,otime) = (tldatetime i,tldatetime o)
|
||||||
(idate,odate) = (localDay itime,localDay otime)
|
(idate,odate) = (localDay itime,localDay otime)
|
||||||
@ -84,20 +84,22 @@ entryFromTimeLogInOut i o
|
|||||||
tdate2 = Nothing,
|
tdate2 = Nothing,
|
||||||
tstatus = True,
|
tstatus = True,
|
||||||
tcode = "",
|
tcode = "",
|
||||||
tdescription = showtime itod ++ "-" ++ showtime otod,
|
tdescription = desc,
|
||||||
tcomment = "",
|
tcomment = "",
|
||||||
ttags = [],
|
ttags = [],
|
||||||
tpostings = ps,
|
tpostings = ps,
|
||||||
tpreceding_comment_lines=""
|
tpreceding_comment_lines=""
|
||||||
}
|
}
|
||||||
showtime = take 5 . show
|
|
||||||
acctname = tlcomment i
|
|
||||||
itime = tldatetime i
|
itime = tldatetime i
|
||||||
otime = tldatetime o
|
otime = tldatetime o
|
||||||
itod = localTimeOfDay itime
|
itod = localTimeOfDay itime
|
||||||
otod = localTimeOfDay otime
|
otod = localTimeOfDay otime
|
||||||
idate = localDay itime
|
idate = localDay itime
|
||||||
|
desc | null (tldescription i) = showtime itod ++ "-" ++ showtime otod
|
||||||
|
| otherwise = tldescription i
|
||||||
|
showtime = take 5 . show
|
||||||
hours = elapsedSeconds (toutc otime) (toutc itime) / 3600 where toutc = localTimeToUTC utc
|
hours = elapsedSeconds (toutc otime) (toutc itime) / 3600 where toutc = localTimeToUTC utc
|
||||||
|
acctname = tlaccount i
|
||||||
amount = Mixed [hrs hours]
|
amount = Mixed [hrs hours]
|
||||||
ps = [posting{paccount=acctname, pamount=amount, ptype=VirtualPosting, ptransaction=Just t}]
|
ps = [posting{paccount=acctname, pamount=amount, ptype=VirtualPosting, ptransaction=Just t}]
|
||||||
|
|
||||||
@ -122,18 +124,18 @@ tests_Hledger_Data_TimeLog = TestList [
|
|||||||
assertEntriesGiveStrings name es ss = assertEqual name ss (map tdescription $ timeLogEntriesToTransactions now es)
|
assertEntriesGiveStrings name es ss = assertEqual name ss (map tdescription $ timeLogEntriesToTransactions now es)
|
||||||
|
|
||||||
assertEntriesGiveStrings "started yesterday, split session at midnight"
|
assertEntriesGiveStrings "started yesterday, split session at midnight"
|
||||||
[clockin (mktime yesterday "23:00:00") ""]
|
[clockin (mktime yesterday "23:00:00") "" ""]
|
||||||
["23:00-23:59","00:00-"++nowstr]
|
["23:00-23:59","00:00-"++nowstr]
|
||||||
assertEntriesGiveStrings "split multi-day sessions at each midnight"
|
assertEntriesGiveStrings "split multi-day sessions at each midnight"
|
||||||
[clockin (mktime (addDays (-2) today) "23:00:00") ""]
|
[clockin (mktime (addDays (-2) today) "23:00:00") "" ""]
|
||||||
["23:00-23:59","00:00-23:59","00:00-"++nowstr]
|
["23:00-23:59","00:00-23:59","00:00-"++nowstr]
|
||||||
assertEntriesGiveStrings "auto-clock-out if needed"
|
assertEntriesGiveStrings "auto-clock-out if needed"
|
||||||
[clockin (mktime today "00:00:00") ""]
|
[clockin (mktime today "00:00:00") "" ""]
|
||||||
["00:00-"++nowstr]
|
["00:00-"++nowstr]
|
||||||
let future = utcToLocalTime tz $ addUTCTime 100 now'
|
let future = utcToLocalTime tz $ addUTCTime 100 now'
|
||||||
futurestr = showtime future
|
futurestr = showtime future
|
||||||
assertEntriesGiveStrings "use the clockin time for auto-clockout if it's in the future"
|
assertEntriesGiveStrings "use the clockin time for auto-clockout if it's in the future"
|
||||||
[clockin future ""]
|
[clockin future "" ""]
|
||||||
[printf "%s-%s" futurestr futurestr]
|
[printf "%s-%s" futurestr futurestr]
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|||||||
@ -155,7 +155,8 @@ data TimeLogEntry = TimeLogEntry {
|
|||||||
tlsourcepos :: SourcePos,
|
tlsourcepos :: SourcePos,
|
||||||
tlcode :: TimeLogCode,
|
tlcode :: TimeLogCode,
|
||||||
tldatetime :: LocalTime,
|
tldatetime :: LocalTime,
|
||||||
tlcomment :: String
|
tlaccount :: String,
|
||||||
|
tldescription :: String
|
||||||
} deriving (Eq,Ord,Typeable,Data)
|
} deriving (Eq,Ord,Typeable,Data)
|
||||||
|
|
||||||
data HistoricalPrice = HistoricalPrice {
|
data HistoricalPrice = HistoricalPrice {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ module Hledger.Read.JournalReader (
|
|||||||
datetimep,
|
datetimep,
|
||||||
codep,
|
codep,
|
||||||
accountnamep,
|
accountnamep,
|
||||||
|
modifiedaccountname,
|
||||||
postingp,
|
postingp,
|
||||||
amountp,
|
amountp,
|
||||||
amountp',
|
amountp',
|
||||||
|
|||||||
@ -50,6 +50,7 @@ where
|
|||||||
import Control.Monad
|
import Control.Monad
|
||||||
import Control.Monad.Except
|
import Control.Monad.Except
|
||||||
import Data.List (isPrefixOf, foldl')
|
import Data.List (isPrefixOf, foldl')
|
||||||
|
import Data.Maybe (fromMaybe)
|
||||||
import Test.HUnit
|
import Test.HUnit
|
||||||
import Text.Parsec hiding (parse)
|
import Text.Parsec hiding (parse)
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
@ -58,7 +59,7 @@ import Hledger.Data
|
|||||||
-- XXX too much reuse ?
|
-- XXX too much reuse ?
|
||||||
import Hledger.Read.JournalReader (
|
import Hledger.Read.JournalReader (
|
||||||
directive, historicalpricedirective, defaultyeardirective, emptyorcommentlinep, datetimep,
|
directive, historicalpricedirective, defaultyeardirective, emptyorcommentlinep, datetimep,
|
||||||
parseJournalWith, getParentAccount
|
parseJournalWith, modifiedaccountname
|
||||||
)
|
)
|
||||||
import Hledger.Utils
|
import Hledger.Utils
|
||||||
|
|
||||||
@ -104,8 +105,9 @@ timelogentry = do
|
|||||||
code <- oneOf "bhioO"
|
code <- oneOf "bhioO"
|
||||||
many1 spacenonewline
|
many1 spacenonewline
|
||||||
datetime <- datetimep
|
datetime <- datetimep
|
||||||
comment <- optionMaybe (many1 spacenonewline >> liftM2 (++) getParentAccount restofline)
|
account <- fromMaybe "" <$> optionMaybe (many1 spacenonewline >> modifiedaccountname)
|
||||||
return $ TimeLogEntry sourcepos (read [code]) datetime (maybe "" rstrip comment)
|
description <- fromMaybe "" <$> optionMaybe (many1 spacenonewline >> restofline)
|
||||||
|
return $ TimeLogEntry sourcepos (read [code]) datetime account description
|
||||||
|
|
||||||
tests_Hledger_Read_TimelogReader = TestList [
|
tests_Hledger_Read_TimelogReader = TestList [
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,12 +1,22 @@
|
|||||||
# a timelog session is parsed as a similarly-named transaction with one virtual posting
|
# a timelog session is parsed as a similarly-named transaction with one virtual posting
|
||||||
hledgerdev -f - print
|
hledgerdev -f - print
|
||||||
<<<
|
<<<
|
||||||
i 2009/1/1 08:00:00 something
|
i 2009/1/1 08:00:00
|
||||||
o 2009/1/1 09:00:00
|
o 2009/1/1 09:00:00 stuff on checkout record is ignored
|
||||||
|
|
||||||
|
i 2009/1/2 08:00:00 account name
|
||||||
|
o 2009/1/2 09:00:00
|
||||||
|
i 2009/1/3 08:00:00 some:account name and a description
|
||||||
|
o 2009/1/3 09:00:00
|
||||||
>>>
|
>>>
|
||||||
2009/01/01 * 08:00-09:00
|
2009/01/01 * 08:00-09:00
|
||||||
(something) 1.00h
|
() 1.00h
|
||||||
|
|
||||||
|
2009/01/02 * 08:00-09:00
|
||||||
|
(account name) 1.00h
|
||||||
|
|
||||||
|
2009/01/03 * and a description
|
||||||
|
(some:account name) 1.00h
|
||||||
|
|
||||||
>>>2
|
>>>2
|
||||||
>>>= 0
|
>>>= 0
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user