Skip to content

Commit

Permalink
Fix "first Friday of next month" returning Friday of next week (#417)
Browse files Browse the repository at this point in the history
Fixing resolution in C# and JS.
  • Loading branch information
AniChikage authored and tellarin committed Mar 21, 2018
1 parent 529b0ec commit 59bad26
Show file tree
Hide file tree
Showing 3 changed files with 252 additions and 129 deletions.
262 changes: 134 additions & 128 deletions .NET/Microsoft.Recognizers.Text.DateTime/Parsers/BaseDateParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,23 @@ public DateTimeParseResult Parse(ExtractResult er, DateObject reference)
innerResult = ParseWeekdayOfMonth(er.Text, referenceDate);
}

if (!innerResult.Success)
{
innerResult = ParseDurationWithAgoAndLater(er.Text, referenceDate);
if (!innerResult.Success)
{
innerResult = ParseDurationWithAgoAndLater(er.Text, referenceDate);
}

// NumberWithMonth must be the second last one, because it only need to find a number and a month to get a "success"
if (!innerResult.Success)
{
innerResult = ParseNumberWithMonth(er.Text, referenceDate);
}

// SingleNumber last one
}

// SingleNumber last one
if (!innerResult.Success)
{
innerResult = ParseSingleNumber(er.Text, referenceDate);
}

}

if (innerResult.Success)
{
innerResult.FutureResolution = new Dictionary<string, string>
Expand Down Expand Up @@ -137,13 +137,13 @@ private DateTimeResolutionResult ParseImplicitDate(string text, DateObject refer
if (DateObject.TryParse(tryStr, out DateObject temp))
{
futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);

pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);

if (futureDate < referenceDate)
{
futureDate = futureDate.AddMonths(+1);
}

}

