-- 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 NoRebindableSyntax #-}
{-# LANGUAGE OverloadedStrings #-}

module Duckling.Time.DA.Rules
  ( rules
  ) where

import Data.Text (Text)
import Prelude

import Duckling.Dimensions.Types
import Duckling.Duration.Helpers (isGrain)
import Duckling.Numeral.Helpers (parseInt)
import Duckling.Ordinal.Types (OrdinalData (..))
import Duckling.Time.Helpers
import Duckling.Time.Types (TimeData (..))
import Duckling.Regex.Types
import Duckling.Types
import qualified Data.Text as Text
import qualified Duckling.Ordinal.Types as TOrdinal
import qualified Duckling.Time.Types as TTime
import qualified Duckling.TimeGrain.Types as TG

ruleDaysOfWeek :: [Rule]
ruleDaysOfWeek = mkRuleDaysOfWeek
  -- 'man' is a common Danish word ('you'), leading to false positives
  [ ( "Monday"   , "mandag"            )
  , ( "Tuesday"  , "tirsdag|tirs?\\.?" )
  , ( "Wednesday", "onsdag|ons\\.?"    )
  , ( "Thursday" , "torsdag|tors?\\.?" )
  , ( "Friday"   , "fredag|fre\\.?"    )
  , ( "Saturday" , "lÃ¸rdag|lÃ¸r\\.?"    )
  , ( "Sunday"   , "sÃ¸ndag|sÃ¸n\\.?"    )
  ]

ruleMonths :: [Rule]
ruleMonths = mkRuleMonths
  [ ( "January"  , "januar|jan\\.?"      )
  , ( "February" , "februar|feb\\.?"     )
  , ( "March"    , "marts|mar\\.?"       )
  , ( "April"    , "april|apr\\.?"       )
  , ( "May"      , "maj"                 )
  , ( "June"     , "juni|jun\\.?"        )
  , ( "July"     , "juli|jul\\.?"        )
  , ( "August"   , "august|aug\\.?"      )
  , ( "September", "september|sept?\\.?" )
  , ( "October"  , "oktober|okt\\.?"     )
  , ( "November" , "november|nov\\.?"    )
  , ( "December" , "december|dec\\.?"    )
  ]

ruleTheDayAfterTomorrow :: Rule
ruleTheDayAfterTomorrow = Rule
  { name = "the day after tomorrow"
  , pattern =
    [ regex "i overmorgen"
    ]
  , prod = \_ -> tt $ cycleNth TG.Day 2
  }

ruleRelativeMinutesTotillbeforeIntegerHourofday :: Rule
ruleRelativeMinutesTotillbeforeIntegerHourofday = Rule
  { name = "relative minutes to|till|before <integer> (hour-of-day)"
  , pattern =
    [ Predicate $ isIntegerBetween 1 59
    , regex "i"
    , Predicate isAnHourOfDay
    ]
  , prod = \tokens -> case tokens of
      (token:_:Token Time td:_) -> do
        n <- getIntValue token
        Token Time <$> minutesBefore n td
      _ -> Nothing
  }

ruleQuarterTotillbeforeIntegerHourofday :: Rule
ruleQuarterTotillbeforeIntegerHourofday = Rule
  { name = "quarter to|till|before <integer> (hour-of-day)"
  , pattern =
    [ regex "(et|Ã©t)? ?kvart(er)? i"
    , Predicate isAnHourOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> Token Time <$> minutesBefore 15 td
      _ -> Nothing
  }

ruleHalfTotillbeforeIntegerHourofday :: Rule
ruleHalfTotillbeforeIntegerHourofday = Rule
  { name = "half to|till|before <integer> (hour-of-day)"
  , pattern =
    [ regex "halv time i"
    , Predicate isAnHourOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> Token Time <$> minutesBefore 30 td
      _ -> Nothing
  }

ruleConstitutionDay :: Rule
ruleConstitutionDay = Rule
  { name = "constitution day"
  , pattern =
    [ regex "grundlov'?s?'? dag"
    ]
  , prod = \_ -> tt $ monthDay 6 5
  }

ruleValentinesDay :: Rule
ruleValentinesDay = Rule
  { name = "valentine's day"
  , pattern =
    [ regex "valentine'?s?( dag)?"
    ]
  , prod = \_ -> tt $ monthDay 2 14
  }

ruleTheOrdinalCycleOfTime :: Rule
ruleTheOrdinalCycleOfTime = Rule
  { name = "the <ordinal> <cycle> of <time>"
  , pattern =
    [ regex "den"
    , dimension Ordinal
    , dimension TimeGrain
    , regex "af|i|fra"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Ordinal od:Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter True grain (TOrdinal.value od - 1) td
      _ -> Nothing
  }

ruleNthTimeOfTime2 :: Rule
ruleNthTimeOfTime2 = Rule
  { name = "nth <time> of <time>"
  , pattern =
    [ regex "den"
    , dimension Ordinal
    , dimension Time
    , regex "af|i"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:
       Token Ordinal OrdinalData{TOrdinal.value = v}:
       Token Time td1:
       _:
       Token Time td2:
       _) -> Token Time . predNth (v - 1) False <$> intersect td2 td1
      _ -> Nothing
  }

ruleNewYearsDay :: Rule
ruleNewYearsDay = Rule
  { name = "new year's day"
  , pattern =
    [ regex "nytÃ¥rsdag"
    ]
  , prod = \_ -> tt $ monthDay 1 1
  }

ruleLastTime :: Rule
ruleLastTime = Rule
  { name = "last <time>"
  , pattern =
    [ regex "(sidste|seneste)"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ predNth (-1) False td
      _ -> Nothing
  }

ruleDatetimeDatetimeInterval :: Rule
ruleDatetimeDatetimeInterval = Rule
  { name = "<datetime> - <datetime> (interval)"
  , pattern =
    [ Predicate isNotLatent
    , regex "\\-|til|indtil"
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleEvening :: Rule
ruleEvening = Rule
  { name = "evening"
  , pattern =
    [ regex "afte(s|n(en)?)"
    ]
  , prod = \_ ->
      let from = hour False 18
          to = hour False 0
      in Token Time . mkLatent . partOfDay <$>
           interval TTime.Open from to
  }

ruleTheDayofmonthNonOrdinal :: Rule
ruleTheDayofmonthNonOrdinal = Rule
  { name = "the <day-of-month> (non ordinal)"
  , pattern =
    [ regex "den"
    , Predicate $ isIntegerBetween 1 31
    ]
  , prod = \tokens -> case tokens of
      (_:token:_) -> do
        n <- getIntValue token
        tt $ dayOfMonth n
      _ -> Nothing
  }

ruleCycleAfterTime :: Rule
ruleCycleAfterTime = Rule
  { name = "<cycle> after <time>"
  , pattern =
    [ dimension TimeGrain
    , regex "efter"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter False grain 1 td
      _ -> Nothing
  }

ruleInDuration :: Rule
ruleInDuration = Rule
  { name = "in <duration>"
  , pattern =
    [ regex "om"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_) ->
        tt $ inDuration dd
      _ -> Nothing
  }

ruleNow :: Rule
ruleNow = Rule
  { name = "now"
  , pattern =
    [ regex "lige nu|nu|(i )?dette Ã¸jeblik"
    ]
  , prod = \_ -> tt now
  }

ruleLastCycleOfTime :: Rule
ruleLastCycleOfTime = Rule
  { name = "last <cycle> of <time>"
  , pattern =
    [ regex "sidste"
    , dimension TimeGrain
    , regex "af|i"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleLastOf grain td
      _ -> Nothing
  }

ruleFromDatetimeDatetimeInterval :: Rule
ruleFromDatetimeDatetimeInterval = Rule
  { name = "from <datetime> - <datetime> (interval)"
  , pattern =
    [ regex "fra"
    , dimension Time
    , regex "\\-|til|indtil"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleRelativeMinutesAfterpastIntegerHourofday :: Rule
ruleRelativeMinutesAfterpastIntegerHourofday = Rule
  { name = "relative minutes after|past <integer> (hour-of-day)"
  , pattern =
    [ Predicate $ isIntegerBetween 1 59
    , regex "over"
    , Predicate isAnHourOfDay
    ]
  , prod = \tokens -> case tokens of
      (token:
       _:
       Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       _) -> do
        n <- getIntValue token
        tt $ hourMinute is12H hours n
      _ -> Nothing
  }

ruleQuarterAfterpastIntegerHourofday :: Rule
ruleQuarterAfterpastIntegerHourofday = Rule
  { name = "quarter after|past <integer> (hour-of-day)"
  , pattern =
    [ regex "(et|Ã©t)? ?kvart(er)? over"
    , Predicate isAnHourOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:
       Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       _) -> tt $ hourMinute is12H hours 15
      _ -> Nothing
  }

ruleHalfAfterpastIntegerHourofday :: Rule
ruleHalfAfterpastIntegerHourofday = Rule
  { name = "half after|past <integer> (hour-of-day)"
  , pattern =
    [ regex "halv time over"
    , Predicate isAnHourOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:
       Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       _) -> tt $ hourMinute is12H hours 30
      _ -> Nothing
  }

ruleMonthDdddInterval :: Rule
ruleMonthDdddInterval = Rule
  { name = "<month> dd-dd (interval)"
  , pattern =
    [ regex "([012]?\\d|30|31)(ter|\\.)?"
    , regex "\\-|til"
    , regex "([012]?\\d|30|31)(ter|\\.)?"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:_)):
       _:
       Token RegexMatch (GroupMatch (m2:_)):
       Token Time td:
       _) -> do
        v1 <- parseInt m1
        v2 <- parseInt m2
        from <- intersect td (dayOfMonth v1)
        to <- intersect td (dayOfMonth v2)
        Token Time <$> interval TTime.Closed from to
      _ -> Nothing
  }

ruleTheCycleAfterTime :: Rule
ruleTheCycleAfterTime = Rule
  { name = "the <cycle> after <time>"
  , pattern =
    [ dimension TimeGrain
    , regex "(en|tet|et)? efter"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter False grain 1 td
      _ -> Nothing
  }

ruleTheCycleBeforeTime :: Rule
ruleTheCycleBeforeTime = Rule
  { name = "the <cycle> before <time>"
  , pattern =
    [ dimension TimeGrain
    , regex "(en|tet|et)? fÃ¸r"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter False grain (-1) td
      _ -> Nothing
  }

ruleSeason4 :: Rule
ruleSeason4 = Rule
  { name = "season"
  , pattern =
    [ regex "forÃ¥r"
    ]
  , prod = \_ -> Token Time <$>
      interval TTime.Open (monthDay 3 20) (monthDay 6 21)
  }

ruleYearLatent2 :: Rule
ruleYearLatent2 = Rule
  { name = "year (latent)"
  , pattern =
    [ Predicate $ isIntegerBetween 2101 10000
    ]
  , prod = \tokens -> case tokens of
      (token:_) -> do
        v <- getIntValue token
        tt . mkLatent $ year v
      _ -> Nothing
  }

ruleTimeAfterNext :: Rule
ruleTimeAfterNext = Rule
  { name = "<time> after next"
  , pattern =
    [ regex "n(Ã¦)ste"
    , dimension Time
    , regex "igen"
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ predNth 1 True td
      _ -> Nothing
  }

ruleTheIdesOfNamedmonth :: Rule
ruleTheIdesOfNamedmonth = Rule
  { name = "the ides of <named-month>"
  , pattern =
    [ regex "midten af"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td@TimeData {TTime.form = Just (TTime.Month m)}:_) ->
        Token Time <$>
          intersect td (dayOfMonth $ if elem m [3, 5, 7, 10] then 15 else 13)
      _ -> Nothing
  }

ruleNoon :: Rule
ruleNoon = Rule
  { name = "noon"
  , pattern =
    [ regex "middag|(kl(\\.|okken)?)? tolv"
    ]
  , prod = \_ -> tt $ hour False 12
  }

ruleToday :: Rule
ruleToday = Rule
  { name = "today"
  , pattern =
    [ regex "i dag|idag"
    ]
  , prod = \_ -> tt today
  }

ruleThisnextDayofweek :: Rule
ruleThisnextDayofweek = Rule
  { name = "this|next <day-of-week>"
  , pattern =
    [ regex "(kommende|n(Ã¦)ste)"
    , Predicate isADayOfWeek
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ predNth 0 True td
      _ -> Nothing
  }

ruleTheDayBeforeYesterday :: Rule
ruleTheDayBeforeYesterday = Rule
  { name = "the day before yesterday"
  , pattern =
    [ regex "i forgÃ¥rs"
    ]
  , prod = \_ -> tt . cycleNth TG.Day $ - 2
  }

ruleBetweenTimeofdayAndTimeofdayInterval :: Rule
ruleBetweenTimeofdayAndTimeofdayInterval = Rule
  { name = "between <time-of-day> and <time-of-day> (interval)"
  , pattern =
    [ regex "mellem"
    , Predicate isATimeOfDay
    , regex "og"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleNextCycle :: Rule
ruleNextCycle = Rule
  { name = "next <cycle>"
  , pattern =
    [ regex "n(Ã¦)ste|kommende"
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_) ->
        tt $ cycleNth grain 1
      _ -> Nothing
  }

ruleTheCycleOfTime :: Rule
ruleTheCycleOfTime = Rule
  { name = "the <cycle> of <time>"
  , pattern =
    [ dimension TimeGrain
    , regex "(en|tet|et)? af"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter True grain 0 td
      _ -> Nothing
  }

ruleTimeofdayApproximately :: Rule
ruleTimeofdayApproximately = Rule
  { name = "<time-of-day> approximately"
  , pattern =
    [ Predicate isATimeOfDay
    , regex "(cirka|ca\\.|-?ish)"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleOnDate :: Rule
ruleOnDate = Rule
  { name = "on <date>"
  , pattern =
    [ regex "den|pÃ¥"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:x:_) -> Just x
      _ -> Nothing
  }

ruleDurationFromNow :: Rule
ruleDurationFromNow = Rule
  { name = "<duration> from now"
  , pattern =
    [ dimension Duration
    , regex "fra (i dag|nu)"
    ]
  , prod = \tokens -> case tokens of
      (Token Duration dd:_) -> tt $ inDuration dd
      _ -> Nothing
  }

ruleLunch :: Rule
ruleLunch = Rule
  { name = "lunch"
  , pattern =
    [ regex "(til )?middag"
    ]
  , prod = \_ ->
      let from = hour False 12
          to = hour False 14
      in Token Time . mkLatent . partOfDay <$>
           interval TTime.Open from to
  }

ruleLastCycle :: Rule
ruleLastCycle = Rule
  { name = "last <cycle>"
  , pattern =
    [ regex "sidste|seneste"
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_) -> tt . cycleNth grain $ - 1
      _ -> Nothing
  }

ruleDdmm :: Rule
ruleDdmm = Rule
  { name = "dd/mm"
  , pattern =
    [ regex "(3[01]|[12]\\d|0?[1-9])[\\/-](0?[1-9]|1[0-2])"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:m2:_)):_) -> do
        m <- parseInt m2
        d <- parseInt m1
        tt $ monthDay m d
      _ -> Nothing
  }

ruleAfternoon :: Rule
ruleAfternoon = Rule
  { name = "afternoon"
  , pattern =
    [ regex "eftermiddag(en)?"
    ]
  , prod = \_ ->
      let from = hour False 12
          to = hour False 19
      in Token Time . mkLatent . partOfDay <$>
           interval TTime.Open from to
  }

ruleTimeBeforeLast :: Rule
ruleTimeBeforeLast = Rule
  { name = "<time> before last"
  , pattern =
    [ regex "sidste"
    , dimension Time
    , regex "igen"
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ predNth (-2) False td
      _ -> Nothing
  }

ruleNamedmonthDayofmonthOrdinal :: Rule
ruleNamedmonthDayofmonthOrdinal = Rule
  { name = "<named-month> <day-of-month> (ordinal)"
  , pattern =
    [ Predicate isAMonth
    , Predicate isDOMOrdinal
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:token:_) -> Token Time <$> intersectDOM td token
      _ -> Nothing
  }

ruleChristmasEve :: Rule
ruleChristmasEve = Rule
  { name = "christmas eve"
  , pattern =
    [ regex "juleaften(sdag)?"
    ]
  , prod = \_ -> tt $ monthDay 12 24
  }

ruleInduringThePartofday :: Rule
ruleInduringThePartofday = Rule
  { name = "in|during the <part-of-day>"
  , pattern =
    [ regex "om|i"
    , Predicate isAPartOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ notLatent td
      _ -> Nothing
  }

ruleHourofdayIntegerAsRelativeMinutes :: Rule
ruleHourofdayIntegerAsRelativeMinutes = Rule
  { name = "<hour-of-day> <integer> (as relative minutes)"
  , pattern =
    [ Predicate $ and . sequence [isNotLatent, isAnHourOfDay]
    , Predicate $ isIntegerBetween 1 59
    ]
  , prod = \tokens -> case tokens of
      (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       token:
       _) -> do
        n <- getIntValue token
        tt $ hourMinute is12H hours n
      _ -> Nothing
  }

ruleHourofdayQuart :: Rule
ruleHourofdayQuart = Rule
  { name = "<hour-of-day> quarter (as relative minutes)"
  , pattern =
    [ Predicate isAnHourOfDay
    , regex "(et|Ã©t)? ?kvart(er)?"
    ]
  , prod = \tokens -> case tokens of
      (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       _) -> tt $ hourMinute is12H hours 15
      _ -> Nothing
  }

ruleHourofdayHalf :: Rule
ruleHourofdayHalf = Rule
  { name = "<hour-of-day> half (as relative minutes)"
  , pattern =
    [ Predicate isAnHourOfDay
    , regex "halv time"
    ]
  , prod = \tokens -> case tokens of
      (Token Time TimeData {TTime.form = Just (TTime.TimeOfDay (Just hours) is12H)}:
       _) -> tt $ hourMinute is12H hours 30
      _ -> Nothing
  }

ruleDayofmonthordinalNamedmonth :: Rule
ruleDayofmonthordinalNamedmonth = Rule
  { name = "<day-of-month>(ordinal) <named-month>"
  , pattern =
    [ Predicate isDOMOrdinal
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (token:Token Time td:_) -> Token Time <$> intersectDOM td token
      _ -> Nothing
  }

ruleIntersectBy :: Rule
ruleIntersectBy = Rule
  { name = "intersect by \",\""
  , pattern =
    [ Predicate isNotLatent
    , regex ","
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (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 "efter"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Ordinal OrdinalData{TOrdinal.value = v}:
       Token Time td1:
       _:
       Token Time td2:
       _) -> tt $ predNthAfter (v - 1) td1 td2
      _ -> Nothing
  }

ruleAfterDuration :: Rule
ruleAfterDuration = Rule
  { name = "after <duration>"
  , pattern =
    [ regex "efter"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_) ->
        tt . withDirection TTime.After $ inDuration dd
      _ -> Nothing
  }

ruleTimeofdayLatent :: Rule
ruleTimeofdayLatent = Rule
  { name = "time-of-day (latent)"
  , pattern =
    [ Predicate $ isIntegerBetween 0 23
    ]
  , prod = \tokens -> case tokens of
      (token:_) -> do
        v <- getIntValue token
        tt . mkLatent $ hour False v
      _ -> Nothing
  }

ruleDayofmonthOrdinalOfNamedmonth :: Rule
ruleDayofmonthOrdinalOfNamedmonth = Rule
  { name = "<day-of-month> (ordinal) of <named-month>"
  , pattern =
    [ Predicate isDOMOrdinal
    , regex "af|i"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (token:_:Token Time td:_) -> Token Time <$> intersectDOM td token
      _ -> Nothing
  }

ruleFromTimeofdayTimeofdayInterval :: Rule
ruleFromTimeofdayTimeofdayInterval = Rule
  { name = "from <time-of-day> - <time-of-day> (interval)"
  , pattern =
    [ regex "(efter|fra)"
    , Predicate isATimeOfDay
    , regex "((men )?fÃ¸r)|\\-|til|indtil"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleExactlyTimeofday :: Rule
ruleExactlyTimeofday = Rule
  { name = "exactly <time-of-day>"
  , pattern =
    [ regex "pr(Ã¦)cis( klokken| kl\\.?)?"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleInduringThePartofday2 :: Rule
ruleInduringThePartofday2 = Rule
  { name = "in|during the <part-of-day>"
  , pattern =
    [ regex "om|i"
    , Predicate isAPartOfDay
    , regex "en|ten"
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ notLatent td
      _ -> Nothing
  }

ruleSeason3 :: Rule
ruleSeason3 = Rule
  { name = "season"
  , pattern =
    [ regex "vinter"
    ]
  , prod = \_ ->
      let from = monthDay 12 21
          to = monthDay 3 20
      in Token Time <$> interval TTime.Open from to
  }

ruleSeason :: Rule
ruleSeason = Rule
  { name = "season"
  , pattern =
    [ regex "sommer"
    ]
  , prod = \_ ->
      let from = monthDay 6 21
          to = monthDay 9 23
      in Token Time <$> interval TTime.Open from to
  }

ruleBetweenDatetimeAndDatetimeInterval :: Rule
ruleBetweenDatetimeAndDatetimeInterval = Rule
  { name = "between <datetime> and <datetime> (interval)"
  , pattern =
    [ regex "mellem"
    , dimension Time
    , regex "og"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_) ->
        Token Time <$> interval TTime.Closed td1 td2
      _ -> Nothing
  }

ruleNewYearsEve :: Rule
ruleNewYearsEve = Rule
  { name = "new year's eve"
  , pattern =
    [ regex "nytÃ¥rsaften(sdag)?"
    ]
  , prod = \_ -> tt $ monthDay 12 31
  }

ruleDurationAgo :: Rule
ruleDurationAgo = Rule
  { name = "<duration> ago"
  , pattern =
    [ dimension Duration
    , regex "siden"
    ]
  , prod = \tokens -> case tokens of
      (Token Duration dd:_) ->
        tt $ durationAgo dd
      _ -> Nothing
  }

ruleByTheEndOfTime :: Rule
ruleByTheEndOfTime = Rule
  { name = "by the end of <time>"
  , pattern =
    [ regex "i slutningen af"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> Token Time <$> interval TTime.Closed now td
      _ -> Nothing
  }

ruleAfterWork :: Rule
ruleAfterWork = Rule
  { name = "after work"
  , pattern =
    [ regex "efter arbejde"
    ]
  , prod = \_ -> do
      td2 <- interval TTime.Open (hour False 17) (hour False 21)
      Token Time . partOfDay <$> intersect today td2
  }

ruleLastNCycle :: Rule
ruleLastNCycle = Rule
  { name = "last n <cycle>"
  , pattern =
    [ regex "sidste|seneste"
    , Predicate $ isIntegerBetween 1 9999
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (_:token:Token TimeGrain grain:_) -> do
        n <- getIntValue token
        tt $ cycleN True grain (- n)
      _ -> Nothing
  }

ruleTimeofdaySharp :: Rule
ruleTimeofdaySharp = Rule
  { name = "<time-of-day> sharp"
  , pattern =
    [ Predicate isATimeOfDay
    , regex "(sharp|pr(Ã¦)cis)"
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleWithinDuration :: Rule
ruleWithinDuration = Rule
  { name = "within <duration>"
  , pattern =
    [ regex "indenfor"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_) -> Token Time <$>
        interval TTime.Open now (inDuration dd)
      _ -> Nothing
  }

ruleMidnighteodendOfDay :: Rule
ruleMidnighteodendOfDay = Rule
  { name = "midnight|EOD|end of day"
  , pattern =
    [ regex "midnat|EOD"
    ]
  , prod = \_ -> tt $ hour False 0
  }

ruleDayofmonthNonOrdinalNamedmonth :: Rule
ruleDayofmonthNonOrdinalNamedmonth = Rule
  { name = "<day-of-month> (non ordinal) <named-month>"
  , pattern =
    [ Predicate isDOMInteger
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (token:Token Time td:_) -> Token Time <$> intersectDOM td token
      _ -> Nothing
  }

ruleIntersect :: Rule
ruleIntersect = Rule
  { name = "intersect"
  , pattern =
    [ Predicate isNotLatent
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleAboutTimeofday :: Rule
ruleAboutTimeofday = Rule
  { name = "about <time-of-day>"
  , pattern =
    [ regex "(omkring|cirka|ca\\.)( klokken| kl\\.?)?"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleUntilTimeofday :: Rule
ruleUntilTimeofday = Rule
  { name = "until <time-of-day>"
  , pattern =
    [ regex "(engang )?inden|indtil|fÃ¸r|op til"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ withDirection TTime.Before td
      _ -> Nothing
  }

ruleAtTimeofday :: Rule
ruleAtTimeofday = Rule
  { name = "at <time-of-day>"
  , pattern =
    [ regex "klokken|kl\\.?|@"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> tt $ notLatent td
      _ -> Nothing
  }

ruleNthTimeOfTime :: Rule
ruleNthTimeOfTime = Rule
  { name = "nth <time> of <time>"
  , pattern =
    [ dimension Ordinal
    , dimension Time
    , regex "af|i"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (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 = \tokens -> case tokens of
      (Token Time td1:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleWeekend :: Rule
ruleWeekend = Rule
  { name = "week-end"
  , pattern =
    [ regex "(week(\\s|-)?end)(en)?"
    ]
  , prod = \_ -> tt weekend
  }

ruleAboutDuration :: Rule
ruleAboutDuration = Rule
  { name = "about <duration>"
  , pattern =
    [ regex "(omkring|cirka|ca.)"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_) -> Just . Token Duration $ dd
      _ -> Nothing
  }

ruleEomendOfMonth :: Rule
ruleEomendOfMonth = Rule
  { name = "EOM|End of month"
  , pattern =
    [ regex "EOM"
    ]
  , prod = \_ -> tt $ cycleNth TG.Month 1
  }

ruleNthTimeAfterTime2 :: Rule
ruleNthTimeAfterTime2 = Rule
  { name = "nth <time> after <time>"
  , pattern =
    [ regex "den"
    , dimension Ordinal
    , dimension Time
    , regex "efter"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:
       Token Ordinal OrdinalData{TOrdinal.value = v}:
       Token Time td1:
       _:
       Token Time td2:
       _) -> tt $ predNthAfter (v - 1) td1 td2
      _ -> Nothing
  }

ruleNextTime :: Rule
ruleNextTime = Rule
  { name = "next <time>"
  , pattern =
    [ regex "n(Ã¦)ste|kommende"
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ predNth 0 True td
      _ -> Nothing
  }

ruleOrdinalQuarterYear :: Rule
ruleOrdinalQuarterYear = Rule
  { name = "<ordinal> quarter <year>"
  , pattern =
    [ dimension Ordinal
    , Predicate $ isGrain TG.Quarter
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (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]|1[0-2])-(3[01]|[12]\\d|0?[1-9])"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:m2:m3:_)):_) -> do
        y <- parseInt m1
        m <- parseInt m2
        d <- parseInt m3
        tt $ yearMonthDay y m d
      _ -> Nothing
  }

ruleTheOrdinalCycleAfterTime :: Rule
ruleTheOrdinalCycleAfterTime = Rule
  { name = "the <ordinal> <cycle> after <time>"
  , pattern =
    [ regex "den"
    , dimension Ordinal
    , dimension TimeGrain
    , regex "efter"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Ordinal od:Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter True grain (TOrdinal.value od - 1) td
      _ -> Nothing
  }

ruleIntersectByOfFromS :: Rule
ruleIntersectByOfFromS = Rule
  { name = "intersect by \"of\", \"from\", \"'s\""
  , pattern =
    [ Predicate isNotLatent
    , regex "i"
    , Predicate isNotLatent
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleNextNCycle :: Rule
ruleNextNCycle = Rule
  { name = "next n <cycle>"
  , pattern =
    [ regex "n(Ã¦)ste"
    , Predicate $ isIntegerBetween 1 9999
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (_:token:Token TimeGrain grain:_) -> do
        n <- getIntValue token
        tt $ cycleN True grain n
      _ -> Nothing
  }

ruleADuration :: Rule
ruleADuration = Rule
  { name = "a <duration>"
  , pattern =
    [ regex "(om )?en|et|Ã©n|Ã©t"
    , dimension Duration
    ]
  , prod = \tokens -> case tokens of
      (_:Token Duration dd:_) ->
        tt $ inDuration dd
      _ -> Nothing
  }

ruleMorning :: Rule
ruleMorning = Rule
  { name = "morning"
  , pattern =
    [ regex "morgen(en)?"
    ]
  , prod = \_ ->
      let from = hour False 4
          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 "i|denne"
    , Predicate isAPartOfDay
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) -> Token Time . partOfDay <$> intersect today td
      _ -> Nothing
  }

ruleThisCycle :: Rule
ruleThisCycle = Rule
  { name = "this <cycle>"
  , pattern =
    [ regex "denne|dette|i|nuv(Ã¦)rende|indev(Ã¦)rende"
    , dimension TimeGrain
    ]
  , prod = \tokens -> case tokens of
      (_:Token TimeGrain grain:_) ->
        tt $ cycleNth grain 0
      _ -> Nothing
  }

ruleThisTime :: Rule
ruleThisTime = Rule
  { name = "this <time>"
  , pattern =
    [ regex "(denne|dette|i|den her)"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ predNth 0 False td
      _ -> Nothing
  }

ruleDurationHence :: Rule
ruleDurationHence = Rule
  { name = "<duration> hence"
  , pattern =
    [ dimension Duration
    , regex "hence"
    ]
  , prod = \tokens -> case tokens of
      (Token Duration dd:_) ->
        tt $ inDuration dd
      _ -> Nothing
  }

ruleDayofmonthNonOrdinalOfNamedmonth :: Rule
ruleDayofmonthNonOrdinalOfNamedmonth = Rule
  { name = "<day-of-month> (non ordinal) of <named-month>"
  , pattern =
    [ Predicate isDOMInteger
    , regex "af|i"
    , Predicate isAMonth
    ]
  , prod = \tokens -> case tokens of
      (token:_:Token Time td:_) -> Token Time <$> intersectDOM td token
      _ -> Nothing
  }

ruleAfterLunch :: Rule
ruleAfterLunch = Rule
  { name = "after lunch"
  , pattern =
    [ regex "efter (frokost|middag)"
    ]
  , prod = \_ -> do
      td2 <- interval TTime.Open (hour False 13) (hour False 17)
      Token Time . partOfDay <$> intersect today td2
  }

ruleOnANamedday :: Rule
ruleOnANamedday = Rule
  { name = "on a named-day"
  , pattern =
    [ regex "pÃ¥ en"
    , Predicate isADayOfWeek
    ]
  , prod = \tokens -> case tokens of
      (_:x:_) -> Just x
      _ -> Nothing
  }

ruleYearLatent :: Rule
ruleYearLatent = Rule
  { name = "year (latent)"
  , pattern =
    [ Predicate $ isIntegerBetween 1 999
    ]
  , prod = \tokens -> case tokens of
      (token:_) -> do
        y <- getIntValue token
        tt . mkLatent $ year y
      _ -> Nothing
  }

ruleYesterday :: Rule
ruleYesterday = Rule
  { name = "yesterday"
  , pattern =
    [ regex "i gÃ¥r|igÃ¥r"
    ]
  , prod = \_ -> tt . cycleNth TG.Day $ - 1
  }

ruleSeason2 :: Rule
ruleSeason2 = Rule
  { name = "season"
  , pattern =
    [ regex "efterÃ¥r"
    ]
  , prod = \_ ->
      let from = monthDay 9 23
          to = monthDay 12 21
      in Token Time <$> interval TTime.Open from to
  }

ruleAfterTimeofday :: Rule
ruleAfterTimeofday = Rule
  { name = "after <time-of-day>"
  , pattern =
    [ regex "(engang )?efter"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td:_) ->
        tt $ withDirection TTime.After td
      _ -> Nothing
  }

ruleChristmas :: Rule
ruleChristmas = Rule
  { name = "christmas"
  , pattern =
    [ regex "((1\\.?)|fÃ¸rste)? ?juledag"
    ]
  , prod = \_ -> tt $ monthDay 12 25
  }

ruleNight :: Rule
ruleNight = Rule
  { name = "night"
  , pattern =
    [ regex "nat(ten)?"
    ]
  , 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 = \tokens -> case tokens of
      (Token Ordinal OrdinalData{TOrdinal.value = v}:_) ->
        tt . mkLatent $ dayOfMonth v
      _ -> Nothing
  }

ruleOrdinalCycleAfterTime :: Rule
ruleOrdinalCycleAfterTime = Rule
  { name = "<ordinal> <cycle> after <time>"
  , pattern =
    [ dimension Ordinal
    , dimension TimeGrain
    , regex "efter"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Ordinal od:Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter True grain (TOrdinal.value od - 1) td
      _ -> Nothing
  }

ruleOrdinalCycleOfTime :: Rule
ruleOrdinalCycleOfTime = Rule
  { name = "<ordinal> <cycle> of <time>"
  , pattern =
    [ dimension Ordinal
    , dimension TimeGrain
    , regex "af|i|fra"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (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 = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (hh:mm:_)):_) -> do
        h <- parseInt hh
        m <- parseInt mm
        tt $ hourMinute False h m
      _ -> Nothing
  }

ruleTonight :: Rule
ruleTonight = Rule
  { name = "tonight"
  , pattern =
    [ regex "i aften"
    ]
  , prod = \_ -> do
      td2 <- interval TTime.Open (hour False 18) (hour False 0)
      Token Time . partOfDay <$> intersect today td2
  }

ruleYear :: Rule
ruleYear = Rule
  { name = "year"
  , pattern =
    [ Predicate $ isIntegerBetween 1000 2100
    ]
  , prod = \tokens -> case tokens of
      (token:_) -> do
        y <- getIntValue token
        tt $ year y
      _ -> Nothing
  }

ruleHalloweenDay :: Rule
ruleHalloweenDay = Rule
  { name = "halloween day"
  , pattern =
    [ regex "hall?owe?en"
    ]
  , prod = \_ -> tt $ monthDay 10 31
  }

ruleNamedmonthDayofmonthNonOrdinal :: Rule
ruleNamedmonthDayofmonthNonOrdinal = Rule
  { name = "<named-month> <day-of-month> (non ordinal)"
  , pattern =
    [ Predicate isAMonth
    , Predicate isDOMInteger
    ]
  , prod = \tokens -> case tokens of
      (Token Time td:token:_) -> Token Time <$> intersectDOM td token
      _ -> Nothing
  }

ruleAbsorptionOfAfterNamedDay :: Rule
ruleAbsorptionOfAfterNamedDay = Rule
  { name = "absorption of , after named day"
  , pattern =
    [ Predicate isADayOfWeek
    , regex ","
    ]
  , prod = \tokens -> case tokens of
      (x:_) -> Just x
      _ -> Nothing
  }

ruleLastDayofweekOfTime :: Rule
ruleLastDayofweekOfTime = Rule
  { name = "last <day-of-week> of <time>"
  , pattern =
    [ regex "sidste"
    , Predicate isADayOfWeek
    , regex "af|i"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (_:Token Time td1:_:Token Time td2:_) ->
        tt $ predLastOf td1 td2
      _ -> Nothing
  }

ruleFathersDay :: Rule
ruleFathersDay = Rule
  { name = "Father's Day"
  , pattern =
    [ regex "far'?s?'? dag"
    ]
  , prod = \_ -> tt $ monthDay 6 5
  }

ruleCycleBeforeTime :: Rule
ruleCycleBeforeTime = Rule
  { name = "<cycle> before <time>"
  , pattern =
    [ dimension TimeGrain
    , regex "fÃ¸r"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token TimeGrain grain:_:Token Time td:_) ->
        tt $ cycleNthAfter False grain (-1) td
      _ -> Nothing
  }

ruleDdmmyyyy :: Rule
ruleDdmmyyyy = Rule
  { name = "dd/mm/yyyy"
  , pattern =
    [ regex "(3[01]|[12]\\d|0?[1-9])[\\/-](0?[1-9]|1[0-2])[\\/-](\\d{2,4})"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:m2:m3:_)):_) -> do
        y <- parseInt m3
        m <- parseInt m2
        d <- parseInt m1
        tt $ yearMonthDay y m d
      _ -> Nothing
  }

ruleTimeofdayTimeofdayInterval :: Rule
ruleTimeofdayTimeofdayInterval = Rule
  { name = "<time-of-day> - <time-of-day> (interval)"
  , pattern =
    [ Predicate $ and . sequence [isNotLatent, isATimeOfDay]
    , regex "\\-|til|indtil"
    , Predicate isATimeOfDay
    ]
  , prod = \tokens -> case tokens of
      (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 "efter"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (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 = \tokens -> case tokens of
      (token:_) -> do
        n <- getIntValue token
        tt . cycleNthAfter False TG.Quarter (n - 1) $
          cycleNth TG.Year 0
      _ -> Nothing
  }

ruleTheDayofmonthOrdinal :: Rule
ruleTheDayofmonthOrdinal = Rule
  { name = "the <day-of-month> (ordinal)"
  , pattern =
    [ regex "den"
    , Predicate isDOMOrdinal
    ]
  , prod = \tokens -> case tokens of
      (_:Token Ordinal OrdinalData{TOrdinal.value = v}:_) ->
        tt $ dayOfMonth v
      _ -> Nothing
  }

ruleDurationBeforeTime :: Rule
ruleDurationBeforeTime = Rule
  { name = "<duration> before <time>"
  , pattern =
    [ dimension Duration
    , regex "fÃ¸r"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Duration dd:_:Token Time td:_) ->
        tt $ durationBefore dd td
      _ -> Nothing
  }

rulePartofdayOfTime :: Rule
rulePartofdayOfTime = Rule
  { name = "<part-of-day> of <time>"
  , pattern =
    [ Predicate isAPartOfDay
    , regex "(en |ten )?den"
    , dimension Time
    ]
  , prod = \tokens -> case tokens of
      (Token Time td1:_:Token Time td2:_) ->
        Token Time <$> intersect td1 td2
      _ -> Nothing
  }

ruleEoyendOfYear :: Rule
ruleEoyendOfYear = Rule
  { name = "EOY|End of year"
  , pattern =
    [ regex "EOY"
    ]
  , prod = \_ -> tt $ cycleNth TG.Year 1
  }

ruleTomorrow :: Rule
ruleTomorrow = Rule
  { name = "tomorrow"
  , pattern =
    [ regex "i morgen|imorgen"
    ]
  , prod = \_ -> tt $ cycleNth TG.Day 1
  }

ruleMothersDay :: Rule
ruleMothersDay = Rule
  { name = "Mother's Day"
  , pattern =
    [ regex "mor'?s? dag"
    ]
  , prod = \_ -> tt $ nthDOWOfMonth 1 7 5
  }

ruleTimeofdayOclock :: Rule
ruleTimeofdayOclock = Rule
  { name = "<time-of-day> o'clock"
  , pattern =
    [ Predicate isATimeOfDay
    , regex "h"
    ]
  , prod = \tokens -> case tokens of
      (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 = \tokens -> case tokens of
      (token:
       Token Time td:
       Token RegexMatch (GroupMatch (match:_)):
       _) -> do
         n <- parseInt match
         td2 <- intersectDOM td token
         Token Time <$> intersect td2 (year n)
      _ -> Nothing
  }

ruleHhmmss :: Rule
ruleHhmmss = Rule
  { name = "hh:mm:ss"
  , pattern =
    [ regex "((?:[01]?\\d)|(?:2[0-3]))[:.]([0-5]\\d)[:.]([0-5]\\d)"
    ]
  , prod = \tokens -> case tokens of
      (Token RegexMatch (GroupMatch (m1:m2:m3:_)):_) -> do
        h <- parseInt m1
        m <- parseInt m2
        s <- parseInt m3
        tt $ hourMinuteSecond False h m s
      _ -> 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 = \tokens -> case tokens of
      (Token Time td:
       Token RegexMatch (GroupMatch (tz:_)):
       _) -> Token Time <$> inTimezone (Text.toUpper tz) td
      _ -> Nothing
  }

rules :: [Rule]
rules =
  [ ruleADuration
  , ruleAboutDuration
  , ruleAboutTimeofday
  , ruleAbsorptionOfAfterNamedDay
  , ruleAfterDuration
  , ruleAfterLunch
  , ruleAfterTimeofday
  , ruleAfterWork
  , ruleAfternoon
  , ruleAtTimeofday
  , ruleBetweenDatetimeAndDatetimeInterval
  , ruleBetweenTimeofdayAndTimeofdayInterval
  , ruleByTheEndOfTime
  , ruleChristmas
  , ruleChristmasEve
  , ruleConstitutionDay
  , ruleCycleAfterTime
  , ruleCycleBeforeTime
  , ruleDatetimeDatetimeInterval
  , ruleDayofmonthNonOrdinalNamedmonth
  , ruleDayofmonthNonOrdinalOfNamedmonth
  , ruleDayofmonthOrdinal
  , ruleDayofmonthOrdinalOfNamedmonth
  , ruleDayofmonthordinalNamedmonth
  , ruleDayofmonthordinalNamedmonthYear
  , ruleDdmm
  , ruleDdmmyyyy
  , ruleDurationAfterTime
  , ruleDurationAgo
  , ruleDurationBeforeTime
  , ruleDurationFromNow
  , ruleDurationHence
  , ruleEomendOfMonth
  , ruleEoyendOfYear
  , ruleEvening
  , ruleExactlyTimeofday
  , ruleFathersDay
  , ruleFromDatetimeDatetimeInterval
  , ruleFromTimeofdayTimeofdayInterval
  , ruleHalloweenDay
  , ruleHhmm
  , ruleHhmmss
  , ruleHourofdayIntegerAsRelativeMinutes
  , ruleInDuration
  , ruleInduringThePartofday
  , ruleInduringThePartofday2
  , ruleIntersect
  , ruleIntersectBy
  , ruleIntersectByOfFromS
  , ruleLastCycle
  , ruleLastCycleOfTime
  , ruleLastDayofweekOfTime
  , ruleLastNCycle
  , ruleLastTime
  , ruleLunch
  , ruleMidnighteodendOfDay
  , ruleMonthDdddInterval
  , ruleMorning
  , ruleMothersDay
  , ruleNamedmonthDayofmonthNonOrdinal
  , ruleNamedmonthDayofmonthOrdinal
  , ruleNewYearsDay
  , ruleNewYearsEve
  , ruleNextCycle
  , ruleNextNCycle
  , ruleNextTime
  , ruleNight
  , ruleNoon
  , ruleNow
  , ruleNthTimeAfterTime
  , ruleNthTimeAfterTime2
  , ruleNthTimeOfTime
  , ruleNthTimeOfTime2
  , ruleOnANamedday
  , ruleOnDate
  , ruleOrdinalCycleAfterTime
  , ruleOrdinalCycleOfTime
  , ruleOrdinalQuarter
  , ruleOrdinalQuarterYear
  , rulePartofdayOfTime
  , ruleRelativeMinutesAfterpastIntegerHourofday
  , ruleRelativeMinutesTotillbeforeIntegerHourofday
  , ruleSeason
  , ruleSeason2
  , ruleSeason3
  , ruleSeason4
  , ruleTheCycleAfterTime
  , ruleTheCycleBeforeTime
  , ruleTheCycleOfTime
  , ruleTheDayAfterTomorrow
  , ruleTheDayBeforeYesterday
  , ruleTheDayofmonthNonOrdinal
  , ruleTheDayofmonthOrdinal
  , ruleTheIdesOfNamedmonth
  , ruleTheOrdinalCycleAfterTime
  , ruleTheOrdinalCycleOfTime
  , ruleThisCycle
  , ruleThisPartofday
  , ruleThisTime
  , ruleThisnextDayofweek
  , ruleTimeAfterNext
  , ruleTimeBeforeLast
  , ruleTimePartofday
  , ruleTimeofdayApproximately
  , ruleTimeofdayLatent
  , ruleTimeofdayOclock
  , ruleTimeofdaySharp
  , ruleTimeofdayTimeofdayInterval
  , ruleToday
  , ruleTomorrow
  , ruleTonight
  , ruleUntilTimeofday
  , ruleValentinesDay
  , ruleWeekend
  , ruleWithinDuration
  , ruleYear
  , ruleYearLatent
  , ruleYearLatent2
  , ruleYesterday
  , ruleYyyymmdd
  , ruleQuarterTotillbeforeIntegerHourofday
  , ruleHalfTotillbeforeIntegerHourofday
  , ruleQuarterAfterpastIntegerHourofday
  , ruleHalfAfterpastIntegerHourofday
  , ruleHourofdayQuart
  , ruleHourofdayHalf
  , ruleTimezone
  ]
  ++ ruleDaysOfWeek
  ++ ruleMonths


-- 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 OverloadedStrings #-}

module Duckling.Time.DE.Corpus
  ( corpus
  , negativeCorpus
  ) where

import Data.String
import Prelude

import Duckling.Locale
import Duckling.Resolve
import Duckling.Testing.Types hiding (examples)
import Duckling.Time.Corpus
import Duckling.Time.Types hiding (Month)
import Duckling.TimeGrain.Types hiding (add)

context :: Context
context = testContext {locale = makeLocale DE Nothing}

corpus :: Corpus
corpus = (context, testOptions, allExamples)

negativeCorpus :: NegativeCorpus
negativeCorpus = (context, testOptions, examples)
  where
    examples =
      [ "ein Hotel"
      , "ein Angebot"
      , "nÃ¤chsten 5"
      , "so"
      ]

allExamples :: [Example]
allExamples = concat
  [ examples (datetime (2013, 2, 12, 4, 30, 0) Second)
             [ "jetzt"
             , "genau jetzt"
             , "gerade eben"
             ]
  , examples (datetime (2013, 2, 12, 0, 0, 0) Day)
             [ "heute"
             , "zu dieser zeit"
             ]
  , examples (datetime (2013, 2, 11, 0, 0, 0) Day)
             [ "gestern"
             ]
  , examples (datetime (2013, 2, 13, 0, 0, 0) Day)
             [ "morgen"
             ]
  , examples (datetime (2013, 2, 18, 0, 0, 0) Day)
             [ "montag"
             , "mo."
             , "diesen montag"
             ]
  , examples (datetime (2013, 2, 18, 0, 0, 0) Day)
             [ "Montag, Feb 18"
             , "Montag, Februar 18"
             ]
  , examples (datetime (2013, 2, 19, 0, 0, 0) Day)
             [ "dienstag"
             ]
  , examples (datetime (2013, 2, 14, 0, 0, 0) Day)
             [ "donnerstag"
             , "do"
             , "do."
             ]
  , examples (datetime (2013, 2, 15, 0, 0, 0) Day)
             [ "freitag"
             , "fr."
             ]
  , examples (datetime (2013, 2, 16, 0, 0, 0) Day)
             [ "samstag"
             , "sa."
             ]
  , examples (datetime (2013, 2, 17, 0, 0, 0) Day)
             [ "sonntag"
             , "so."
             ]
  , examples (datetime (2013, 3, 1, 0, 0, 0) Day)
             [ "1 mÃ¤rz"
             , "erster mÃ¤rz"
             ]
  , examples (datetime (2013, 3, 3, 0, 0, 0) Day)
             [ "mÃ¤rz 3"
             ]
  , examples (datetime (2015, 3, 3, 0, 0, 0) Day)
             [ "mÃ¤rz 3 2015"
             ]
  , examples (datetime (2013, 2, 15, 0, 0, 0) Day)
             [ "am 15ten"
             ]
  , examples (datetime (2013, 2, 15, 0, 0, 0) Day)
             [ "15. februar"
             , "februar 15"
             , "15te februar"
             , "15.2."
             , "am 15.2."
             , "februar 15"
             ]
  , examples (datetime (2013, 8, 8, 0, 0, 0) Day)
             [ "Aug 8"
             ]
  , examples (datetime (2014, 10, 0, 0, 0, 0) Month)
             [ "Oktober 2014"
             ]
  , examples (datetime (1974, 10, 31, 0, 0, 0) Day)
             [ "31.10.1974"
             , "31.10.74"
             ]
  , examples (datetime (2015, 4, 14, 0, 0, 0) Day)
             [ "14 april 2015"
             , "April 14, 2015"
             , "14te April 15"
             ]
  , examples (datetime (2013, 2, 19, 0, 0, 0) Day)
             [ "nÃ¤chsten dienstag"
             ]
  , examples (datetime (2013, 2, 22, 0, 0, 0) Day)
             [ "Ã¼bernÃ¤chsten freitag"
             ]
  , examples (datetime (2013, 3, 0, 0, 0, 0) Month)
             [ "nÃ¤chsten mÃ¤rz"
             ]
  , examples (datetime (2014, 3, 0, 0, 0, 0) Month)
             [ "Ã¼bernÃ¤chsten mÃ¤rz"
             ]
  , examples (datetime (2013, 2, 10, 0, 0, 0) Day)
             [ "Sonntag, Feb 10"
             ]
  , examples (datetime (2013, 2, 13, 0, 0, 0) Day)
             [ "Mittwoch, Feb 13"
             ]
  , examples (datetime (2013, 2, 18, 0, 0, 0) Day)
             [ "Montag, Feb 18"
             ]
  , examples (datetime (2013, 2, 11, 0, 0, 0) Week)
             [ "diese woche"
             , "kommende woche"
             ]
  , examples (datetime (2013, 2, 4, 0, 0, 0) Week)
             [ "letzte woche"
             ]
  , examples (datetime (2013, 2, 18, 0, 0, 0) Week)
             [ "nÃ¤chste woche"
             ]
  , examples (datetime (2013, 2, 25, 0, 0, 0) Week)
             [ "Ã¼bernÃ¤chste woche"
             ]
  , examples (datetime (2013, 1, 0, 0, 0, 0) Month)
             [ "letzten monat"
             ]
  , examples (datetime (2013, 3, 0, 0, 0, 0) Month)
             [ "nÃ¤chsten monat"
             ]
  , examples (datetime (2013, 4, 0, 0, 0, 0) Month)
             [ "Ã¼bernÃ¤chsten monat"
             ]
  , examples (datetime (2013, 1, 1, 0, 0, 0) Quarter)
             [ "dieses quartal"
             ]
  , examples (datetime (2013, 4, 1, 0, 0, 0) Quarter)
             [ "nÃ¤chstes quartal"
             ]
  , examples (datetime (2013, 7, 1, 0, 0, 0) Quarter)
             [ "Ã¼bernÃ¤chstes quartal"
             ]
  , examples (datetime (2013, 7, 1, 0, 0, 0) Quarter)
             [ "drittes quartal"
             ]
  , examples (datetime (2018, 10, 1, 0, 0, 0) Quarter)
             [ "4tes quartal 2018"
             ]
  , examples (datetime (2012, 0, 0, 0, 0, 0) Year)
             [ "letztes jahr"
             ]
  , examples (datetime (2013, 0, 0, 0, 0, 0) Year)
             [ "dieses jahr"
             ]
  , examples (datetime (2014, 0, 0, 0, 0, 0) Year)
             [ "nÃ¤chstes jahr"
             ]
  , examples (datetime (2015, 0, 0, 0, 0, 0) Year)
             [ "Ã¼bernÃ¤chstes jahr"
             ]
  , examples (datetime (2013, 2, 10, 0, 0, 0) Day)
             [ "letzten sonntag"
             , "sonntag der letzten woche"
             , "sonntag letzte woche"
             ]
  , examples (datetime (2013, 2, 5, 0, 0, 0) Day)
             [ "letzten dienstag"
             ]
  , examples (datetime (2013, 2, 19, 0, 0, 0) Day)
             [ "nÃ¤chsten dienstag"
             ]
  , examples (datetime (2013, 2, 13, 0, 0, 0) Day)
             [ "nÃ¤chsten mittwoch"
             ]
  , examples (datetime (2013, 2, 20, 0, 0, 0) Day)
             [ "mittwoch der nÃ¤chsten woche"
             , "mittwoch nÃ¤chste woche"
             , "mittwoch nach dem nÃ¤chsten"
             ]
  , examples (datetime (2013, 2, 27, 0, 0, 0) Day)
             [ "mittwoch in 2 wochen"
             , "mittwoch in zwei wochen"
             ]
  , examples (datetime (2013, 1, 30, 0, 0, 0) Day)
             [ "mittwoch vor 2 wochen"
             , "mittwoch vor zwei wochen"
             ]
  , examples (datetime (2013, 2, 22, 0, 0, 0) Day)
             [ "freitag nach dem nÃ¤chsten"
             ]
  , examples (datetime (2013, 2, 11, 0, 0, 0) Day)
             [ "montag dieser woche"
             ]
  , examples (datetime (2013, 2, 12, 0, 0, 0) Day)
             [ "dienstag dieser woche"
             ]
  , examples (datetime (2013, 2, 13, 0, 0, 0) Day)
             [ "mittwoch dieser woche"
             ]
  , examples (datetime (2013, 2, 14, 0, 0, 0) Day)
             [ "Ã¼bermorgen"
             ]
  , examples (datetime (2013, 2, 10, 0, 0, 0) Day)
             [ "vorgestern"
             ]
  , examples (datetime (2013, 3, 25, 0, 0, 0) Day)
             [ "letzter montag im mÃ¤rz"
             ]
  , examples (datetime (2014, 3, 30, 0, 0, 0) Day)
             [ "letzter sonntag im mÃ¤rz 2014"
             ]
  , examples (datetime (2013, 10, 3, 0, 0, 0) Day)
             [ "dritter tag im oktober"
             ]
  , examples (datetime (2014, 10, 6, 0, 0, 0) Week)
             [ "erste woche im oktober 2014"
             ]
  , examples (datetime (2015, 10, 31, 0, 0, 0) Day)
             [ "letzter tag im oktober 2015"
             ]
  , examples (datetime (2014, 9, 22, 0, 0, 0) Week)
             [ "letzte woche im september 2014"
             ]
  , examples (datetime (2013, 10, 1, 0, 0, 0) Day)
             [ "erster dienstag im oktober"
             ]
  , examples (datetime (2014, 9, 16, 0, 0, 0) Day)
             [ "dritter dienstag im september 2014"
             ]
  , examples (datetime (2014, 10, 1, 0, 0, 0) Day)
             [ "erster mittwoch im oktober 2014"
             ]
  , examples (datetime (2014, 10, 8, 0, 0, 0) Day)
             [ "zweiter mittwoch im oktober 2014"
             ]
  , examples (datetime (2015, 1, 13, 0, 0, 0) Day)
             [ "dritter dienstag nach weihnachten 2014"
             ]
  , examples (datetime (2013, 2, 12, 4, 0, 0) Hour)
             [ "um 4 in der frÃ¼h"
             ]
  , examples (datetime (2013, 2, 12, 15, 0, 0) Hour)
             [ "um 3"
             , "3 uhr"
             , "um drei"
             ]
  , examples (datetime (2013, 2, 12, 3, 18, 0) Minute)
             [ "3:18 frÃ¼h"
             ]
  , examples (datetime (2013, 2, 13, 3, 18, 0) Minute)
             [ "3:18"
             ]
  , examples (datetime (2013, 2, 12, 15, 0, 0) Hour)
             [ "um 3 am nachmittag"
             , "um 15"
             , "um 15 uhr"
             , "15 uhr"
             ]
  , examples (datetime (2013, 2, 12, 15, 0, 0) Hour)
             [ "zirka 15 uhr"
             , "circa 15 uhr"
             , "um circa 15 uhr"
             , "zirka 3 uhr am nachmittag"
             , "um ungefÃ¤hr 15 uhr"
             , "gegen 15 uhr"
             , "ca. 15h"
             , "ca. um 15 uhr"
             , "um ca 15h"
             , "so gegen 15 uhr"
             , "so um 15 uhr"
             , "etwa um 15 uhr"
             , "so ungefÃ¤hr um 15 uhr"
             , "etwa gegen 15 uhr"
             , "gegen 15 uhr"
             , "ungefÃ¤hr um 15 uhr"
             , "ungefÃ¤hr gegen 15 uhr"
             , "so circa um 15 uhr"
             , "15 uhr in etwa"
             ]
  , examples (datetime (2013, 4, 1, 18, 0, 0) Hour)
             [ "01.04. gegen 18Uhr"
             ]
  , examples (datetime (2013, 2, 13, 17, 0, 0) Hour)
             [ "pÃ¼nktlich um 17 uhr morgen"
             ]
  , examples (datetime (2013, 2, 12, 15, 15, 0) Minute)
             [ "um viertel nach 3"
             , "viertel nach drei Uhr"
             , "3 uhr 15 am nachmittag"
             , "15:15"
             ]
  , examples (datetime (2013, 2, 12, 15, 20, 0) Minute)
             [ "um 20 nach 3"
             , "15:20 am nachmittag"
             , "15 uhr 20 nachmittags"
             , "zwanzig nach 3"
             , "15:20"
             ]
  , examples (datetime (2013, 2, 12, 15, 30, 0) Minute)
             [ "um halb 4"
             ]
  , examples (datetime (2013, 2, 12, 15, 30, 0) Minute)
             [ "halb vier uhr nachmittags"
             , "halb vier am nachmittag"
             , "15:30"
             ]
  , examples (datetime (2013, 2, 13, 3, 30, 0) Minute)
             [ "3:30"
             ]
  , examples (datetime (2013, 2, 12, 11, 45, 0) Minute)
             [ "viertel vor 12"
             , "11:45"
             ]
  , examples (datetime (2013, 2, 12, 11, 45, 0) Minute)
             [ "15 minuten vor 12"
             ]
  , examples (datetime (2013, 2, 12, 20, 0, 0) Hour)
             [ "8 uhr am abend"
             , "heute abend um 20 Uhr"
             ]
  , examples (datetime (2013, 2, 12, 20, 0, 0) Minute)
             [ "heute um 20:00"
             ]
  , examples (datetime (2013, 9, 20, 19, 30, 0) Minute)
             [ "um 19:30 am fr, 20. Sept."
             ]
  , examples (datetime (2013, 2, 16, 9, 0, 0) Hour)
             [ "am samstag um 9 Uhr"
             ]
  , examples (datetime (2014, 7, 18, 19, 0, 0) Hour)
             [ "Fr, 18. Juli 2014 7 uhr abends"
             ]
  , examples (datetime (2014, 7, 18, 0, 0, 0) Day)
             [ "Fr, 18. Juli 2014"
             , "Freitag, 18.07.14"
             , "Freitag, den 18.07.2014"
             , "Freitag, der 18. Juli 14"
             ]
  , examples (datetime (2013, 2, 12, 4, 30, 1) Second)
             [ "in einer sekunde"
             ]
  , examples (datetime (2013, 2, 12, 4, 31, 0) Second)
             [ "in einer minute"
             ]
  , examples (datetime (2013, 2, 12, 4, 32, 0) Second)
             [ "in 2 minuten"
             ]
  , examples (datetime (2013, 2, 12, 5, 30, 0) Second)
             [ "in 60 minuten"
             ]
  , examples (datetime (2013, 2, 12, 5, 0, 0) Second)
             [ "in einer halben stunde"
             , "in 30 minuten"
             ]
  , examples (datetime (2013, 2, 12, 7, 0, 0) Second)
             [ "in 2,5 stunden"
             , "in zwei ein halb stunden"
             ]
  , examples (datetime (2013, 2, 12, 5, 30, 0) Minute)
             [ "in einer stunde"
             ]
  , examples (datetime (2013, 2, 12, 6, 30, 0) Minute)
             [ "in zwei stunden"
             ]
  , examples (datetime (2013, 2, 12, 6, 30, 0) Minute)
             [ "in ein paar stunden"
             ]
  , examples (datetime (2013, 2, 13, 4, 30, 0) Minute)
             [ "in 24 stunden"
             ]
  , examples (datetime (2013, 2, 13, 0, 0, 0) Day)
             [ "morgen"
             ]
  , examples (datetime (2016, 2, 0, 0, 0, 0) Month)
             [ "in 3 Jahren"
             ]
  , examples (datetime (2013, 2, 19, 4, 0, 0) Hour)
             [ "in 7 tagen"
             ]
  , examples (datetime (2013, 2, 19, 0, 0, 0) Day)
             [ "in 1 woche"
             , "in einer woche"
             ]
  , examples (datetime (2013, 2, 12, 5, 0, 0) Second)
             [ "in zirka einer halben stunde"
             ]
  , examples (datetime (2013, 2, 5, 4, 0, 0) Hour)
             [ "vor 7 tagen"
             ]
  , examples (datetime (2013, 1, 29, 4, 0, 0) Hour)
             [ "vor 14 tagen"
             ]
  , examples (datetime (2013, 1, 29, 0, 0, 0) Day)
             [ "vor zwei wochen"
             ]
  , examples (datetime (2013, 2, 5, 0, 0, 0) Day)
             [ "vor einer woche"
             ]
  , examples (datetime (2013, 1, 22, 0, 0, 0) Day)
             [ "vor drei wochen"
             ]
  , examples (datetime (2012, 11, 12, 0, 0, 0) Day)
             [ "vor drei monaten"
             ]
  , examples (datetime (2011, 2, 0, 0, 0, 0) Month)
             [ "vor zwei jahren"
             ]
  , examples (datetime (2013, 2, 19, 4, 0, 0) Hour)
             [ "in 7 tagen"
             ]
  , examples (datetime (2013, 12, 25, 0, 0, 0) Day)
             [ "ein jahr nach weihnachten"
             ]
  , examples (datetimeInterval ((2013, 6, 21, 0, 0, 0), (2013, 9, 24, 0, 0, 0)) Day)
             [ "diesen sommer"
             ]
  , examples (datetimeInterval ((2012, 12, 21, 0, 0, 0), (2013, 3, 21, 0, 0, 0)) Day)
             [ "diesen winter"
             ]
  , examples (datetimeHoliday (2013, 12, 25, 0, 0, 0) Day "Weihnachten")
             [ "Weihnachten"
             , "Weihnachtstag"
             ]
  , examples (datetimeHoliday (2013, 12, 31, 0, 0, 0) Day "Silvester")
             [ "Silvester"
             ]
  , examples (datetimeHoliday (2014, 1, 1, 0, 0, 0) Day "Neujahr")
             [ "Neujahrstag"
             , "Neujahr"
             ]
  , examples (datetimeHoliday (2013, 2, 14, 0, 0, 0) Day "Valentinstag")
             [ "Valentinstag"
             ]
  , examples (datetimeHoliday (2013, 5, 12, 0, 0, 0) Day "Muttertag" )
             [ "Muttertag"
             ]
  , examples (datetimeHoliday (2013, 6, 16, 0, 0, 0) Day "Vatertag" )
             [ "Vatertag"
             ]
  , examples (datetimeHoliday (2013, 10, 3, 0, 0, 0) Day "Tag der Deutschen Einheit")
             [ "Tag der Deutschen Einheit"
             ]
  , examples (datetimeHoliday (2013, 10, 31, 0, 0, 0) Day "Halloween")
             [ "Halloween"
             ]
  , examples (datetimeHoliday (2013, 11, 1, 0, 0, 0) Day "Allerheiligen" )
             [ "Allerheiligen"
             ]
  , examples (datetimeHoliday (2013, 12, 6, 0, 0, 0) Day "Nikolaus")
             [ "Nikolaus"
             , "Nikolaustag"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 18, 0, 0), (2013, 2, 13, 0, 0, 0)) Hour)
             [ "heute abend"
             , "am abend"
             ]
  , examples (datetimeInterval ((2013, 2, 13, 18, 0, 0), (2013, 2, 14, 0, 0, 0)) Hour)
             [ "morgen abend"
             ]
  , examples (datetimeInterval ((2013, 2, 13, 12, 0, 0), (2013, 2, 13, 14, 0, 0)) Hour)
             [ "morgen mittag"
             , "morgen zu mittag"
             ]
  , examples (datetimeInterval ((2013, 2, 11, 18, 0, 0), (2013, 2, 12, 0, 0, 0)) Hour)
             [ "gestern abend"
             ]
  , examples (datetimeInterval ((2013, 2, 15, 18, 0, 0), (2013, 2, 18, 0, 0, 0)) Hour)
             [ "dieses wochenende"
             ]
  , examples (datetimeInterval ((2013, 2, 18, 3, 0, 0), (2013, 2, 18, 12, 0, 0)) Hour)
             [ "montag morgens"
             ]
  , examples (datetimeInterval ((2013, 2, 15, 3, 0, 0), (2013, 2, 15, 12, 0, 0)) Hour)
             [ "morgens am 15. februar"
             , "15. februar morgens"
             , "am morgen des 15. februar"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 4, 29, 58), (2013, 2, 12, 4, 30, 0)) Second)
             [ "letzte 2 sekunden"
             , "letzten zwei sekunden"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 4, 30, 1), (2013, 2, 12, 4, 30, 4)) Second)
             [ "nÃ¤chste 3 sekunden"
             , "nÃ¤chsten drei sekunden"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 4, 28, 0), (2013, 2, 12, 4, 30, 0)) Minute)
             [ "letzte 2 minuten"
             , "letzten zwei minuten"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 4, 31, 0), (2013, 2, 12, 4, 34, 0)) Minute)
             [ "nÃ¤chste 3 minuten"
             , "nÃ¤chsten drei minuten"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 5, 0, 0), (2013, 2, 12, 8, 0, 0)) Hour)
             [ "nÃ¤chste 3 stunden"
             , "nÃ¤chsten drei stunden"
             ]
  , examples (datetimeInterval ((2013, 2, 10, 0, 0, 0), (2013, 2, 12, 0, 0, 0)) Day)
             [ "letzte 2 tage"
             , "letzten zwei tage"
             , "vergangenen zwei tage"
             ]
  , examples (datetimeInterval ((2013, 2, 13, 0, 0, 0), (2013, 2, 16, 0, 0, 0)) Day)
             [ "nÃ¤chsten 3 tagen"
             , "nÃ¤chsten drei tage"
             , "kommenden drei tagen"
             ]
  , examples (datetimeInterval ((2013, 2, 13, 0, 0, 0), (2013, 2, 15, 0, 0, 0)) Day)
             [ "nÃ¤chsten paar tagen"
             , "kommenden paar tagen"
             ]
  , examples (datetimeInterval ((2013, 1, 28, 0, 0, 0), (2013, 2, 11, 0, 0, 0)) Week)
             [ "letzten 2 wochen"
             , "letzte zwei wochen"
             , "vergangenen 2 wochen"
             ]
  , examples (datetimeInterval ((2013, 2, 18, 0, 0, 0), (2013, 3, 11, 0, 0, 0)) Week)
             [ "nÃ¤chsten 3 wochen"
             , "nÃ¤chste drei wochen"
             , "kommenden drei wochen"
             ]
  , examples (datetimeInterval ((2012, 12, 0, 0, 0, 0), (2013, 2, 0, 0, 0, 0)) Month)
             [ "letzten 2 monaten"
             , "letzte zwei monate"
             , "vergangenen zwei monaten"
             ]
  , examples (datetimeInterval ((2013, 3, 0, 0, 0, 0), (2013, 6, 0, 0, 0, 0)) Month)
             [ "nÃ¤chsten 3 monaten"
             , "nÃ¤chste drei monate"
             , "kommenden drei monaten"
             ]
  , examples (datetimeInterval ((2011, 0, 0, 0, 0, 0), (2013, 0, 0, 0, 0, 0)) Year)
             [ "letzten 2 jahren"
             , "letzten zwei jahre"
             , "vergangenen zwei jahren"
             ]
  , examples (datetimeInterval ((2014, 0, 0, 0, 0, 0), (2017, 0, 0, 0, 0, 0)) Year)
             [ "nÃ¤chsten 3 jahren"
             , "kommenden drei jahren"
             , "nÃ¤chste drei jahre"
             ]
  , examples (datetimeInterval ((2013, 7, 13, 0, 0, 0), (2013, 7, 16, 0, 0, 0)) Day)
             [ "13. - 15. Juli"
             , "13ter bis 15ter Juli"
             , "13 bis 15 Juli"
             , "13 - 15 Juli"
             , "Juli 13 - Juli 15"
             ]
  , examples (datetimeInterval ((2013, 8, 8, 0, 0, 0), (2013, 8, 13, 0, 0, 0)) Day)
             [ "Aug 8 - Aug 12"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 9, 30, 0), (2013, 2, 12, 11, 1, 0)) Minute)
             [ "9:30 - 11:00"
             ]
  , examples (datetimeInterval ((2013, 2, 14, 9, 30, 0), (2013, 2, 14, 11, 1, 0)) Minute)
             [ "am Donnerstag von 9:30 - 11:00"
             , "am Donnerstag zwischen 9:30 und 11:00"
             , "Donnerstag 9:30 - 11:00"
             , "am Donnerstag nach 9:30 aber vor 11:00"
             , "Donnerstag von 9:30 bis 11:00"
             ]
  , examples (datetimeInterval ((2013, 2, 14, 9, 0, 0), (2013, 2, 14, 12, 0, 0)) Hour)
             [ "Donnerstag Vormittag von 9 bis 11"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 11, 30, 0), (2013, 2, 12, 13, 31, 0)) Minute)
             [ "11:30-13:30"
             ]
  , examples (datetime (2013, 9, 21, 1, 30, 0) Minute)
             [ "1:30 am Sa, 21. Sept"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 4, 30, 0), (2013, 2, 26, 0, 0, 0)) Second)
             [ "binnen 2 wochen"
             , "innerhalb von 2 wochen"
             ]
  , examples (datetimeOpenInterval Before (2013, 2, 12, 14, 0, 0) Hour)
             [ "bis 2 Uhr nachmittag"
             ]
  , examples (datetimeOpenInterval Before (2013, 2, 13, 0, 0, 0) Hour)
             [ "bis zum ende des tages"
             ]
  , examples (datetimeOpenInterval Before (2013, 3, 1, 0, 0, 0) Month)
             [ "bis zum ende des monats"
             ]
  , examples (datetime (2013, 2, 12, 13, 0, 0) Minute)
             [ "16 Uhr CET"
             ]
  , examples (datetime (2013, 2, 14, 6, 0, 0) Minute)
             [ "donnerstag 8:00 GMT"
             , "donnerstag 8:00 gmt"
             ]
  , examples (datetime (2013, 2, 12, 14, 0, 0) Hour)
             [ "heute um 14 Uhr"
             , "um 2"
             ]
  , examples (datetime (2013, 2, 13, 15, 0, 0) Hour)
             [ "morgen um 15 Uhr"
             , "morgen so um 15 Uhr"
             ]
  , examples (datetimeOpenInterval After (2013, 2, 12, 14, 0, 0) Hour)
             [ "nach 14 Uhr"
             , "nach 14h"
             , "ab 14Uhr"
             , "nach 2 Uhr"
             , "frÃ¼hestens 14 Uhr"
             , "14 Uhr frÃ¼hstens"
             ]
  , examples (datetimeOpenInterval Before (2013, 2, 12, 11, 0, 0) Hour)
             [ "bis 11 uhr"
             , "vor 11 uhr"
             , "bis 11h vormittags"
             , "bis 11 am vormittag"
             , "spÃ¤testens 11 uhr"
             , "11Uhr spÃ¤testens"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 12, 0, 0), (2013, 2, 12, 19, 0, 0)) Hour)
             [ "am nachmittag"
             ]
  , examples (datetime (2013, 2, 12, 13, 30, 0) Minute)
             [ "um 13:30 am nachmittag"
             , "nachmittags um 1 uhr 30"
             , "13:30"
             ]
  , examples (datetime (2013, 2, 12, 4, 45, 0) Second)
             [ "in 15 minuten"
             ]
  , examples (datetimeInterval ((2013, 2, 12, 13, 0, 0), (2013, 2, 12, 17, 0, 0)) Hour)
             [ "nach dem mittagessen"
             ]
  , examples (datetime (2013, 2, 12, 10, 30, 0) Minute)
             [ "10:30"
             ]
  , examples (datetime (2013, 2, 18, 0, 0, 0) Day)
             [ "nÃ¤chsten montag"
             , "kommenden montag"
             ]
  , examples (datetime (2013, 12, 10, 0, 0, 0) Day)
             [ "10.12."
             ]
  , examples (datetimeInterval ((2013, 2, 12, 18, 30, 0), (2013, 2, 12, 19, 1, 0)) Minute)
             [ "18:30h - 19:00h"
             , "18:30h/19:00h"
             ]
  , examples (datetimeInterval ((2013, 10, 14, 0, 0, 0), (2013, 10, 16, 0, 0, 0)) Day)
             [ "14. - 15.10."
             , "14 - 15.10."
             , "14. - 15.10"
             , "14 - 15.10"
             , "14.10. - 15.10."
             , "14. - 15.10.2013"
             , "14.10. - 15.10.2013"
             , "14./15.10."
             ]
  , examples (datetimeInterval ((2018, 10, 14, 0, 0, 0), (2018, 10, 16, 0, 0, 0)) Day)
             [ "14. - 15.10.18"
             , "14 - 15.10.18"
             , "14.10. - 15.10.2018"
             , "14./15.10.2018"
             , "vom 14.10. - 15.10.2018"
             , "14.10. bis 15.10.2018"
             , "vom 14.10. auf den 15.10.2018"
             , "vom 14.10. bis zum 15.10.2018"
             ]
  , examples (datetime (2013, 10, 10, 0, 0, 0) Day)
             [ "am 10.10."
             , "am 10.10"
             , "10.10"
             ]
  , examples (datetime (2013, 2, 12, 10, 10, 0) Minute)
             [ "um 10.10"
             ]
  , examples (datetime (2013, 2, 12, 17, 10, 0) Minute)
             [ "17h10"
             ]
  , examples (datetime (2018, 8, 31, 0, 0, 0) Day)
             [ "2018-08-31"
             , "2018-8-31"
             ]
  , examples (datetime (1980, 5, 30, 0, 0, 0) Day)
             [ "30. Mai 1980"
             ]
  , examples (datetime (2013, 2, 9, 0, 0, 0) Day)
             [ "vorvorgestern"
             ]
  , examples (datetime (2013, 12, 5, 0, 0, 0) Day)
             [ "fÃ¼nfter Dezember"
             ]
  , examples (datetime (2013, 12, 30, 0, 0, 0) Day)
             [ "dreiÃŸigster Dezember"
             , "dreissigster Dezember"
             ]
  , examples (datetime (2013, 12, 4, 0, 0, 0) Day)
             [ "am vierten Dezember"
             , "der vierte Dezember"
             ]
  , examples (datetimeHoliday (2014, 1, 31, 0, 0, 0) Day "Chinesisches Neujahr")
             [ "Chinesisches Neujahr"
             , "Chinesisches FrÃ¼hlingsfest"
             , "Chinesisches Neujahrsfest"
             ]
  , examples (datetimeHoliday (2018, 2, 16, 0, 0, 0) Day "Chinesisches Neujahr")
             [ "Chinesisches Neujahr 2018"
             ]
  , examples (datetimeHoliday (2018, 9, 18, 0, 0, 0) Day "Jom Kippur")
             [ "Jom Kippur 2018"
             , "Yom Kippur 2018"
             ]
  , examples (datetimeHoliday (2018, 9, 30, 0, 0, 0) Day "Schmini Azeret")
             [ "Schmini Azeret 2018"
             , "Schemini Azeret 2018"
             , "Shemini Atzeret 2018"
             ]
  , examples (datetimeHoliday (2018, 10, 1, 0, 0, 0) Day "Simchat Torah")
             [ "simchat torah 2018"
             ]
  , examples (datetimeHoliday (2018, 7, 21, 0, 0, 0) Day "Tisha B'Av")
             [ "tisha b'av 2018"
             ]
  , examples (datetimeHoliday (2018, 4, 18, 0, 0, 0) Day "Jom Ha'atzmaut")
             [ "Jom Haatzmaut 2018"
             , "Yom Haatzmaut 2018"
             , "Yom Ha'atzmaut 2018"
             ]
  , examples (datetimeHoliday (2017, 5, 13, 0, 0, 0) Day "Lag BaOmer")
             [ "Lag BaOmer 2017"
             , "Lag LaOmer 2017"
             ]
  , examples (datetimeHoliday (2018, 4, 11, 0, 0, 0) Day "Jom HaShoah")
             [ "Jom HaShoah 2018"
             , "Yom HaShoah 2018"
             , "Holocaustgedenktag 2018"
             , "Holocaust-Gedenktag 2018"
             ]
  , examples (datetimeIntervalHoliday ((2018, 9, 9, 0, 0, 0), (2018, 9, 12, 0, 0, 0)) Day "Rosch haSchana")
             [ "Rosch haSchana 2018"
             , "Rosch ha-Schana 2018"
             , "Rosch ha-Schanah 2018"
             ]
  , examples (datetimeIntervalHoliday ((2018, 12, 2, 0, 0, 0), (2018, 12, 10, 0, 0, 0)) Day "Chanukka")
             [ "Chanukka 2018"
             , "Hanukkah 2018"
             ]
  , examples (datetimeIntervalHoliday ((2018, 3, 30, 0, 0, 0), (2018, 4, 8, 0, 0, 0)) Day "Pessach")
             [ "Passover 2018"
             , "Pessach 2018"
             , "Passa 2018"
             , "Passah 2018"
             , "Pascha 2018"
             ]
  , examples (datetimeIntervalHoliday ((2018, 9, 23, 0, 0, 0), (2018, 10, 2, 0, 0, 0)) Day "Sukkot")
             [ "LaubhÃ¼ttenfest 2018"
             , "Sukkot 2018"
             ]
  , examples (datetimeIntervalHoliday ((2018, 5, 19, 0, 0, 0), (2018, 5, 22, 0, 0, 0)) Day "Schawuot")
             [ "Shavuot 2018"
             , "Schawuot 2018"
             ]
  , examples (datetimeHoliday (2017, 11, 30, 0, 0, 0) Day "Maulid an-NabÄ«")
             [ "Mawlid al-Nabawi 2017"
             , "Maulid an-NabÄ« 2017"
             ]
  , examples (datetimeHoliday (1950, 7, 16, 0, 0, 0) Day "Eid al-Fitr")
             [ "Eid al-Fitr 1950"
             ]
  , examples (datetimeHoliday (1975, 10, 6, 0, 0, 0) Day "Eid al-Fitr")
             [ "Eid al-Fitr 1975"
             ]
  , examples (datetimeHoliday (1988, 5, 16, 0, 0, 0) Day "Eid al-Fitr")
             [ "Eid al-Fitr 1988"
             ]
  , examples (datetimeHoliday (2018, 6, 15, 0, 0, 0) Day "Eid al-Fitr")
             [ "Eid al-Fitr 2018"
             ]
  , examples (datetimeHoliday (2034, 12, 12, 0, 0, 0) Day "Eid al-Fitr")
             [ "Eid al-Fitr 2034"
             ]
  , examples (datetimeHoliday (2046, 8, 4, 0, 0, 0) Day "Eid al-Fitr")
             [ "Eid al-Fitr 2046"
             ]
  , examples (datetimeHoliday (2050, 6, 21, 0, 0, 0) Day "Eid al-Fitr")
             [ "Eid al-Fitr 2050"
             ]
  , examples (datetimeHoliday (2018, 8, 21, 0, 0, 0) Day "Eid al-Adha")
             [ "Eid al-Adha 2018"
             , "id ul-adha 2018"
             , "Opferfest 2018"
             , "Bakr Id 2018"
             ]
  , examples (datetimeHoliday (1980, 10, 19, 0, 0, 0) Day "Eid al-Adha")
             [ "Eid al-Adha 1980"
             , "id ul-adha 1980"
             , "Opferfest 1980"
             , "Bakr Id 1980"
             ]
  , examples (datetimeHoliday (1966, 4, 1, 0, 0, 0) Day "Eid al-Adha")
             [ "Eid al-Adha 1966"
             , "id ul-adha 1966"
             , "Opferfest 1966"
             , "Bakr Id 1966"
             ]
  , examples (datetimeHoliday (1974, 1, 3, 0, 0, 0) Day "Eid al-Adha")
             [ "Eid al-Adha 1974"
             , "id ul-adha 1974"
             , "Opferfest 1974"
             , "Bakr Id 1974"
             ]
  , examples (datetimeHoliday (2017, 6, 22, 0, 0, 0) Day "Lailat al-Qadr")
             [ "laylat al kadr 2017"
             , "die Nacht der Bestimmung 2017"
             , "Laylat al-Qadr 2017"
             , "Lailat al-Qadr 2017"
             ]
  , examples (datetimeHoliday (2018, 6, 11, 0, 0, 0) Day "Lailat al-Qadr")
             [ "laylat al-qadr 2018"
             , "die Nacht der Allmacht 2018"
             , "Laylat al-Qadr 2018"
             , "Lailat al-Qadr 2018"
             ]
  , examples (datetimeHoliday (2018, 9, 11, 0, 0, 0) Day "Islamisches Neujahr")
             [ "Islamisches Neujahr 2018"
             , "Amun Jadid 2018"
             ]
  , examples (datetimeHoliday (2017, 9, 30, 0, 0, 0) Day "Aschura")
             [ "Aschura-Tag 2017"
             , "Aschura 2017"
             , "Ashura 2017"
             ]
  , examples (datetimeHoliday (2018, 1, 30, 0, 0, 0) Day "Tu biSchevat")
             [ "Tu BiShvat 2018"
             , "Tu biSchevat 2018"
             ]
  , examples (datetimeHoliday (2017, 6, 23, 0, 0, 0) Day "Jumu'atul-Wida")
             [ "Jamat Ul-Vida 2017"
             , "Jumu'atul-Wida 2017"
             ]
  , examples (datetimeHoliday (2018, 6, 8, 0, 0, 0) Day "Jumu'atul-Wida")
             [ "Jamat Ul-Vida 2018"
             , "Jumu'atul-Wida 2018"
             ]
  , examples (datetimeHoliday (2018, 4, 13, 0, 0, 0) Day "Isra and Mi'raj")
             [ "isra and mi'raj 2018"
             , "Aufstieg des Propheten 2018"
             ]
  , examples (datetimeHoliday (2019, 4, 3, 0, 0, 0) Day "Isra and Mi'raj")
             [ "Die Nachtreise 2019"
             , "Aufstieg in den Himmel 2019"
             ]
  , examples (datetimeIntervalHoliday ((1950, 6, 17, 0, 0, 0), (1950, 7, 16, 0, 0, 0)) Day "Ramadan")
             [ "Ramadan 1950"
             ]
  , examples (datetimeIntervalHoliday ((1977, 8, 15, 0, 0, 0), (1977, 9, 14, 0, 0, 0)) Day "Ramadan")
             [ "Ramadan 1977"
             ]
  , examples (datetimeIntervalHoliday ((2018, 5, 16, 0, 0, 0), (2018, 6, 15, 0, 0, 0)) Day "Ramadan")
             [ "Ramadan 2018"
             ]
  , examples (datetimeIntervalHoliday ((2034, 11, 12, 0, 0, 0), (2034, 12, 12, 0, 0, 0)) Day "Ramadan")
             [ "Ramadan 2034"
             ]
  , examples (datetimeIntervalHoliday ((2046, 7, 5, 0, 0, 0), (2046, 8, 4, 0, 0, 0)) Day "Ramadan")
             [ "Ramadan 2046"
             ]
  , examples (datetimeIntervalHoliday ((2050, 5, 22, 0, 0, 0), (2050, 6, 21, 0, 0, 0)) Day "Ramadan")
             [ "Ramadan 2050"
             ]
  , examples (datetimeHoliday (2017, 10, 17, 0, 0, 0) Day "Dhanteras")
             [ "Dhanatrayodashi 2017"
             ]
  , examples (datetimeHoliday (2019, 10, 25, 0, 0, 0) Day "Dhanteras")
             [ "Dhanteras 2019"
             ]
  , examples (datetimeHoliday (2019, 10, 26, 0, 0, 0) Day "Naraka Chaturdashi")
             [ "kali chaudas 2019"
             , "choti diwali 2019"
             ]
  , examples (datetimeHoliday (2019, 10, 27, 0, 0, 0) Day "Diwali")
             [ "diwali 2019"
             , "Deepavali 2019"
             , "Lakshmi Puja 2019"
             ]
  , examples (datetimeHoliday (2019, 10, 29, 0, 0, 0) Day "Bhai Dooj")
             [ "bhai dooj 2019"
             ]
  , examples (datetimeHoliday (2019, 11, 2, 0, 0, 0) Day "Chhath")
             [ "chhath 2019"
             , "dala puja 2019"
             , "Surya Shashthi 2019"
             ]
  , examples (datetimeHoliday (2021, 10, 14, 0, 0, 0) Day "Maha Navami")
             [ "Maha Navami 2021"
             ]
  , examples (datetimeHoliday (2021, 10, 12, 0, 0, 0) Day "Maha Saptami")
             [ "Maha Saptami 2021"
             ]
  , examples (datetimeHoliday (2018, 10, 18, 0, 0, 0) Day "Vijayadashami")
             [ "Dussehra 2018"
             , "vijayadashami 2018"
             ]
  , examples (datetimeIntervalHoliday ((2018, 10, 9, 0, 0, 0), (2018, 10, 19, 0, 0, 0)) Day "Navaratri")
             [ "navaratri 2018"
             , "durga puja 2018"
             ]
  , examples (datetimeHoliday (2018, 10, 27, 0, 0, 0) Day "Karva Chauth")
             [ "karva chauth 2018"
             , "karva chauth 2018"
             ]
  , examples (datetimeHoliday (2018, 8, 26, 0, 0, 0) Day "Raksha Bandhan")
             [ "rakhi 2018"
             ]
  , examples (datetimeHoliday (2020, 4, 6, 0, 0, 0) Day "Mahavir Jayanti")
             [ "mahavir jayanti 2020"
             , "mahaveer janma kalyanak 2020"
             ]
  , examples (datetimeHoliday (2020, 2, 21, 0, 0, 0) Day "Maha Shivaratri")
             [ "maha shivaratri 2020"
             ]
  , examples (datetimeHoliday (2018, 2, 10, 0, 0, 0) Day "Dayananda Saraswati Jayanti")
             [ "saraswati jayanti 2018"
             ]
  , examples (datetimeHoliday (2018, 1, 14, 0, 0, 0) Day "Thai Pongal")
             [ "pongal 2018"
             , "makara sankranthi 2018"
             ]
  , examples (datetimeHoliday (2018, 1, 13, 0, 0, 0) Day "Boghi")
             [ "bogi pandigai 2018"
             ]
  , examples (datetimeHoliday (2018, 1, 15, 0, 0, 0) Day "Mattu Pongal")
             [ "maattu pongal 2018"
             ]
  , examples (datetimeHoliday (2018, 1, 16, 0, 0, 0) Day "Kaanum Pongal")
             [ "kaanum pongal 2018"
             , "kanni pongal 2018"
             ]
  , examples (datetimeHoliday (2019, 1, 15, 0, 0, 0) Day "Thai Pongal")
             [ "makar sankranti 2019"
             , "maghi 2019"
             ]
  , examples (datetimeHoliday (2018, 4, 14, 0, 0, 0) Day "Vaisakhi")
             [ "Vaisakhi 2018"
             , "baisakhi 2018"
             , "Vasakhi 2018"
             , "vaishakhi 2018"
             ]
  , examples (datetimeHoliday (2018, 8, 24, 0, 0, 0) Day "Thiru Onam")
             [ "onam 2018"
             , "Thiru Onam 2018"
             , "Thiruvonam 2018"
             ]
  , examples (datetimeHoliday (2019, 2, 10, 0, 0, 0) Day "Vasant Panchami")
             [ "vasant panchami 2019"
             , "basant panchami 2019"
             ]
  , examples (datetimeHoliday (2019, 3, 20, 0, 0, 0) Day "Holika Dahan")
             [ "chhoti holi 2019"
             , "holika dahan 2019"
             , "kamudu pyre 2019"
             ]
  , examples (datetimeHoliday (2019, 8, 23, 0, 0, 0) Day "Krishna Janmashtami")
             [ "krishna janmashtami 2019"
             , "gokulashtami 2019"
             ]
  , examples (datetimeHoliday (2019, 3, 21, 0, 0, 0) Day "Holi")
             [ "holi 2019"
             , "dhulandi 2019"
             , "phagwah 2019"
             ]
  , examples (datetimeHoliday (2018, 8, 17, 0, 0, 0) Day "Parsi Neujahr")
             [ "Parsi Neujahr 2018"
             , "Jamshedi Navroz 2018"
             ]
  , examples (datetimeHoliday (2022, 8, 16, 0, 0, 0) Day "Parsi Neujahr")
             [ "jamshedi Navroz 2022"
             , "Parsi Neujahr 2022"
             ]
  , examples (datetimeIntervalHoliday ((2013, 4, 26, 0, 0, 0), (2013, 4, 29, 0, 0, 0)) Day "Global Youth Service-Tag")
             [ "GYSD 2013"
             , "Global Youth Service-Tag"
             ]
  , examples (datetimeHoliday (2013, 5, 24, 0, 0, 0) Day "Vesak")
             [ "vesak"
             , "vaisakha"
             , "Buddha-Tag"
             , "Buddha Purnima"
             , "Wesakfest"
             ]
  , examples (datetimeIntervalHoliday ((2013, 3, 23, 20, 30, 0), (2013, 3, 23, 21, 31, 0)) Minute "Earth Hour")
             [ "Earth Hour"
             , "Stunde der Erde"
             ]
  , examples (datetimeIntervalHoliday ((2016, 3, 19, 20, 30, 0), (2016, 3, 19, 21, 31, 0)) Minute "Earth Hour")
             [ "Earth Hour 2016"
             , "Stunde der Erde 2016"
             ]
  , examples (datetimeHoliday (2013, 2, 23, 0, 0, 0) Day "Purim")
             [ "purim"
             ]
  , examples (datetimeHoliday (2013, 2, 24, 0, 0, 0) Day "Shushan Purim")
             [ "Shushan Purim"
             ]
  , examples (datetimeHoliday (2014, 1, 7, 0, 0, 0) Day "Guru Gobind Singh Jayanti")
             [ "Guru Gobind Singh Geburtstag"
             , "Guru Gobind Singh Jayanti 2014"
             , "Guru Govind Singh Jayanti"
             ]
  , examples (datetimeHoliday (2018, 4, 27, 0, 0, 0) Day "KÃ¶nigstag")
             [ "Koningsdag 2018"
             , "kÃ¶nigstag 2018"
             ]
  , examples (datetimeHoliday (2014, 4, 26, 0, 0, 0) Day "KÃ¶nigstag")
             [ "Koningsdag 2014"
             ]
  , examples (datetimeHoliday (2018, 5, 9, 0, 0, 0) Day "Rabindra Jayanti")
             [ "Rabindra Jayanti 2018"
             , "Rabindranath Jayanti 2018"
             ]
  , examples (datetimeHoliday (2019, 5, 9, 0, 0, 0) Day "Rabindra Jayanti")
             [ "Rabindra Jayanti 2019"
             , "Rabindranath Jayanti 2019"
             ]
  , examples (datetimeHoliday (2018, 1, 31, 0, 0, 0) Day "Guru Ravidass Jayanti")
             [ "Guru Ravidas Jayanti 2018"
             , "Guru Ravidass Geburtstag 2018"
             , "Guru Ravidass Jayanti 2018"
             ]
  , examples (datetimeHoliday (2019, 2, 19, 0, 0, 0) Day "Guru Ravidass Jayanti")
             [ "Guru Ravidass Jayanti 2019"
             , "Guru Ravidas Geburtstag 2019"
             ]
  , examples (datetimeHoliday (2019, 10, 13, 0, 0, 0) Day "Pargat Diwas")
             [ "Valmiki Jayanti 2019"
             , "Pargat Diwas 2019"
             ]
  , examples (datetimeHoliday (2018, 10, 24, 0, 0, 0) Day "Pargat Diwas")
             [ "Maharishi Valmiki Jayanti 2018"
             , "Pargat Diwas 2018"
             ]
  , examples (datetimeHoliday (2018, 5, 10, 0, 0, 0) Day "Christi Himmelfahrt")
             [ "Christi Himmelfahrt 2018"
             , "Himmelfahrt 2018"
             , "Himmelfahrtstag 2018"
             ]
  , examples (datetimeHoliday (2018, 2, 14, 0, 0, 0) Day "Aschermittwoch")
             [ "Aschermittwoch 2018"
             , "Aschertag 2018"
             , "Aschetag 2018"
             ]
  , examples (datetimeHoliday (2018, 2, 19, 0, 0, 0) Day "Aschermontag")
             [ "Aschermontag 2018"
             , "Reiner Montag 2018"
             , "Sauberer Montag 2018"
             ]
  , examples (datetimeHoliday (2018, 5, 31, 0, 0, 0) Day "Corpus Christi")
             [ "Corpus Christi 2018"
             , "Fronleichnam 2018"
             ]
  , examples (datetimeHoliday (2018, 4, 2, 0, 0, 0) Day "Ostermontag")
             [ "Ostermontag 2018"
             ]
  , examples (datetimeHoliday (2018, 4, 1, 0, 0, 0) Day "Ostersonntag")
             [ "Ostersonntag 2018"
             ]
  , examples (datetimeHoliday (2018, 11, 8, 0, 0, 0) Day "Govardhan Puja")
             [ "Govardhan Puja 2018"
             , "Annakut 2018"
             ]
  , examples (datetimeHoliday (2018, 3, 30, 0, 0, 0) Day "Karfreitag")
             [ "Karfreitag 2018"
             , "Stiller Freitag 2018"
             , "Hoher Freitag 2018"
             ]
  , examples (datetimeHoliday (2018, 3, 31, 0, 0, 0) Day "Karsamstag")
             [ "Karsamstag 2018"
             , "Stiller Samstag 2018"
             , "Karsonnabend 2018"
             ]
  , examples (datetimeHoliday (2018, 3, 31, 0, 0, 0) Day "Lazarus-Samstag")
             [ "Lazarus-Samstag 2018"
             , "Lazarus Samstag 2018"
             ]
  , examples (datetimeHoliday (2018, 3, 29, 0, 0, 0) Day "GrÃ¼ndonnerstag")
             [ "GrÃ¼ndonnerstag 2018"
             , "Hoher Donnerstag 2018"
             , "Heiliger Donnerstag 2018"
             , "WeiÃŸer Donnerstag 2018"
             , "Palmdonnerstag 2018"
             ]
  , examples (datetimeHoliday (2018, 4, 9, 0, 0, 0) Day "Orthodoxer Ostermontag")
             [ "Orthodoxer Ostermontag 2018"
             ]
  , examples (datetimeHoliday (2018, 4, 8, 0, 0, 0) Day "Orthodoxer Ostersonntag")
             [ "Orthodoxer Ostersonntag 2018"
             ]
  , examples (datetimeHoliday (2018, 4, 7, 0, 0, 0) Day "Orthodoxer Karsamstag")
             [ "Orthodoxer Karsamstag 2018"
             ]
  , examples (datetimeHoliday (2018, 4, 6, 0, 0, 0) Day "Orthodoxer Karfreitag")
             [ "Orthodoxer Karfreitag 2018"
             ]
  , examples (datetimeHoliday (2018, 4, 1, 0, 0, 0) Day "Orthodoxer Palmsonntag")
             [ "Orthodoxer Palmsonntag 2018"
             ]
  , examples (datetimeHoliday (2018, 3, 25, 0, 0, 0) Day "Palmsonntag")
             [ "Palmsonntag 2018"
             ]
  , examples (datetimeHoliday (2018, 5, 20, 0, 0, 0) Day "Pfingsten")
             [ "Pfingsten 2018"
             , "pentecost 2018"
             ]
  , examples (datetimeHoliday (2018, 2, 13, 0, 0, 0) Day "Fastnacht")
             [ "Fastnacht 2018"
             , "mardi gras 2018"
             , "Fastnachtsdienstag 2018"
             ]
  , examples (datetimeHoliday (2018, 5, 27, 0, 0, 0) Day "Dreifaltigkeitssonntag")
             [ "Dreifaltigkeitssonntag 2018"
             , "Dreifaltigkeitsfest 2018"
             , "Trinitatis 2018"
             , "Goldener Sonntag 2018"
             ]
  , examples (datetimeHoliday (2018, 5, 21, 0, 0, 0) Day "Pfingstmontag")
             [ "Pfingstmontag 2018"
             , "Pentecost Montag 2018"
             ]
  , examples (datetimeIntervalHoliday ((2018, 2, 19, 0, 0, 0), (2018, 3, 31, 0, 0, 0)) Day "GroÃŸe Fastenzeit")
             [ "GroÃŸe Fastenzeit 2018"
             ]
  , examples (datetimeIntervalHoliday ((2018, 2, 14, 0, 0, 0), (2018, 4, 1, 0, 0, 0)) Day "Fastenzeit")
             [ "Fastenzeit 2018"
             ]
  ]