duckling/Duckling/Time/RU/Rules.hs
Aleksey Landyrev 590651150b Add Time dimension for RU language
Summary: Used b40e2147a9 as reference

Reviewed By: kappa

Differential Revision: D24773196

Pulled By: chessai

fbshipit-source-id: 7cc008c0ee80f930efd76e39bb16ca91ec94b641
2021-02-12 12:02:44 -08:00

1136 lines
29 KiB
Haskell
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- Copyright (c) 2016-present, Facebook, Inc.
-- All rights reserved.
--
-- This source code is licensed under the BSD-style license found in the
-- LICENSE file in the root directory of this source tree.
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NoRebindableSyntax #-}
{-# LANGUAGE OverloadedStrings #-}
module Duckling.Time.RU.Rules
( rules
) where
import Prelude
import qualified Data.Text as Text
import Duckling.Dimensions.Types
import Duckling.Duration.Helpers (isGrain)
import Duckling.Numeral.Helpers (parseInt)
import Duckling.Ordinal.Types (OrdinalData(..))
import Duckling.Regex.Types
import Duckling.Time.Helpers
import Duckling.Time.Types (TimeData(..))
import Duckling.Types
import qualified Duckling.Ordinal.Types as TOrdinal
import qualified Duckling.Time.Types as TTime
import qualified Duckling.TimeGrain.Types as TG
ruleInstants :: [Rule]
ruleInstants = mkRuleInstants
[ ( "сейчас" , TG.Second , 0, "сейчас" )
, ( "сегодня" , TG.Day , 0, "сегодня" )
, ( "завтра" , TG.Day , 1, "завтра" )
, ( "вчера" , TG.Day , -1, "вчера" )
, ( "послезавтра" , TG.Day , 2, "послезавтра" )
, ( "позавчера" , TG.Day , -2, "позавчера" )
, ( "Конец месяца" , TG.Month , 1, "(конец|конца) месяца" )
, ( "Конец года" , TG.Year , 1, "(конец|конца) года" )
]
ruleDaysOfWeek :: [Rule]
ruleDaysOfWeek = mkRuleDaysOfWeek
[ ( "Понедельник" , "понедельник(а)?|пн" )
, ( "Вторник" , "вторник(а)?|вт" )
, ( "Среда" , "сред(а|у)|ср" )
, ( "Четверг" , "четверг(а)?|чт" )
, ( "Пятница" , "пятниц(а|у)|пт" )
, ( "Суббота" , "суббот(а|у)|сб" )
, ( "Воскресенье" , "воскресенье|вс" )
]
ruleMonths :: [Rule]
ruleMonths = mkRuleMonths
[ ( "Январь" , "январ(ь|я)|янв\\.?" )
, ( "Февраль" , "феврал(ь|я)|фев\\.?" )
, ( "Март" , "март(а)?|мар\\.?" )
, ( "Апрель" , "апрел(ь|я)|апр\\.?" )
, ( "Май" , "ма(й|я)" )
, ( "Июнь" , "июн(ь|я)|июн\\.?" )
, ( "Июль" , "июл(ь|я)|июл\\.?" )
, ( "Август" , "август(а)?|авг\\.?" )
, ( "Сентябрь" , "сентябр(ь|я)|сен\\.?" )
, ( "Октябрь" , "октябр(ь|я)|окт\\.?" )
, ( "Ноябрь" , "ноябр(ь|я)?|ноя\\.?" )
, ( "Декабрь" , "декабр(ь|я)|дек\\.?" )
]
ruleSeasons :: [Rule]
ruleSeasons = mkRuleSeasons
[ ( "лето" , "лет(о|а)" , monthDay 6 1, monthDay 8 31 )
, ( "осень" , "осень" , monthDay 9 1, monthDay 11 30 )
, ( "зима" , "зима" , monthDay 12 1, monthDay 2 28 )
, ( "весна" , "весна" , monthDay 3 1, monthDay 5 31 )
]
ruleHolidays :: [Rule]
ruleHolidays = mkRuleHolidays
[ ( "Новый год" , "Новый год" , monthDay 1 1 )
, ( "Рождество Христово" , "рождество( христово)?" , monthDay 1 7 )
, ( "День защитника отечества" , "день защитника" , monthDay 2 23 )
, ( "Международный женский день" , "международный женский день" , monthDay 3 8 )
, ( "День смеха" , "день смеха" , monthDay 4 1 )
, ( "Праздник Весны и Труда" , "день труда" , monthDay 5 1 )
, ( "День Победы" , "День Победы" , monthDay 5 9 )
, ( "День России" , "день россии" , monthDay 6 12 )
, ( "День народного единства" , "день единства" , monthDay 11 4 )
]
ruleLastTime :: Rule
ruleLastTime = Rule
{ name = "last <time>"
, pattern =
[ regex "(в )?прошл(ый|ого|ому|ом|ые|ых|ым|ыми|ая)"
, Predicate isOkWithThisNext
]
, prod = \case
(_:Token Time td:_) ->
tt $ predNth (-1) False td
_ -> Nothing
}
ruleDatetimeDatetimeInterval :: Rule
ruleDatetimeDatetimeInterval = Rule
{ name = "<datetime> - <datetime> (interval)"
, pattern =
[ Predicate isNotLatent
, regex "\\-"
, Predicate isNotLatent
]
, prod = \case
(Token Time td1:_:Token Time td2:_) ->
Token Time <$> interval TTime.Closed td1 td2
_ -> Nothing
}
ruleDateDateInterval :: Rule
ruleDateDateInterval = Rule
{ name = "dd.(mm.)? - dd.mm.(yy[yy]?)? (interval)"
, pattern =
[ regex "(?:с\\s+)?(10|20|30|31|[012]?[1-9])\\.?((?<=\\.)(?:10|11|12|0?[1-9])(?:\\.?))?"
, regex "\\-|/|по"
, regex "(10|20|30|31|[012]?[1-9])\\.(10|11|12|0?[1-9])\\.?((?<=\\.)\\d{2,4})?"
]
, prod = \case
(Token RegexMatch (GroupMatch (d1:"":_)):
_:
Token RegexMatch (GroupMatch (d2:m2:"":_)):
_) -> do
d1 <- parseInt d1
d2 <- parseInt d2
m2 <- parseInt m2
Token Time <$> interval TTime.Closed (monthDay m2 d1) (monthDay m2 d2)
(Token RegexMatch (GroupMatch (d1:"":_)):
_:
Token RegexMatch (GroupMatch (d2:m2:y:_)):
_) -> do
d1 <- parseInt d1
d2 <- parseInt d2
m2 <- parseInt m2
y <- parseInt y
Token Time <$> interval TTime.Closed (yearMonthDay y m2 d1) (yearMonthDay y m2 d2)
(Token RegexMatch (GroupMatch (d1:m1:_)):
_:
Token RegexMatch (GroupMatch (d2:m2:"":_)):
_) -> do
d1 <- parseInt d1
d2 <- parseInt d2
m1 <- parseInt m1
m2 <- parseInt m2
Token Time <$> interval TTime.Closed (monthDay m1 d1) (monthDay m2 d2)
(Token RegexMatch (GroupMatch (d1:m1:_)):
_:
Token RegexMatch (GroupMatch (d2:m2:y:_)):
_) -> do
d1 <- parseInt d1
d2 <- parseInt d2
m1 <- parseInt m1
m2 <- parseInt m2
y <- parseInt y
Token Time <$> interval TTime.Closed (yearMonthDay y m1 d1) (yearMonthDay y m2 d2)
_ -> Nothing
}
ruleInDuration :: Rule
ruleInDuration = Rule
{ name = "in <duration>"
, pattern =
[ regex "через"
, dimension Duration
]
, prod = \case
(_:Token Duration dd:_) ->
tt $ inDuration dd
_ -> Nothing
}
ruleLastCycleOfTime :: Rule
ruleLastCycleOfTime = Rule
{ name = "last <cycle> of <time>"
, pattern =
[ regex "последн(ий|юю|яя|его|ему)"
, dimension TimeGrain
, regex "в"
, dimension Time
]
, prod = \case
(_:Token TimeGrain grain:_:Token Time td:_) ->
tt $ cycleLastOf grain td
_ -> Nothing
}
ruleLastCycleOfTime2 :: Rule
ruleLastCycleOfTime2 = Rule
{ name = "last <cycle> of <time>"
, pattern =
[ regex "последн(ий|юю|яя|его|ему)"
, dimension TimeGrain
, dimension Time
]
, prod = \case
(_:Token TimeGrain grain:Token Time td:_) ->
tt $ cycleLastOf grain td
_ -> Nothing
}
ruleMonthDdddInterval :: Rule
ruleMonthDdddInterval = Rule
{ name = "<month> dd-dd (interval)"
, pattern =
[ regex "(?:с\\s+)?([012]?\\d|30|31)(го|\\.)?"
, regex "\\-|по|до"
, regex "([012]?\\d|30|31)(ое|\\.)?"
, Predicate isAMonth
]
, prod = \case
(Token RegexMatch (GroupMatch (m1:_)):
_:
Token RegexMatch (GroupMatch (m2:_)):
Token Time td:
_) -> do
v1 <- parseInt m1
v2 <- parseInt m2
from <- intersect (dayOfMonth v1) td
to <- intersect (dayOfMonth v2) td
Token Time <$> interval TTime.Closed from to
_ -> Nothing
}
ruleYearLatent2 :: Rule
ruleYearLatent2 = Rule
{ name = "year (latent)"
, pattern =
[ Predicate $ isIntegerBetween 2101 10000
]
, prod = \case
(token:_) -> do
v <- getIntValue token
tt . mkLatent $ year v
_ -> Nothing
}
ruleTimeAfterNext :: Rule
ruleTimeAfterNext = Rule
{ name = "<time> after next"
, pattern =
[ dimension Time
, regex "после следующ(ей|его)"
]
, prod = \case
(Token Time td:_:_) ->
tt $ predNth 1 True td
_ -> Nothing
}
ruleNoon :: Rule
ruleNoon = Rule
{ name = "noon"
, pattern =
[ regex "полдень"
]
, prod = \_ -> tt $ hour False 12
}
ruleThisnextDayofweek :: Rule
ruleThisnextDayofweek = Rule
{ name = "this|next <day-of-week>"
, pattern =
[ regex "следующ(ий|ая|ее)"
, Predicate isADayOfWeek
]
, prod = \case
(_:Token Time td:_) ->
tt $ predNth 0 True td
_ -> Nothing
}
ruleBetweenTimeofdayAndTimeofdayInterval :: Rule
ruleBetweenTimeofdayAndTimeofdayInterval = Rule
{ name = "between <time-of-day> and <time-of-day> (interval)"
, pattern =
[ regex "с"
, Predicate isATimeOfDay
, regex "по"
, Predicate isATimeOfDay
]
, prod = \case
(_:Token Time td1:_:Token Time td2:_) ->
Token Time <$> interval TTime.Closed td1 td2
_ -> Nothing
}
ruleNextCycle :: Rule
ruleNextCycle = Rule
{ name = "next <cycle>"
, pattern =
[ regex "(в |на )?следующ(ий|его|ему|им|ем|ие|их|ими)"
, dimension TimeGrain
]
, prod = \case
(_:Token TimeGrain grain:_) ->
tt $ cycleNth grain 1
_ -> Nothing
}
ruleOnDate :: Rule
ruleOnDate = Rule
{ name = "on <date>"
, pattern =
[ regex "в"
, dimension Time
]
, prod = \case
(_:x:_) -> Just x
_ -> Nothing
}
ruleLastCycle :: Rule
ruleLastCycle = Rule
{ name = "last <cycle>"
, pattern =
[ regex "(в )?прошл(ый|ого|ому|ым|ом|ые|ых|ыми)"
, dimension TimeGrain
]
, prod = \case
(_:Token TimeGrain grain:_) ->
tt . cycleNth grain $ - 1
_ -> Nothing
}
ruleLastCycle2 :: Rule
ruleLastCycle2 = Rule
{ name = "last <cycle>"
, pattern =
[ regex "(в )?прошедш(ий|его|ему|им|ем|их|ие|ими)"
, dimension TimeGrain
]
, prod = \case
(_:Token TimeGrain grain:_) ->
tt . cycleNth grain $ - 1
_ -> Nothing
}
ruleLunch :: Rule
ruleLunch = Rule
{ name = "lunch"
, pattern =
[ regex "(в )?обед"
]
, prod = \_ ->
let from = hour False 12
to = hour False 14
in Token Time . mkLatent . partOfDay <$>
interval TTime.Open from to
}
ruleAfternoon :: Rule
ruleAfternoon = Rule
{ name = "afternoon"
, pattern =
[ regex "дня|днем"
]
, prod = \_ ->
let from = hour False 12
to = hour False 19
in Token Time . mkLatent . partOfDay <$>
interval TTime.Open from to
}
ruleEvening :: Rule
ruleEvening = Rule
{ name = "evening"
, pattern =
[ regex "вечера|вечером|вечер"
]
, prod = \_ ->
let from = hour False 18
to = hour False 0
in Token Time . mkLatent . partOfDay <$>
interval TTime.Open from to
}
ruleNamedmonthDayofmonthOrdinal :: Rule
ruleNamedmonthDayofmonthOrdinal = Rule
{ name = "<named-month> <day-of-month> (ordinal)"
, pattern =
[ Predicate isAMonth
, Predicate isDOMOrdinal
]
, prod = \case
(Token Time td:token:_) -> Token Time <$> intersectDOM td token
_ -> Nothing
}
ruleHourofdayIntegerAsRelativeMinutes :: Rule
ruleHourofdayIntegerAsRelativeMinutes = Rule
{ name = "<hour-of-day> <integer> (as relative minutes)"
, pattern =
[ Predicate $ and . sequence [isNotLatent, isAnHourOfDay]
, Predicate $ isIntegerBetween 1 59
]
, prod = \case
(Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
token:
_) -> do
n <- getIntValue token
tt $ hourMinute is12H hours n
_ -> Nothing
}
ruleDayofmonthordinalNamedmonth :: Rule
ruleDayofmonthordinalNamedmonth = Rule
{ name = "<day-of-month>(ordinal) <named-month>"
, pattern =
[ Predicate isDOMOrdinal
, Predicate isAMonth
]
, prod = \case
(token:Token Time td:_) -> Token Time <$> intersectDOM td token
_ -> Nothing
}
ruleIntersectBy :: Rule
ruleIntersectBy = Rule
{ name = "intersect by ','"
, pattern =
[ Predicate isNotLatent
, regex ","
, Predicate isNotLatent
]
, prod = \case
(Token Time td1:_:Token Time td2:_) ->
Token Time <$> intersect td1 td2
_ -> Nothing
}
ruleNthTimeAfterTime :: Rule
ruleNthTimeAfterTime = Rule
{ name = "nth <time> after <time>"
, pattern =
[ dimension Ordinal
, dimension Time
, regex "после"
, dimension Time
]
, prod = \case
(Token Ordinal OrdinalData{TOrdinal.value = v}:
Token Time td1:
_:
Token Time td2:
_) -> tt $ predNthAfter (v - 1) td1 td2
_ -> Nothing
}
ruleMmdd :: Rule
ruleMmdd = Rule
{ name = "mm/dd"
, pattern =
[ regex "([012]?[1-9]|10|20|30|31)\\.(10|11|12|0?[1-9])\\.?"
]
, prod = \case
(Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do
d <- parseInt m1
m <- parseInt m2
tt $ monthDay m d
_ -> Nothing
}
ruleTimeofdayLatent :: Rule
ruleTimeofdayLatent = Rule
{ name = "time-of-day (latent)"
, pattern =
[ Predicate $ isIntegerBetween 0 23
]
, prod = \case
(token:_) -> do
n <- getIntValue token
tt . mkLatent $ hour (n < 12) n
_ -> Nothing
}
ruleDurationAgo :: Rule
ruleDurationAgo = Rule
{ name = "<duration> ago"
, pattern =
[ dimension Duration
, regex "назад"
]
, prod = \case
(Token Duration dd:_:_) ->
tt $ durationAgo dd
_ -> Nothing
}
ruleLastNCycle :: Rule
ruleLastNCycle = Rule
{ name = "last n <cycle>"
, pattern =
[ regex "последние"
, Predicate $ isIntegerBetween 1 9999
, dimension TimeGrain
]
, prod = \case
(_:token:Token TimeGrain grain:_) -> do
n <- getIntValue token
tt $ cycleN True grain (- n)
_ -> Nothing
}
ruleWithinDuration :: Rule
ruleWithinDuration = Rule
{ name = "within <duration>"
, pattern =
[ regex "в течение"
, dimension Duration
]
, prod = \case
(_:Token Duration dd:_) -> Token Time <$>
interval TTime.Open now (inDuration dd)
_ -> Nothing
}
ruleMidnighteodendOfDay :: Rule
ruleMidnighteodendOfDay = Rule
{ name = "midnight|EOD|end of day"
, pattern =
[ regex "кон(ец|ц(а|е)) дня"
]
, prod = \_ -> tt $ hour False 0
}
ruleDayofmonthNonOrdinalNamedmonth :: Rule
ruleDayofmonthNonOrdinalNamedmonth = Rule
{ name = "<day-of-month> (non ordinal) <named-month>"
, pattern =
[ Predicate isDOMInteger
, Predicate isAMonth
]
, prod = \case
(token:Token Time td:_) -> Token Time <$> intersectDOM td token
_ -> Nothing
}
ruleIntersect :: Rule
ruleIntersect = Rule
{ name = "intersect"
, pattern =
[ Predicate isNotLatent
, Predicate isNotLatent
]
, prod = \case
(Token Time td1:Token Time td2:_) ->
Token Time <$> intersect td1 td2
_ -> Nothing
}
ruleUntilTimeofday :: Rule
ruleUntilTimeofday = Rule
{ name = "until <time-of-day>"
, pattern =
[ regex "до"
, dimension Time
]
, prod = \case
(_:Token Time td:_) -> tt $ withDirection TTime.Before td
_ -> Nothing
}
ruleAtTimeofday :: Rule
ruleAtTimeofday = Rule
{ name = "at <time-of-day>"
, pattern =
[ regex "в"
, Predicate isATimeOfDay
]
, prod = \case
(_:Token Time td:_) -> tt $ notLatent td
_ -> Nothing
}
ruleNthTimeOfTime :: Rule
ruleNthTimeOfTime = Rule
{ name = "nth <time> of <time>"
, pattern =
[ dimension Ordinal
, dimension Time
, regex "в"
, dimension Time
]
, prod = \case
(Token Ordinal OrdinalData{TOrdinal.value = v}:
Token Time td1:
_:
Token Time td2:
_) -> Token Time . predNth (v - 1) False <$> intersect td2 td1
_ -> Nothing
}
ruleNthTimeOfTime2 :: Rule
ruleNthTimeOfTime2 = Rule
{ name = "nth <time> of <time>"
, pattern =
[ dimension Ordinal
, dimension Time
, dimension Time
]
, prod = \case
(Token Ordinal OrdinalData{TOrdinal.value = v}:
Token Time td1:
Token Time td2:
_) -> Token Time . predNth (v - 1) False <$> intersect td2 td1
_ -> Nothing
}
ruleTimePartofday :: Rule
ruleTimePartofday = Rule
{ name = "<time> <part-of-day>"
, pattern =
[ dimension Time
, Predicate isAPartOfDay
]
, prod = \case
(Token Time td1:Token Time td2:_) ->
Token Time <$> intersect td1 td2
_ -> Nothing
}
ruleWeek :: Rule
ruleWeek = Rule
{ name = "week"
, pattern =
[ regex "(эта )?неделя" -- regex "(all|rest of the|the|this) week"
]
, prod = \case
(Token RegexMatch (GroupMatch (m:_)):_) -> do
let end = cycleNthAfter True TG.Day (-2) $ cycleNth TG.Week 1
let match = Text.strip $ Text.toLower m
period <- case match of
"эта" -> interval TTime.Closed (cycleNth TG.Week 0) end
"rest of the" -> interval TTime.Open today end
-- no prefix, implicit 'the'
"неделя" -> interval TTime.Open today end
_ -> Nothing
let l = case match of { "неделя" -> mkLatent; _ -> id; }
Just $ Token Time $ l period
_ -> Nothing
}
ruleWeekend :: Rule
ruleWeekend = Rule
{ name = "week-end"
, pattern =
[ regex "выходные"
]
, prod = \_ -> tt $ mkOkForThisNext weekend
}
ruleOrdinalQuarterYear :: Rule
ruleOrdinalQuarterYear = Rule
{ name = "<ordinal> quarter <year>"
, pattern =
[ dimension Ordinal
, Predicate $ isGrain TG.Quarter
, dimension Time
]
, prod = \case
(Token Ordinal od:_:Token Time td:_) ->
tt $ cycleNthAfter False TG.Quarter (TOrdinal.value od - 1) td
_ -> Nothing
}
ruleYyyymmdd :: Rule
ruleYyyymmdd = Rule
{ name = "yyyy-mm-dd"
, pattern =
[ regex "(\\d{2,4})-(0?[1-9]|10|11|12)-([012]?[1-9]|10|20|30|31)"
]
, prod = \case
(Token RegexMatch (GroupMatch (m1:m2:m3:_)):_) -> do
y <- parseInt m1
m <- parseInt m2
d <- parseInt m3
tt $ yearMonthDay y m d
_ -> Nothing
}
ruleIntersectByOfFromS :: Rule
ruleIntersectByOfFromS = Rule
{ name = "intersect by 'of', 'from', 's"
, pattern =
[ Predicate isNotLatent
, regex "на"
, Predicate isNotLatent
]
, prod = \case
(Token Time td1:_:Token Time td2:_) ->
Token Time <$> intersect td1 td2
_ -> Nothing
}
ruleNextNCycle :: Rule
ruleNextNCycle = Rule
{ name = "next n <cycle>"
, pattern =
[ regex "следующие"
, Predicate $ isIntegerBetween 1 9999
, dimension TimeGrain
]
, prod = \case
(_:token:Token TimeGrain grain:_) -> do
v <- getIntValue token
tt $ cycleN True grain v
_ -> Nothing
}
ruleMorning :: Rule
ruleMorning = Rule
{ name = "morning"
, pattern =
[ regex "утро|утром|утра"
]
, prod = \_ ->
let from = hour False 3
to = hour False 12
in Token Time . mkLatent . partOfDay <$>
interval TTime.Open from to
}
ruleThisPartofday :: Rule
ruleThisPartofday = Rule
{ name = "this <part-of-day>"
, pattern =
[ regex "(в )?(это|эту|этот|этого|этому|эти)"
, Predicate isAPartOfDay
]
, prod = \case
(_:Token Time td:_) -> Token Time . partOfDay <$> intersect today td
_ -> Nothing
}
ruleThisCycle :: Rule
ruleThisCycle = Rule
{ name = "this <cycle>"
, pattern =
[ regex "(в )?(это|эту|этот|этого|этому|эти)"
, dimension TimeGrain
]
, prod = \case
(_:Token TimeGrain grain:_) ->
tt $ cycleNth grain 0
_ -> Nothing
}
ruleThisTime :: Rule
ruleThisTime = Rule
{ name = "this <time>"
, pattern =
[ regex "(в )?(это|эту|этот|этого|этому|эти)"
, Predicate isOkWithThisNext
]
, prod = \case
(_:Token Time td:_) ->
tt $ predNth 0 False td
_ -> Nothing
}
ruleYearLatent :: Rule
ruleYearLatent = Rule
{ name = "year (latent)"
, pattern =
[ Predicate $
or . sequence [isIntegerBetween (- 10000) 0, isIntegerBetween 25 999]
]
, prod = \case
(token:_) -> do
y <- getIntValue token
tt . mkLatent $ year y
_ -> Nothing
}
ruleAfterTimeofday :: Rule
ruleAfterTimeofday = Rule
{ name = "after <time-of-day>"
, pattern =
[ regex "после"
, dimension Time
]
, prod = \case
(_:Token Time td:_) -> tt $ withDirection TTime.After td
_ -> Nothing
}
ruleNight :: Rule
ruleNight = Rule
{ name = "night"
, pattern =
[ regex "ночь|ночи|ночью"
]
, prod = \_ ->
let from = hour False 0
to = hour False 4
in Token Time . mkLatent . partOfDay <$>
interval TTime.Open from to
}
ruleDayofmonthOrdinal :: Rule
ruleDayofmonthOrdinal = Rule
{ name = "<day-of-month> (ordinal)"
, pattern =
[ Predicate isDOMOrdinal
]
, prod = \case
(Token Ordinal OrdinalData{TOrdinal.value = v}:_) ->
tt $ dayOfMonth v
_ -> Nothing
}
ruleOrdinalCycleOfTime :: Rule
ruleOrdinalCycleOfTime = Rule
{ name = "<ordinal> <cycle> of <time>"
, pattern =
[ dimension Ordinal
, dimension TimeGrain
, regex "в"
, dimension Time
]
, prod = \case
(Token Ordinal od:Token TimeGrain grain:_:Token Time td:_) ->
tt $ cycleNthAfter True grain (TOrdinal.value od - 1) td
_ -> Nothing
}
ruleHhmm :: Rule
ruleHhmm = Rule
{ name = "hh:mm"
, pattern =
[ regex "((?:[01]?\\d)|(?:2[0-3]))[:.ч]([0-5]\\d)(?:час(ов|а|у)?|ч)?"
]
, prod = \case
(Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do
h <- parseInt m1
m <- parseInt m2
tt $ hourMinute False h m
_ -> Nothing
}
ruleYear :: Rule
ruleYear = Rule
{ name = "year"
, pattern =
[ Predicate $ isIntegerBetween 1000 2100
]
, prod = \case
(token:_) -> do
y <- getIntValue token
tt $ year y
_ -> Nothing
}
ruleNamedmonthDayofmonthNonOrdinal :: Rule
ruleNamedmonthDayofmonthNonOrdinal = Rule
{ name = "<named-month> <day-of-month> (non ordinal)"
, pattern =
[ Predicate isAMonth
, Predicate isDOMInteger
]
, prod = \case
(Token Time td:token:_) -> Token Time <$> intersectDOM td token
_ -> Nothing
}
ruleHhmmMilitary :: Rule
ruleHhmmMilitary = Rule
{ name = "hhmm (military)"
, pattern =
[ regex "((?:[01]?\\d)|(?:2[0-3]))([0-5]\\d)"
]
, prod = \case
(Token RegexMatch (GroupMatch (h:m:_)):_) -> do
hh <- parseInt h
mm <- parseInt m
tt . mkLatent $ hourMinute False hh mm
_ -> Nothing
}
ruleAbsorptionOfAfterNamedDay :: Rule
ruleAbsorptionOfAfterNamedDay = Rule
{ name = "absorption of , after named day"
, pattern =
[ Predicate isADayOfWeek
, regex ","
]
, prod = \case
(x:_) -> Just x
_ -> Nothing
}
ruleLastDayofweekOfTime :: Rule
ruleLastDayofweekOfTime = Rule
{ name = "last <day-of-week> of <time>"
, pattern =
[ regex "последний"
, Predicate isADayOfWeek
, regex "в"
, dimension Time
]
, prod = \case
(_:Token Time td1:_:Token Time td2:_) ->
tt $ predLastOf td1 td2
_ -> Nothing
}
ruleTimeofdayTimeofdayInterval :: Rule
ruleTimeofdayTimeofdayInterval = Rule
{ name = "<time-of-day> - <time-of-day> (interval)"
, pattern =
[ Predicate $ and . sequence [isNotLatent, isATimeOfDay]
, regex "\\-"
, Predicate isATimeOfDay
]
, prod = \case
(Token Time td1:_:Token Time td2:_) ->
Token Time <$> interval TTime.Closed td1 td2
_ -> Nothing
}
ruleTimeofdayTimeofdayInterval2 :: Rule
ruleTimeofdayTimeofdayInterval2 = Rule
{ name = "<time-of-day> - <time-of-day> (interval)"
, pattern =
[ Predicate isATimeOfDay
, regex "\\-|/"
, Predicate $ and . sequence [isNotLatent, isATimeOfDay]
]
, prod = \case
(Token Time td1:_:Token Time td2:_) ->
Token Time <$> interval TTime.Closed td1 td2
_ -> Nothing
}
ruleDurationAfterTime :: Rule
ruleDurationAfterTime = Rule
{ name = "<duration> after <time>"
, pattern =
[ dimension Duration
, regex "после"
, dimension Time
]
, prod = \case
(Token Duration dd:_:Token Time td:_) ->
tt $ durationAfter dd td
_ -> Nothing
}
ruleOrdinalQuarter :: Rule
ruleOrdinalQuarter = Rule
{ name = "<ordinal> quarter"
, pattern =
[ dimension Ordinal
, Predicate $ isGrain TG.Quarter
]
, prod = \case
(Token Ordinal OrdinalData{TOrdinal.value = v}:_) -> tt .
cycleNthAfter False TG.Quarter (v - 1) $ cycleNth TG.Year 0
_ -> Nothing
}
ruleDurationBeforeTime :: Rule
ruleDurationBeforeTime = Rule
{ name = "<duration> before <time>"
, pattern =
[ dimension Duration
, regex "перед"
, dimension Time
]
, prod = \case
(Token Duration dd:_:Token Time td:_) ->
tt $ durationBefore dd td
_ -> Nothing
}
rulePartofdayOfTime :: Rule
rulePartofdayOfTime = Rule
{ name = "<part-of-day> of <time>"
, pattern =
[ Predicate isAPartOfDay
, dimension Time
]
, prod = \case
(Token Time td1:Token Time td2:_) ->
Token Time <$> intersect td1 td2
_ -> Nothing
}
ruleMmddyyyy :: Rule
ruleMmddyyyy = Rule
{ name = "mm/dd/yyyy"
, pattern =
[ regex "([012]?[1-9]|10|20|30|31)\\.(0?[1-9]|10|11|12)\\.(\\d{2,4})"
]
, prod = \case
(Token RegexMatch (GroupMatch (m1:m2:m3:_)):_) -> do
y <- parseInt m3
m <- parseInt m2
d <- parseInt m1
tt $ yearMonthDay y m d
_ -> Nothing
}
ruleTimeofdayOclock :: Rule
ruleTimeofdayOclock = Rule
{ name = "<time-of-day> o'clock"
, pattern =
[ Predicate isATimeOfDay
, regex "час(у|а|ов)?|ч(?:[\\s'\"-_{}\\[\\]()]|$)"
]
, prod = \case
(Token Time td:_) ->
tt $ notLatent td
_ -> Nothing
}
ruleDayofmonthordinalNamedmonthYear :: Rule
ruleDayofmonthordinalNamedmonthYear = Rule
{ name = "<day-of-month>(ordinal) <named-month> year"
, pattern =
[ Predicate isDOMOrdinal
, Predicate isAMonth
, regex "(\\d{2,4})"
]
, prod = \case
(token:
Token Time td:
Token RegexMatch (GroupMatch (match:_)):
_) -> do
n <- parseInt match
dom <- intersectDOM td token
Token Time <$> intersect dom (year n)
_ -> Nothing
}
ruleTimezone :: Rule
ruleTimezone = Rule
{ name = "<time> timezone"
, pattern =
[ Predicate $ and . sequence [isNotLatent, isATimeOfDay]
, regex "\\b(YEKT|YEKST|YAKT|YAKST|WITA|WIT|WIB|WGT|WGST|WFT|WET|WEST|WAT|WAST|VUT|VLAT|VLAST|VET|UZT|UYT|UYST|UTC|ULAT|TVT|TMT|TLT|TKT|TJT|TFT|TAHT|SST|SRT|SGT|SCT|SBT|SAST|SAMT|RET|PYT|PYST|PWT|PST|PONT|PMST|PMDT|PKT|PHT|PHOT|PGT|PETT|PETST|PET|PDT|OMST|OMSST|NZST|NZDT|NUT|NST|NPT|NOVT|NOVST|NFT|NDT|NCT|MYT|MVT|MUT|MST|MSK|MSD|MMT|MHT|MDT|MAWT|MART|MAGT|MAGST|LINT|LHST|LHDT|KUYT|KST|KRAT|KRAST|KGT|JST|IST|IRST|IRKT|IRKST|IRDT|IOT|IDT|ICT|HOVT|HKT|GYT|GST|GMT|GILT|GFT|GET|GAMT|GALT|FNT|FKT|FKST|FJT|FJST|EST|EGT|EGST|EET|EEST|EDT|ECT|EAT|EAST|EASST|DAVT|ChST|CXT|CVT|CST|COT|CLT|CLST|CKT|CHAST|CHADT|CET|CEST|CDT|CCT|CAT|CAST|BTT|BST|BRT|BRST|BOT|BNT|AZT|AZST|AZOT|AZOST|AWST|AWDT|AST|ART|AQTT|ANAT|ANAST|AMT|AMST|ALMT|AKST|AKDT|AFT|AEST|AEDT|ADT|ACST|ACDT)\\b"
]
, prod = \case
(Token Time td:
Token RegexMatch (GroupMatch (tz:_)):
_) -> Token Time <$> inTimezone (Text.toUpper tz) td
_ -> Nothing
}
rules :: [Rule]
rules =
[ruleAbsorptionOfAfterNamedDay
, ruleAfterTimeofday
, ruleAfternoon
, ruleAtTimeofday
, ruleBetweenTimeofdayAndTimeofdayInterval
, ruleDatetimeDatetimeInterval
, ruleDateDateInterval
, ruleDayofmonthNonOrdinalNamedmonth
, ruleDayofmonthOrdinal
, ruleDayofmonthordinalNamedmonth
, ruleDayofmonthordinalNamedmonthYear
, ruleDurationAfterTime
, ruleDurationAgo
, ruleDurationBeforeTime
, ruleEvening
, ruleHhmm
, ruleHhmmMilitary
, ruleHourofdayIntegerAsRelativeMinutes
, ruleInDuration
, ruleIntersect
, ruleIntersectBy
, ruleIntersectByOfFromS
, ruleLastCycle
, ruleLastCycle2
, ruleLastCycleOfTime
, ruleLastCycleOfTime2
, ruleLastDayofweekOfTime
, ruleLastNCycle
, ruleLastTime
, ruleLunch
, ruleMidnighteodendOfDay
, ruleMmdd
, ruleMmddyyyy
, ruleMonthDdddInterval
, ruleMorning
, ruleNamedmonthDayofmonthNonOrdinal
, ruleNamedmonthDayofmonthOrdinal
, ruleNextCycle
, ruleNextNCycle
, ruleNight
, ruleNoon
, ruleNthTimeAfterTime
, ruleNthTimeOfTime
, ruleNthTimeOfTime2
, ruleOnDate
, ruleOrdinalCycleOfTime
, ruleOrdinalQuarter
, ruleOrdinalQuarterYear
, rulePartofdayOfTime
, ruleThisCycle
, ruleThisPartofday
, ruleThisTime
, ruleThisnextDayofweek
, ruleTimeAfterNext
, ruleTimePartofday
, ruleTimeofdayLatent
, ruleTimeofdayOclock
, ruleTimeofdayTimeofdayInterval
, ruleTimeofdayTimeofdayInterval2
, ruleUntilTimeofday
, ruleWeek
, ruleWeekend
, ruleWithinDuration
, ruleYear
, ruleYearLatent
, ruleYearLatent2
, ruleYyyymmdd
, ruleTimezone
]
++ ruleInstants
++ ruleDaysOfWeek
++ ruleMonths
++ ruleSeasons
++ ruleHolidays