parsing: historical price directives may contain a numeric time zone, like ledger; note that the time is ignored
This commit is contained in:
		
							parent
							
								
									946e5ffcbc
								
							
						
					
					
						commit
						8d62452260
					
				@ -290,6 +290,8 @@ historical price directive (P) as shown:
 | 
				
			|||||||
     expenses:foreign currency       €100
 | 
					     expenses:foreign currency       €100
 | 
				
			||||||
     assets
 | 
					     assets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note: a time and numeric time zone are allowed in historical price directives, but currently ignored.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Or, you can write a transaction in two commodities, without prices but
 | 
					Or, you can write a transaction in two commodities, without prices but
 | 
				
			||||||
with all amounts specified, and a conversion price will be inferred so as
 | 
					with all amounts specified, and a conversion price will be inferred so as
 | 
				
			||||||
to balance the transaction:
 | 
					to balance the transaction:
 | 
				
			||||||
 | 
				
			|||||||
@ -123,8 +123,11 @@ import Data.List
 | 
				
			|||||||
import Data.List.Split (wordsBy)
 | 
					import Data.List.Split (wordsBy)
 | 
				
			||||||
import Data.Maybe
 | 
					import Data.Maybe
 | 
				
			||||||
import Data.Time.Calendar
 | 
					import Data.Time.Calendar
 | 
				
			||||||
 | 
					-- import Data.Time.Clock
 | 
				
			||||||
 | 
					-- import Data.Time.Format
 | 
				
			||||||
import Data.Time.LocalTime
 | 
					import Data.Time.LocalTime
 | 
				
			||||||
import Safe (headDef)
 | 
					import Safe (headDef)
 | 
				
			||||||
 | 
					-- import System.Locale (defaultTimeLocale)
 | 
				
			||||||
import Test.HUnit
 | 
					import Test.HUnit
 | 
				
			||||||
import Text.ParserCombinators.Parsec hiding (parse)
 | 
					import Text.ParserCombinators.Parsec hiding (parse)
 | 
				
			||||||
import Text.Printf
 | 
					import Text.Printf
 | 
				
			||||||
@ -364,6 +367,8 @@ ledgerTransaction = do
 | 
				
			|||||||
  postings <- ledgerpostings
 | 
					  postings <- ledgerpostings
 | 
				
			||||||
  return $ txnTieKnot $ Transaction date edate status code description comment md postings ""
 | 
					  return $ txnTieKnot $ Transaction date edate status code description comment md postings ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- | Parse a date in YYYY/MM/DD format. Fewer digits are allowed. The year
 | 
				
			||||||
 | 
					-- may be omitted if a default year has already been set.
 | 
				
			||||||
ledgerdate :: GenParser Char JournalContext Day
 | 
					ledgerdate :: GenParser Char JournalContext Day
 | 
				
			||||||
ledgerdate = do
 | 
					ledgerdate = do
 | 
				
			||||||
  -- hacky: try to ensure precise errors for invalid dates
 | 
					  -- hacky: try to ensure precise errors for invalid dates
 | 
				
			||||||
@ -383,6 +388,10 @@ ledgerdate = do
 | 
				
			|||||||
    Just date -> return date
 | 
					    Just date -> return date
 | 
				
			||||||
  <?> "full or partial date"
 | 
					  <?> "full or partial date"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- | Parse a date and time in YYYY/MM/DD HH:MM[:SS][+-ZZZZ] format.  Any
 | 
				
			||||||
 | 
					-- timezone will be ignored; the time is treated as local time.  Fewer
 | 
				
			||||||
 | 
					-- digits are allowed, except in the timezone. The year may be omitted if
 | 
				
			||||||
 | 
					-- a default year has already been set.
 | 
				
			||||||
ledgerdatetime :: GenParser Char JournalContext LocalTime
 | 
					ledgerdatetime :: GenParser Char JournalContext LocalTime
 | 
				
			||||||
ledgerdatetime = do 
 | 
					ledgerdatetime = do 
 | 
				
			||||||
  day <- ledgerdate
 | 
					  day <- ledgerdate
 | 
				
			||||||
