mirror of
https://github.com/facebook/duckling.git
synced 2024-09-11 21:27:13 +03:00
Duration/RU: For non-int times, use the coarsest grain
Summary: This commit fixes #111, which was an open issue that any non-integer multiple of any unit of time was being converted to seconds. My solution is to write a recursive function `Duration.Helpers.inCoarsestGrain` which, given a grain `g` and double value `v` finds the coarses grain `g'` such that `v * g` - rounded to the nearest seconds - has integral units. We call this function only in the case of non-integer multiples, and we start our search from the given grain because nothing coarser would make sense. The code could actually be slightly more efficient if we started at the next-smallest grain, but in the interest of clarity I think this is probably better. Reviewed By: chessai Differential Revision: D27891439 fbshipit-source-id: b048310963eb71337fd91ab4ef3c840134a76e73
This commit is contained in:
parent
f73277c2b0
commit
23ec021b07
@ -13,6 +13,7 @@
|
||||
* Duration: Diminutives for minutes and hours
|
||||
* Duration: quarters of an hour
|
||||
* Duration: added 'сутки' (24-hour period)
|
||||
* Duration: use coarsest reasonable grain for \<positive-non-integer\> \<time-grain\>
|
||||
|
||||
### Server
|
||||
|
||||
|
@ -16,6 +16,7 @@ module Duckling.Duration.Helpers
|
||||
, secondsFromHourMixedFraction
|
||||
, timesOneQuarter
|
||||
, timesThreeQuarter
|
||||
, inCoarsestGrain
|
||||
) where
|
||||
|
||||
import Prelude
|
||||
@ -25,6 +26,7 @@ import Duckling.Duration.Types (DurationData (DurationData))
|
||||
import Duckling.Numeral.Helpers (isNatural)
|
||||
import Duckling.Types
|
||||
import qualified Duckling.Duration.Types as TDuration
|
||||
import qualified Duckling.Numeral.Types as TNumeral
|
||||
import qualified Duckling.TimeGrain.Types as TG
|
||||
|
||||
-- -----------------------------------------------------------------
|
||||
@ -74,3 +76,15 @@ timesThreeQuarter grain = case grain of
|
||||
TG.Month -> Just . duration TG.Day . (21+) . (30*)
|
||||
TG.Year -> Just . duration TG.Month . (9+) . (12*)
|
||||
_ -> const Nothing
|
||||
|
||||
inCoarsestGrain :: TG.Grain -> Double -> DurationData
|
||||
inCoarsestGrain g v =
|
||||
go g
|
||||
where
|
||||
seconds = fromIntegral (floor $ TG.inSeconds g v :: Int)
|
||||
go grain =
|
||||
-- recursion terminates because `seconds` is an Integer
|
||||
let inGrain = seconds / TG.inSeconds grain 1
|
||||
in case TNumeral.getIntValue inGrain of
|
||||
Just n -> duration grain n
|
||||
Nothing -> go $ TG.lower grain
|
||||
|
@ -58,10 +58,12 @@ allExamples = concat
|
||||
, "3 четверти часа"
|
||||
, "три четверти часа"
|
||||
]
|
||||
, examples (DurationData 5400 Second)
|
||||
, examples (DurationData 90 Minute)
|
||||
[ "полтора часа"
|
||||
, "1.5 часа"
|
||||
, "5400 секунд"
|
||||
]
|
||||
, examples (DurationData 5400 Second)
|
||||
[ "5400 секунд"
|
||||
]
|
||||
, examples (DurationData 8 Hour)
|
||||
[ "8 часов"
|
||||
@ -88,7 +90,7 @@ allExamples = concat
|
||||
, "полгода"
|
||||
, "пол года"
|
||||
]
|
||||
, examples (DurationData 9072000 Second)
|
||||
, examples (DurationData 105 Day)
|
||||
[ "3.5 месяца"
|
||||
, "три с половиной месяца"
|
||||
, "приблизительно 3.5 месяца"
|
||||
|
@ -97,7 +97,7 @@ ruleGrainAsDuration = Rule
|
||||
|
||||
rulePositiveDuration :: Rule
|
||||
rulePositiveDuration = Rule
|
||||
{ name = "<positive-numeral> <time-grain>"
|
||||
{ name = "<positive-non-integer> <time-grain>"
|
||||
, pattern =
|
||||
[ numberWith TNumeral.value $ and . sequence [not . isInteger, (>0)]
|
||||
, dimension TimeGrain
|
||||
@ -105,7 +105,8 @@ rulePositiveDuration = Rule
|
||||
, prod = \case
|
||||
(Token Numeral NumeralData{TNumeral.value = v}:
|
||||
Token TimeGrain grain:
|
||||
_) -> Just $ Token Duration $ duration Second $ floor $ inSeconds grain v
|
||||
_) ->
|
||||
Just $ Token Duration $ inCoarsestGrain grain v
|
||||
_ -> Nothing
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user