diff --git a/doc/manual.md b/doc/manual.md index a3b396b36..84d370fcb 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -738,21 +738,39 @@ The original order of same-day entries will be preserved, usually. ### Timelog -hledger can also read time log files. These are (a subset of) timeclock.el's -format, containing clock-in and clock-out entries like so: +hledger can also read timelog files. +[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 - o 2009/04/01 02:00:34 + i 2015/03/30 09:00:00 some:account name optional description after two spaces + 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, -and creates a virtual transaction (or several - one per day) with the -appropriate amount of hours. From the time log above, hledger print gives: +The date is a [simple date](#simple-dates), so hyphen (-) and period +(.) are also allowed as separators, leading zeroes are optional, the +year may be omitted (and a [default year directive](#default-year) can +be used to set it). - 2009/03/31 * 22:21-23:59 - (projects:A) 1.64h - - 2009/04/01 * 00:00-02:00 - (projects:A) 2.01h +The time format is HH:MM[:SS][+-ZZZZ]. Seconds and timezone are optional. +The timezone, if present, must be four digits and is ignored +(currently the time is always interpreted as a local time). + +hledger treats each clock-in/clock-out pair as a transaction posting +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 [sample.timelog](https://raw.github.com/simonmichael/hledger/master/data/sample.timelog) to diff --git a/hledger-lib/Hledger/Data/TimeLog.hs b/hledger-lib/Hledger/Data/TimeLog.hs index 3d6315289..b381c783b 100644 --- a/hledger-lib/Hledger/Data/TimeLog.hs +++ b/hledger-lib/Hledger/Data/TimeLog.hs @@ -28,7 +28,7 @@ import Hledger.Data.Posting import Hledger.Data.Transaction 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 show SetBalance = "b" @@ -54,7 +54,7 @@ timeLogEntriesToTransactions now [i] | odate > idate = entryFromTimeLogInOut i o' : timeLogEntriesToTransactions now [i',o] | otherwise = [entryFromTimeLogInOut i o] where - o = TimeLogEntry (tlsourcepos i) Out end "" + o = TimeLogEntry (tlsourcepos i) Out end "" "" end = if itime > now then itime else now (itime,otime) = (tldatetime i,tldatetime o) (idate,odate) = (localDay itime,localDay otime) @@ -84,20 +84,22 @@ entryFromTimeLogInOut i o tdate2 = Nothing, tstatus = True, tcode = "", - tdescription = showtime itod ++ "-" ++ showtime otod, + tdescription = desc, tcomment = "", ttags = [], tpostings = ps, tpreceding_comment_lines="" } - showtime = take 5 . show - acctname = tlcomment i itime = tldatetime i otime = tldatetime o itod = localTimeOfDay itime otod = localTimeOfDay otime 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 + acctname = tlaccount i amount = Mixed [hrs hours] 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 "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] 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] assertEntriesGiveStrings "auto-clock-out if needed" - [clockin (mktime today "00:00:00") ""] + [clockin (mktime today "00:00:00") "" ""] ["00:00-"++nowstr] let future = utcToLocalTime tz $ addUTCTime 100 now' futurestr = showtime future assertEntriesGiveStrings "use the clockin time for auto-clockout if it's in the future" - [clockin future ""] + [clockin future "" ""] [printf "%s-%s" futurestr futurestr] ] diff --git a/hledger-lib/Hledger/Data/Types.hs b/hledger-lib/Hledger/Data/Types.hs index a9fd652bc..a35575e70 100644 --- a/hledger-lib/Hledger/Data/Types.hs +++ b/hledger-lib/Hledger/Data/Types.hs @@ -155,7 +155,8 @@ data TimeLogEntry = TimeLogEntry { tlsourcepos :: SourcePos, tlcode :: TimeLogCode, tldatetime :: LocalTime, - tlcomment :: String + tlaccount :: String, + tldescription :: String } deriving (Eq,Ord,Typeable,Data) data HistoricalPrice = HistoricalPrice { diff --git a/hledger-lib/Hledger/Read/JournalReader.hs b/hledger-lib/Hledger/Read/JournalReader.hs index b748dfe11..77a66ba56 100644 --- a/hledger-lib/Hledger/Read/JournalReader.hs +++ b/hledger-lib/Hledger/Read/JournalReader.hs @@ -30,6 +30,7 @@ module Hledger.Read.JournalReader ( datetimep, codep, accountnamep, + modifiedaccountname, postingp, amountp, amountp', diff --git a/hledger-lib/Hledger/Read/TimelogReader.hs b/hledger-lib/Hledger/Read/TimelogReader.hs index 047481ffa..8ea8d00f2 100644 --- a/hledger-lib/Hledger/Read/TimelogReader.hs +++ b/hledger-lib/Hledger/Read/TimelogReader.hs @@ -50,6 +50,7 @@ where import Control.Monad import Control.Monad.Except import Data.List (isPrefixOf, foldl') +import Data.Maybe (fromMaybe) import Test.HUnit import Text.Parsec hiding (parse) import System.FilePath @@ -58,7 +59,7 @@ import Hledger.Data -- XXX too much reuse ? import Hledger.Read.JournalReader ( directive, historicalpricedirective, defaultyeardirective, emptyorcommentlinep, datetimep, - parseJournalWith, getParentAccount + parseJournalWith, modifiedaccountname ) import Hledger.Utils @@ -104,8 +105,9 @@ timelogentry = do code <- oneOf "bhioO" many1 spacenonewline datetime <- datetimep - comment <- optionMaybe (many1 spacenonewline >> liftM2 (++) getParentAccount restofline) - return $ TimeLogEntry sourcepos (read [code]) datetime (maybe "" rstrip comment) + account <- fromMaybe "" <$> optionMaybe (many1 spacenonewline >> modifiedaccountname) + description <- fromMaybe "" <$> optionMaybe (many1 spacenonewline >> restofline) + return $ TimeLogEntry sourcepos (read [code]) datetime account description tests_Hledger_Read_TimelogReader = TestList [ ] diff --git a/tests/timelog/timelog.test b/tests/timelog/timelog.test index 9e9b35194..a00fd8bd9 100644 --- a/tests/timelog/timelog.test +++ b/tests/timelog/timelog.test @@ -1,12 +1,22 @@ # a timelog session is parsed as a similarly-named transaction with one virtual posting hledgerdev -f - print <<< -i 2009/1/1 08:00:00 something -o 2009/1/1 09:00:00 +i 2009/1/1 08: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 - (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 >>>= 0