@ -394,14 +403,22 @@ ledgerdatetime = do
 | 
				
			|||||||
  m <- many1 digit
 | 
					  m <- many1 digit
 | 
				
			||||||
  let m' = read m
 | 
					  let m' = read m
 | 
				
			||||||
  guard $ m' >= 0 && m' <= 59
 | 
					  guard $ m' >= 0 && m' <= 59
 | 
				
			||||||
  s <- optionMaybe $ do
 | 
					  s <- optionMaybe $ char ':' >> many1 digit
 | 
				
			||||||
      char ':'
 | 
					 | 
				
			||||||
      many1 digit
 | 
					 | 
				
			||||||
  let s' = case s of Just sstr -> read sstr
 | 
					  let s' = case s of Just sstr -> read sstr
 | 
				
			||||||
                     Nothing   -> 0
 | 
					                     Nothing   -> 0
 | 
				
			||||||
  guard $ s' >= 0 && s' <= 59
 | 
					  guard $ s' >= 0 && s' <= 59
 | 
				
			||||||
  let tod = TimeOfDay h' m' (fromIntegral s')
 | 
					  {- tz <- -}
 | 
				
			||||||
  return $ LocalTime day tod
 | 
					  optionMaybe $ do
 | 
				
			||||||
 | 
					                   plusminus <- oneOf "-+"
 | 
				
			||||||
 | 
					                   d1 <- digit
 | 
				
			||||||
 | 
					                   d2 <- digit
 | 
				
			||||||
 | 
					                   d3 <- digit
 | 
				
			||||||
 | 
					                   d4 <- digit
 | 
				
			||||||
 | 
					                   return $ plusminus:d1:d2:d3:d4:""
 | 
				
			||||||
 | 
					  -- ltz <- liftIO $ getCurrentTimeZone
 | 
				
			||||||
 | 
					  -- let tz' = maybe ltz (fromMaybe ltz . parseTime defaultTimeLocale "%z") tz
 | 
				
			||||||
 | 
					  -- return $ localTimeToUTC tz' $ LocalTime day $ TimeOfDay h' m' (fromIntegral s')
 | 
				
			||||||
 | 
					  return $ LocalTime day $ TimeOfDay h' m' (fromIntegral s')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ledgereffectivedate :: Day -> GenParser Char JournalContext Day
 | 
					ledgereffectivedate :: Day -> GenParser Char JournalContext Day
 | 
				
			||||||
ledgereffectivedate actualdate = do
 | 
					ledgereffectivedate actualdate = do
 | 
				
			||||||
@ -729,13 +746,20 @@ tests_Hledger_Read_JournalReader = TestList [
 | 
				
			|||||||
     assertParse (parseWithCtx nullctx{ctxYear=Just 2011} ledgerdate "1/1")
 | 
					     assertParse (parseWithCtx nullctx{ctxYear=Just 2011} ledgerdate "1/1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ,"ledgerdatetime" ~: do
 | 
					  ,"ledgerdatetime" ~: do
 | 
				
			||||||
     assertParseFailure (parseWithCtx nullctx ledgerdatetime "2011/1/1")
 | 
					      let p = do {t <- ledgerdatetime; eof; return t}
 | 
				
			||||||
     assertParseFailure (parseWithCtx nullctx ledgerdatetime "2011/1/1 24:00:00")
 | 
					          bad = assertParseFailure . parseWithCtx nullctx p
 | 
				
			||||||
     assertParseFailure (parseWithCtx nullctx ledgerdatetime "2011/1/1 00:60:00")
 | 
					          good = assertParse . parseWithCtx nullctx p
 | 
				
			||||||
     assertParseFailure (parseWithCtx nullctx ledgerdatetime "2011/1/1 00:00:60")
 | 
					      bad "2011/1/1"
 | 
				
			||||||
     assertParse (parseWithCtx nullctx ledgerdatetime "2011/1/1 00:00")
 | 
					      bad "2011/1/1 24:00:00"
 | 
				
			||||||
     assertParse (parseWithCtx nullctx ledgerdatetime "2011/1/1 23:59:59")
 | 
					      bad "2011/1/1 00:60:00"
 | 
				
			||||||
     assertParse (parseWithCtx nullctx ledgerdatetime "2011/1/1 3:5:7")
 | 
					      bad "2011/1/1 00:00:60"
 | 
				
			||||||
 | 
					      good "2011/1/1 00:00"
 | 
				
			||||||
 | 
					      good "2011/1/1 23:59:59"
 | 
				
			||||||
 | 
					      good "2011/1/1 3:5:7"
 | 
				
			||||||
 | 
					      -- timezone is parsed but ignored
 | 
				
			||||||
 | 
					      let startofday = LocalTime (fromGregorian 2011 1 1) (TimeOfDay 0 0 (fromIntegral 0))
 | 
				
			||||||
 | 
					      assertParseEqual (parseWithCtx nullctx p "2011/1/1 00:00-0800") startofday
 | 
				
			||||||
 | 
					      assertParseEqual (parseWithCtx nullctx p "2011/1/1 00:00+1234") startofday
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ,"ledgerDefaultYear" ~: do
 | 
					  ,"ledgerDefaultYear" ~: do
 | 
				
			||||||
     assertParse (parseWithCtx nullctx ledgerDefaultYear "Y 2010\n")
 | 
					     assertParse (parseWithCtx nullctx ledgerDefaultYear "Y 2010\n")
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										21
									
								
								tests/timezone.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								tests/timezone.test
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					# timezone-related tests
 | 
				
			||||||
 | 
					# 1. as in ledger, historical prices may contain a time and timezone.
 | 
				
			||||||
 | 
					# hledger ignores them and uses 00:00 local time instead.
 | 
				
			||||||
 | 
					bin/hledger -f - balance --no-total --cost
 | 
				
			||||||
 | 
					<<<
 | 
				
			||||||
 | 
					P 2011/01/01 00:00:00      A $1
 | 
				
			||||||
 | 
					P 2011/01/01 15:00:00-0100 A $2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2010/12/31
 | 
				
			||||||
 | 
					  (20101231)  1 A
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2011/1/1
 | 
				
			||||||
 | 
					  (20110101)  1 A
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2011/1/2
 | 
				
			||||||
 | 
					  (20110102)  1 A
 | 
				
			||||||
 | 
					>>>
 | 
				
			||||||
 | 
					                 1 A  20101231
 | 
				
			||||||
 | 
					                  $2  20110101
 | 
				
			||||||
 | 
					                  $2  20110102
 | 
				
			||||||
 | 
					>>>=0
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user