lib: Fix splitSpan for nthdayof{week,month} - start of DateSpan was not covered

Demonstration:

Consider year-test.journal:
```
2015/02/01 first half
    expenses  $1
    assets

2015/07/01 second half
    expenses  $2
    assets

2016/02/01 first half
    expenses  $4
    assets

2016/07/01 second half
    expenses  $8
    assets

2017/02/01 first half
    expenses  $16
    assets

2017/07/01 second half
    expenses  $32
    assets
```

Year balances are good:
```
$ hledger balance -f year-test.journal -p yearly
Balance changes in 2015/01/01-2017/12/31:

          || 2015  2016  2017
==========++==================
 assets   ||  $-3  $-12  $-48
 expenses ||   $3   $12   $48
----------++------------------
          ||    0     0     0
```

Note how first transaction in 2015 is not included. Note that this is old period expression, so this bug exsits in master:
```$ hledger balance -f year-test.journal -p 'every 2nd day of month'
Balance changes in 2015/07/02-2017/07/01:

          || 2015/07/02-2015/08/01  2015/08/02-2015/09/01  2015/09/02-2015/10/01  2015/10/02-2015/11/01  2015/11/02-2015/12/01  2015/12/02-2016/01/01  2016/01/02-2016/02/01  2016/02/02-2016/03/01  2016/03/02-2016/04/01  2016/04/02-2016/05/01  2016/05/02-2016/06/01  2016/06/02-2016/07/01  2016/07/02-2016/08/01  2016/08/02-2016/09/01  2016/09/02-2016/10/01  2016/10/02-2016/11/01  2016/11/02-2016/12/01  2016/12/02-2017/01/01  2017/01/02-2017/02/01  2017/02/02-2017/03/01  2017/03/02-2017/04/01  2017/04/02-2017/05/01  2017/05/02-2017/06/01  2017/06/02-2017/07/01
==========++========================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
 assets   ||                     0                      0                      0                      0                      0                      0                    $-4                      0                      0                      0                      0                    $-8                      0                      0                      0                      0                      0                      0                   $-16                      0                      0                      0                      0                   $-32
 expenses ||                     0                      0                      0                      0                      0                      0                     $4                      0                      0                      0                      0                     $8                      0                      0                      0                      0                      0                      0                    $16                      0                      0                      0                      0                    $32
----------++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
          ||                     0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0                      0
```

Note how 2015 is absent entirely. This is new expression, but i think that general nature of bug is the same...
```
$ hledger balance -f year-test.journal -p 'every 4th Apr'
Balance changes in 2016/04/04-2018/04/03:

          || 2016/04/04-2017/04/03  2017/04/04-2018/04/03
==========++==============================================
 assets   ||                  $-24                   $-32
 expenses ||                   $24                    $32
----------++----------------------------------------------
          ||                     0                      0
```
This commit is contained in:
Dmitry Astapov 2017-11-24 21:51:51 +00:00
parent fbd28be6cb
commit 4049455f26

View File

