Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DUCK] 节日更新 & 序列时间重做,扩展适用范围 #232

Merged
merged 2 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ object Types {

def and(ps: Predicate*): Predicate = {
case token: Token =>
ps.forall(p => p.isDefinedAt(token) && p(token))
val result = ps.forall(p => p.isDefinedAt(token) && p(token))
result
}

def or(ps: Predicate*): Predicate = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,17 @@ trait Rules extends DimRules {
// else if (td1.timeGrain == Day && td2.timeGrain == Hour) None
else {
val hint =
if (td1.timeGrain == Year && td2.hint == MonthOnly) YearMonth
if (td1.timePred.isInstanceOf[SequencePredicate]) Sequence
else if (td1.timeGrain == Year && td2.hint == MonthOnly) YearMonth
else Intersect
// 10号八点,需要去掉AMPM (今天是10号9点时,不应再出20点)
// 今天8点,需要根据当前时间是出8/20点
val _td2 = if (td1.hint == Hint.RecentNominal) td2 else removeAMPM(td2)
val _td1 = FuzzyDayIntervals.enlarge(td1, options.timeOptions.beforeEndOfInterval)
val td = intersect(_td1, _td2).map(_.copy(hint = hint))
tt(td)
hint match {
case Sequence => sequenceProd(_td1, _td2)
case _ => tt(intersect(_td1, _td2).map(_.copy(hint = hint)))
}
}
}
)
Expand Down Expand Up @@ -533,7 +536,7 @@ trait Rules extends DimRules {
case _ =>
if (td1.timeGrain >= td2.timeGrain) {
val cal = calendar(td1, td2)
if (td1.timeGrain > td2.timeGrain && recentHint(td2.hint)) {
if (td1.timeGrain > td2.timeGrain && (td1.timePred.isInstanceOf[SequencePredicate] || recentHint(td2.hint))) {
tt(
TimeData(
ReplacePartPredicate(td1, td2),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,10 +355,11 @@ object Types {
}

def withYear(y: Int): DuckDateTime = this.copy(date = date.withYear(y))

def withMonth(m: Int): DuckDateTime = this.copy(date = date.withMonth(m))

def withDayOfMonth(d: Int): DuckDateTime = this.copy(date = date.withDayOfMonth(d))
def withHour(h: Int): DuckDateTime = this.copy(time = time.withHour(h))
def withMinute(m: Int): DuckDateTime = this.copy(time = time.withMinute(m))
def withSecond(s: Int): DuckDateTime = this.copy(time = time.withSecond(s))

def to(calendar: Calendar): DuckDateTime = {
calendar match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class LocalHolidayProvider extends HolidayProvider {
val rulePeriodicHolidays: List[(Token, String, String)] = mkRuleHolidays(
// Fixed dates, year over year
List(
(monthDay(1, 10), "中国人民警察节", "中国人民警察节|人民警察节|中国警察节|警察节"),
(monthDay(2, 7), "国际声援南非日", "国际声援南非日|声援南非日"),
(monthDay(2, 15), "中国12亿人口日", "中国12亿人口日"),
(monthDay(2, 21), "反对殖民主义斗争日", "反对殖民主义斗争日|反对殖民制度斗争日"),
Expand Down Expand Up @@ -140,7 +141,7 @@ class LocalHolidayProvider extends HolidayProvider {
(monthDay(12, 12), "双十二", "双十二|双十二电商节"),
(monthDay(12, 12), "西安事变纪念日", "西安事变纪念日"),
(monthDay(12, 13), "南京大屠杀纪念日", "南京大屠杀纪念日"),
(monthDay(12, 13), "南京大屠杀死难者国家公祭日", "南京大屠杀死难者国家公祭日"),
(monthDay(12, 13), "南京大屠杀死难者国家公祭日", "南京大屠杀死难者国家公祭日|国家公祭日"),
(monthDay(12, 2), "全国交通安全日", "全国交通安全日|交通安全日"),
(monthDay(12, 20), "澳门回归纪念日", "澳门回归纪念日|澳门回归日"),
(monthDay(12, 24), "平安夜", "平安夜"),
Expand All @@ -160,7 +161,7 @@ class LocalHolidayProvider extends HolidayProvider {
(monthDay(3, 1), "国际海豹日", "国际海豹日|海豹日"),
(monthDay(3, 12), "植树节", "中国植树节|植树节"),
(monthDay(3, 14), "白色情人节", "白色情人节"),
(monthDay(3, 15), "国际消费者权益日", "国际消费者权益日|世界消费者权益日|消费者权益日|三一五"),
(monthDay(3, 15), "国际消费者权益日", "国际消费者权益日|世界消费者权益日|消费者权益日|三一五|消费者日"),
(monthDay(3, 17), "中国国医节", "中国国医节|国医节"),
(monthDay(3, 17), "圣帕特里克节", "圣帕特里克节"),
(monthDay(3, 21), "世界森林日", "世界森林日|森林日"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,26 +191,68 @@ package object time {
t1 <- resolveTimeData(t, td1)
t2 <- resolveTimeData(t, td2)
} yield {
val to = (td1.timeGrain, td2.timeGrain) match {
case (Year, Month) => t2.copy(start = t2.start.withYear(t1.start.year))
case (Year, Day) => t2.copy(start = t2.start.withYear(t1.start.year))
case (Month, Day) =>
t2.copy(start = t2.start.withMonth(t1.start.month).withYear(t1.start.year))
case (Day, NoGrain) => // 今天现在
t2.copy(
start = t2.start
.withYear(t1.start.year)
.withMonth(t1.start.month)
.withDayOfMonth(t1.start.dayOfMonth)
)
case _ => null
}
val to =
if (td2.timePred.maxGrain.nonEmpty && td1.timeGrain > td2.timePred.maxGrain.get) {
copyGrain(Year, td2.timePred.maxGrain.get, t1, t2)
} else {
(td1.timeGrain, td2.timeGrain) match {
case (Year, Month) => t2.copy(start = t2.start.withYear(t1.start.year))
case (Year, Day) => t2.copy(start = t2.start.withYear(t1.start.year))
case (Month, Day) =>
t2.copy(start = t2.start.withMonth(t1.start.month).withYear(t1.start.year))
case (Day, NoGrain) => // 今天现在
t2.copy(
start = t2.start
.withYear(t1.start.year)
.withMonth(t1.start.month)
.withDayOfMonth(t1.start.dayOfMonth)
)
case _ => null
}
}
if (to == null) EmptySeries
else if (to.start.isBefore(t.start)) (Stream(to), Stream.empty)
else (Stream.empty, Stream(to))
}).getOrElse(EmptySeries)
}

def copy(grain: Grain, t1: DuckDateTime, t2: DuckDateTime): DuckDateTime = {
grain match {
case Grain.Minute => t2.withMinute(t1.minute)
case Grain.Hour => t2.withHour(t1.hour)
case Grain.Day => t2.withDayOfMonth(t1.dayOfMonth)
case Grain.Month => t2.withMonth(t1.month)
case Grain.Year => t2.withYear(t1.year)
case _ => t2
}
}

@scala.annotation.tailrec
def copyGrain(thisGrain: Grain, stopGrain: Grain, t1: TimeObject, t2: TimeObject): TimeObject = {
if (t1.start.date.isInstanceOf[LunarDate]) {
if (thisGrain >= Day && stopGrain < Day) {
val start = t2.start.copy(date = t1.start.date)
val end =
if (t2.end.isEmpty) None
else if (t1.end.isEmpty) t2.end
else t2.end.map(d => d.copy(date = t1.start.date))
val t = t2.copy(start = start, end = end)
copyGrain(Hour, stopGrain, t1, t)
} else t2
} else if (thisGrain > stopGrain) {
val start = copy(thisGrain, t1.start, t2.start)
val end =
if (t2.end.isEmpty) None
else if (t1.end.isEmpty) t2.end
else t2.end.map(copy(thisGrain, t1.end.get, _))
val t = t2.copy(start = start, end = end)
thisGrain.finer() match {
case Some(g) => copyGrain(g, stopGrain, t1, t)
case _ => t2
}
} else t2
}

@scala.annotation.tailrec
def runSequencePredicate(list: List[TimeData])(t: TimeObject,
context: TimeContext): PastFutureTime = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ object Examples extends DimExamples {
(y(2013), List("今年", "这一年")),
(y(2014), List("明年", "下一年")),
(ymd(2013, 12, 30, calendar = Lunar(false)).copy(holiday = "除夕"), List("今年除夕", "大年三十", "年三十")),
(ymdhms(2013, 12, 30, 20, grain=Hour, calendar = Lunar(false)), List("除夕晚上八点")),
(ymd(2021, 12, 29, calendar = Lunar(false), holiday = "除夕"), List("2021年除夕")), // 2021年没有大年三十
(
localDateTimeInterval(
Expand Down Expand Up @@ -148,8 +149,8 @@ object Examples extends DimExamples {
val times = List(
(hms(4, 30, 0), List("现在", "此时", "此刻", "当前", "4:30:00", "04点30分0秒")),
(hm(15, 15), List("下午三点十五", "下午3:15", "15:15", "3:15pm", "3:15p.m", "下午三点一刻", "下午的三点一刻")),
(yMdHms(d=13, H=2, grain = Hour), List("晚上两点")),
(yMdHms(d=12, H=17, grain = Hour), List("晚上五点")),
(ymdhms(d=13, h=2, grain = Hour), List("晚上两点")),
(ymdhms(d=12, h=17, grain = Hour), List("晚上五点")),
(hm(16, 40), List("十六时四十分", "十六点四十")),
(hm(6, 10), List("六点十分", "六点一十")),
(hms(4, 33, 0), List("过三分钟")),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.xiaomi.duckling.dimension.time.helper

import java.time.{LocalDateTime, LocalTime}
import java.time.{LocalDate, LocalDateTime, LocalTime}

import com.github.heqiao2010.lunar.LunarCalendar

Expand All @@ -10,6 +10,7 @@ import com.xiaomi.duckling.Types.{Context, ZoneCN}
import com.xiaomi.duckling.dimension.time.enums._
import com.xiaomi.duckling.dimension.time.enums.Grain._
import com.xiaomi.duckling.dimension.time.Types._
import com.xiaomi.duckling.ranking.Testing
import com.xiaomi.duckling.ranking.Testing.testContext

object TimeValueHelpers {
Expand Down Expand Up @@ -71,8 +72,12 @@ object TimeValueHelpers {

def md(m: Int, d: Int): TimeValue = ymd(2013, m, d)

def yMdHms(y: Int = 2013, M: Int = 2, d: Int = 12, H: Int = 0, m: Int = 0, s: Int = 0, grain: Grain): TimeValue = {
datetime(LocalDateTime.of(y, M, d, H, m, s), grain)
def ymdhms(y: Int = 2013, M: Int = 2, d: Int = 12, h: Int = 0, m: Int = 0, s: Int = 0, grain: Grain, calendar: Calendar = Solar, holiday: Option[String] = None): TimeValue = {
val date = calendar match {
case Solar => SolarDate(LocalDate.of(y, M, d))
case Lunar(leap) => LunarDate(new LunarCalendar(y, M, d, leap))
}
datetime(DuckDateTime(date, LocalTime.of(h, m, s), Testing.testContext.referenceTime.getZone), grain, holiday)
}

def datetimeInterval(dt1: DuckDateTime, dt2: DuckDateTime, g: Grain, holiday: Option[String] = None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@ object Examples extends DimExamples {
Hour)
), List("每个月五号的早上")),
(RepeatValue(DurationData(1, Month), start = ymd(m = 3, d = 5)), List("每个月的五号")),
(RepeatValue(DurationData(1, Month), start = yMdHms(M = 3, d = 2, H = 14, grain = Hour)), List("每月2号下午2点")),
(RepeatValue(DurationData(1, Month), start = ymdhms(M = 3, d = 2, h = 14, grain = Hour)), List("每月2号下午2点")),
(RepeatValue(DurationData(1, Week), start = (ymd(d = 13), Some(form.DayOfWeek))), List("每周三", "每个星期三")),
(RepeatValue(DurationData(1, Day), start = (h(8), Some(form.TimeOfDay(Some(8), false)))), List("每天上午八点", "每个上午八点")),
(RepeatValue(workdayType = NonWorkday), List("非工作日", "节假日")),
(RepeatValue(workdayType = Workday, start = (yMdHms(d = 13, H = 3, grain = Hour), Some(form.TimeOfDay(Some(3), false)))), List("工作日三点", "工作日每天三点", "每个工作日三点")),
(RepeatValue(workdayType = Workday, start = (ymdhms(d = 13, h = 3, grain = Hour), Some(form.TimeOfDay(Some(3), false)))), List("工作日三点", "工作日每天三点", "每个工作日三点")),
(RepeatValue(workdayType = Workday, start = (datetimeInterval(
new DuckDateTime(LocalDateTime.of(2013, 2, 12, 8, 0, 0)),
new DuckDateTime(LocalDateTime.of(2013, 2, 12, 12, 0, 0)),
Expand Down
Loading