if (pastDate >= referenceDate)
{
pastDate = pastDate.AddMonths(-1);
Expand Down Expand Up @@ -272,47 +272,47 @@ private DateTimeResolutionResult ParseImplicitDate(string text, DateObject refer

day = Convert.ToInt32((double)(this.config.NumberParser.Parse(er).Value ?? 0));

ret.Timex = FormatUtil.LuisDate(-1, -1, day);

DateObject futureDate;
var tryStr = FormatUtil.LuisDate(year, month, day);
if (DateObject.TryParse(tryStr, out DateObject temp))
{
futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
}
else
{
futureDate = DateObject.MinValue.SafeCreateFromValue(year, month + 1, day);
}

ret.FutureValue = futureDate;
ret.PastValue = ret.FutureValue;
ret.Success = true;

ret.Timex = FormatUtil.LuisDate(-1, -1, day);

DateObject futureDate;
var tryStr = FormatUtil.LuisDate(year, month, day);
if (DateObject.TryParse(tryStr, out DateObject temp))
{
futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
}
else
{
futureDate = DateObject.MinValue.SafeCreateFromValue(year, month + 1, day);
}

ret.FutureValue = futureDate;
ret.PastValue = ret.FutureValue;
ret.Success = true;

return ret;
}

// handling cases like 'Thursday the 21st', which both 'Thursday' and '21st' refer to a same date
match = this.config.WeekDayAndDayOfMothRegex.Match(text);
if (match.Success)
{
int month = referenceDate.Month, year = referenceDate.Year;
// create a extract result which content ordinal string of text
ExtractResult erTmp = new ExtractResult();
erTmp.Text = match.Groups["DayOfMonth"].Value.ToString();
erTmp.Start = match.Groups["DayOfMonth"].Index;
erTmp.Length = match.Groups["DayOfMonth"].Length;

// parse the day in text into number
var day = Convert.ToInt32((double)(this.config.NumberParser.Parse(erTmp).Value ?? 0));

// the validity of the phrase is guaranteed in the Date Extractor
ret.Timex = FormatUtil.LuisDate(year, month, day);
ret.FutureValue = new DateObject(year, month, day); ;
ret.PastValue = new DateObject(year, month, day); ;
ret.Success = true;

return ret;
// handling cases like 'Thursday the 21st', which both 'Thursday' and '21st' refer to a same date
match = this.config.WeekDayAndDayOfMothRegex.Match(text);
if (match.Success)
{
int month = referenceDate.Month, year = referenceDate.Year;
// create a extract result which content ordinal string of text
ExtractResult erTmp = new ExtractResult();
erTmp.Text = match.Groups["DayOfMonth"].Value.ToString();
erTmp.Start = match.Groups["DayOfMonth"].Index;
erTmp.Length = match.Groups["DayOfMonth"].Length;

// parse the day in text into number
var day = Convert.ToInt32((double)(this.config.NumberParser.Parse(erTmp).Value ?? 0));

// the validity of the phrase is guaranteed in the Date Extractor
ret.Timex = FormatUtil.LuisDate(year, month, day);
ret.FutureValue = new DateObject(year, month, day); ;
ret.PastValue = new DateObject(year, month, day); ;
ret.Success = true;

return ret;
}

return ret;
Expand All @@ -325,7 +325,7 @@ private DateTimeResolutionResult ParseNumberWithMonth(string text, DateObject re
var ret = new DateTimeResolutionResult();

var trimedText = text.Trim().ToLower();
int month = 0, day = 0, year = referenceDate.Year;
int month = 0, day = 0, year = referenceDate.Year;
bool ambiguous = true;

var er = this.config.OrdinalExtractor.Extract(trimedText);
Expand All @@ -342,98 +342,98 @@ private DateTimeResolutionResult ParseNumberWithMonth(string text, DateObject re
var num = Convert.ToInt32((double)(this.config.NumberParser.Parse(er[0]).Value ?? 0));

var match = this.config.MonthRegex.Match(trimedText);
if (match.Success)
{
month = this.config.MonthOfYear[match.Value.Trim()];
day = num;

var suffix = trimedText.Substring(er[0].Start + er[0].Length ?? 0);
var matchYear = this.config.YearSuffix.Match(suffix);
if (matchYear.Success)
{
year = ((BaseDateExtractor)this.config.DateExtractor).GetYearFromText(matchYear);
if (year != Constants.InvalidYear)
{
ambiguous = false;
}
}
if (match.Success)
{
month = this.config.MonthOfYear[match.Value.Trim()];
day = num;

var suffix = trimedText.Substring(er[0].Start + er[0].Length ?? 0);
var matchYear = this.config.YearSuffix.Match(suffix);
if (matchYear.Success)
{
year = ((BaseDateExtractor)this.config.DateExtractor).GetYearFromText(matchYear);
if (year != Constants.InvalidYear)
{
ambiguous = false;
}
}
}

// handling relatived month
if (!match.Success)
{
{
match = this.config.RelativeMonthRegex.Match(trimedText);
if (match.Success)
{
var monthStr = match.Groups["order"].Value;
var swift = this.config.GetSwiftMonth(monthStr);
month = referenceDate.AddMonths(swift).Month;
year = referenceDate.AddMonths(swift).Year;
day = num;
ambiguous = false;
if (match.Success)
{
var monthStr = match.Groups["order"].Value;
var swift = this.config.GetSwiftMonth(monthStr);
month = referenceDate.AddMonths(swift).Month;
year = referenceDate.AddMonths(swift).Year;
day = num;
ambiguous = false;
}
}

// handling casesd like 'second Sunday'
if (!match.Success)
{
{
match = this.config.WeekDayRegex.Match(trimedText);
if (match.Success)
{
month = referenceDate.Month;
// resolve the date of wanted week day
var wantedWeekDay = this.config.DayOfWeek[match.Groups["weekday"].Value];
var firstDate = DateObject.MinValue.SafeCreateFromValue(referenceDate.Year, referenceDate.Month, 1);
var firstWeekDay = (int)firstDate.DayOfWeek;
var firstWantedWeekDay = firstDate.AddDays(wantedWeekDay > firstWeekDay ? wantedWeekDay - firstWeekDay : wantedWeekDay - firstWeekDay + 7);
var AnswerDay = firstWantedWeekDay.Day + ((num - 1) * 7);
day = AnswerDay;
ambiguous = false;
if (match.Success)
{
month = referenceDate.Month;
// resolve the date of wanted week day
var wantedWeekDay = this.config.DayOfWeek[match.Groups["weekday"].Value];
var firstDate = DateObject.MinValue.SafeCreateFromValue(referenceDate.Year, referenceDate.Month, 1);
var firstWeekDay = (int)firstDate.DayOfWeek;
var firstWantedWeekDay = firstDate.AddDays(wantedWeekDay > firstWeekDay ? wantedWeekDay - firstWeekDay : wantedWeekDay - firstWeekDay + 7);
var AnswerDay = firstWantedWeekDay.Day + ((num - 1) * 7);
day = AnswerDay;
ambiguous = false;
}
}

if (!match.Success)
{
return ret;
if (!match.Success)
{
return ret;
}

// for LUIS format value string
var futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
var pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);

if (ambiguous)
{
ret.Timex = FormatUtil.LuisDate(-1, month, day);
if (futureDate < referenceDate)
{
futureDate = futureDate.AddYears(+1);
}

if (pastDate >= referenceDate)
{
pastDate = pastDate.AddYears(-1);
}
}
else
{
ret.Timex = FormatUtil.LuisDate(year, month, day);
var pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);

if (ambiguous)
{
ret.Timex = FormatUtil.LuisDate(-1, month, day);
if (futureDate < referenceDate)
{
futureDate = futureDate.AddYears(+1);
}

if (pastDate >= referenceDate)
{
pastDate = pastDate.AddYears(-1);
}
}
else
{
ret.Timex = FormatUtil.LuisDate(year, month, day);
}

ret.FutureValue = futureDate;
ret.PastValue = pastDate;
ret.Success = true;

return ret;
}

// handle cases like "the 27th". In the extractor, only the unmatched weekday and date will output this date.
}

// handle cases like "the 27th". In the extractor, only the unmatched weekday and date will output this date.
private DateTimeResolutionResult ParseSingleNumber(string text, DateObject referenceDate)
{
var ret = new DateTimeResolutionResult();

var trimedText = text.Trim().ToLower();
int month = referenceDate.Month, day = 0, year = referenceDate.Year;

int month = referenceDate.Month, day = 0, year = referenceDate.Year;

var er = this.config.OrdinalExtractor.Extract(trimedText);
if (er.Count == 0)
{
Expand All @@ -449,9 +449,9 @@ private DateTimeResolutionResult ParseSingleNumber(string text, DateObject refer

// for LUIS format value string
ret.Timex = FormatUtil.LuisDate(-1, -1, day);
var pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
var futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);

var pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
var futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);

if (!futureDate.Equals(DateObject.MinValue) && futureDate < referenceDate)
{
futureDate = futureDate.AddMonths(1);
Expand All @@ -467,9 +467,9 @@ private DateTimeResolutionResult ParseSingleNumber(string text, DateObject refer
ret.Success = true;

return ret;
}

// Handle cases like "two days ago"
}

// Handle cases like "two days ago"
private DateTimeResolutionResult ParseDurationWithAgoAndLater(string text, DateObject referenceDate)
{

Expand Down Expand Up @@ -519,13 +519,13 @@ private DateTimeResolutionResult Match2Date(Match match, DateObject referenceDat
}

var futureDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);
var pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);

var pastDate = DateObject.MinValue.SafeCreateFromValue(year, month, day);

if (noYear && futureDate < referenceDate)
{
futureDate = futureDate.AddYears(+1);
}

}

if (noYear && pastDate >= referenceDate)
{
pastDate = pastDate.AddYears(-1);
Expand Down Expand Up @@ -563,8 +563,8 @@ private DateTimeResolutionResult ParseWeekdayOfMonth(string text, DateObject ref
else
{
cardinal = this.config.CardinalMap[cardinalStr];
}

}

var weekday = this.config.DayOfWeek[weekdayStr];
int month;
if (string.IsNullOrEmpty(monthStr))
Expand Down Expand Up @@ -597,8 +597,8 @@ private DateTimeResolutionResult ParseWeekdayOfMonth(string text, DateObject ref
{
futureDate = futureDate.AddDays(-7);
}
}

}

if (noYear && pastDate >= referenceDate)
{
pastDate = ComputeDate(cardinal, weekday, month, year - 1);
Expand All @@ -621,13 +621,19 @@ private static DateObject ComputeDate(int cardinal, int weekday, int month, int
{
var firstDay = DateObject.MinValue.SafeCreateFromValue(year, month, 1);
var firstWeekday = firstDay.This((DayOfWeek)weekday);
int dayOfWeekOfFirstDay = (int)firstDay.DayOfWeek;

if (weekday == 0)
{
weekday = 7;
}

if (weekday < (int)firstDay.DayOfWeek)
if (dayOfWeekOfFirstDay == 0)
{
dayOfWeekOfFirstDay = 7;
}

if (weekday < dayOfWeekOfFirstDay)
{
firstWeekday = firstDay.Next((DayOfWeek)weekday);
}
Expand Down
Loading

0 comments on commit 59bad26

Please sign in to comment.