@ -165,9 +165,9 @@ spansSpan spans = DateSpan (maybe Nothing spanStart $ headMay spans) (maybe Noth
-- >>> t (Weeks 2) "2008/01/01" "2008/01/15" -- >>> t (Weeks 2) "2008/01/01" "2008/01/15"
-- [DateSpan 2007/12/31-2008/01/13,DateSpan 2008/01/14-2008/01/27] -- [DateSpan 2007/12/31-2008/01/13,DateSpan 2008/01/14-2008/01/27]
-- >>> t (DayOfMonth 2) "2008/01/01" "2008/04/01" -- >>> t (DayOfMonth 2) "2008/01/01" "2008/04/01"
-- [DateSpan 2008/01/02-2008/02/01,DateSpan 2008/02/02-2008/03/01,DateSpan 2008/03/02-2008/04/01] -- [DateSpan 2007/12/02-2008/01/01,DateSpan 2008/01/02-2008/02/01,DateSpan 2008/02/02-2008/03/01,DateSpan 2008/03/02-2008/04/01]
-- >>> t (DayOfWeek 2) "2011/01/01" "2011/01/15" -- >>> t (DayOfWeek 2) "2011/01/01" "2011/01/15"
-- [DateSpan 2011/01/04-2011/01/10,DateSpan 2011/01/11-2011/01/17] -- [DateSpan 2010/12/28-2011/01/03,DateSpan 2011/01/04-2011/01/10,DateSpan 2011/01/11-2011/01/17]
-- --
splitSpan :: Interval -> DateSpan -> [DateSpan] splitSpan :: Interval -> DateSpan -> [DateSpan]
splitSpan _ (DateSpan Nothing Nothing) = [DateSpan Nothing Nothing] splitSpan _ (DateSpan Nothing Nothing) = [DateSpan Nothing Nothing]
@ -461,16 +461,51 @@ prevyear = startofyear . addGregorianYearsClip (-1)
nextyear = startofyear . addGregorianYearsClip 1 nextyear = startofyear . addGregorianYearsClip 1
startofyear day = fromGregorian y 1 1 where (y,_,_) = toGregorian day startofyear day = fromGregorian y 1 1 where (y,_,_) = toGregorian day
nthdayofmonthcontaining n d | d1 >= d = d1 -- | For given date d find month-long interval that starts on nth day of month
| otherwise = d2 -- and covers it.
where d1 = addDays (fromIntegral n-1) s --
d2 = addDays (fromIntegral n-1) $ nextmonth s -- Examples: lets take 2017-11-22. Month-long intervals covering it that
-- start on 1st-22nd of month will start in Nov. However
-- intervals that start on 23rd-30th of month should start in Oct:
-- >>> let wed22nd = parsedate "2017-11-22"
-- >>> nthdayofmonthcontaining 1 wed22nd
-- 2017-11-01
-- >>> nthdayofmonthcontaining 12 wed22nd
-- 2017-11-12
-- >>> nthdayofmonthcontaining 22 wed22nd
-- 2017-11-22
-- >>> nthdayofmonthcontaining 23 wed22nd
-- 2017-10-23
-- >>> nthdayofmonthcontaining 30 wed22nd
-- 2017-10-30
nthdayofmonthcontaining n d | nthOfSameMonth <= d = nthOfSameMonth
| otherwise = nthOfPrevMonth
where nthOfSameMonth = addDays (fromIntegral n-1) s
nthOfPrevMonth = addDays (fromIntegral n-1) $ prevmonth s
s = startofmonth d s = startofmonth d
nthdayofweekcontaining n d | d1 >= d = d1
| otherwise = d2 -- | For given date d find week-long interval that starts on nth day of week
where d1 = addDays (fromIntegral n-1) s -- and covers it.
d2 = addDays (fromIntegral n-1) $ nextweek s --
-- Examples: 2017-11-22 is Wed. Week-long intervals that cover it and
-- start on Mon, Tue or Wed will start in the same week. However
-- intervals that start on Thu or Fri should start in prev week:
-- >>> let wed22nd = parsedate "2017-11-22"
-- >>> nthdayofweekcontaining 1 wed22nd
-- 2017-11-20
-- >>> nthdayofweekcontaining 2 wed22nd
-- 2017-11-21
-- >>> nthdayofweekcontaining 3 wed22nd
-- 2017-11-22
-- >>> nthdayofweekcontaining 4 wed22nd
-- 2017-11-16
-- >>> nthdayofweekcontaining 5 wed22nd
-- 2017-11-17
nthdayofweekcontaining n d | nthOfSameWeek <= d = nthOfSameWeek
| otherwise = nthOfPrevWeek
where nthOfSameWeek = addDays (fromIntegral n-1) s
nthOfPrevWeek = addDays (fromIntegral n-1) $ prevweek s
s = startofweek d s = startofweek d
---------------------------------------------------------------------- ----------------------------------------------------------------------