Added year to opening hours parser

This commit is contained in:
crimean 2019-07-25 13:44:23 +03:00
parent 8c07e9a80f
commit 4d8fcc5238
2 changed files with 226 additions and 30 deletions

View file

@ -594,6 +594,14 @@ public class OpeningHoursParser {
*/
public boolean containsMonth(Calendar cal);
/**
* Check if the year of "cal" is part of this rule
*
* @param cal the time to check
* @return true if the year is part of the rule
*/
public boolean containsYear(Calendar cal);
/**
* @return true if the rule overlap to the next day
*/
@ -644,6 +652,14 @@ public class OpeningHoursParser {
*/
private boolean[] months = new boolean[12];
/**
* represents the list on which year / month it is open.
*/
private int[] firstYearMonths = null;
private int[] lastYearMonths = null;
private int fullYears = 0;
private int year = 0;
/**
* represents the list on which day it is open.
*/
@ -908,10 +924,29 @@ public class OpeningHoursParser {
*/
@Override
public boolean containsMonth(Calendar cal) {
int i = cal.get(Calendar.MONTH);
if (months[i]) {
int month = cal.get(Calendar.MONTH);
int year = cal.get(Calendar.YEAR);
return containsYear(cal) && months[month];
}
public boolean containsYear(Calendar cal) {
if (year == 0 && firstYearMonths == null) {
return true;
}
int month = cal.get(Calendar.MONTH);
int year = cal.get(Calendar.YEAR);
if (firstYearMonths != null && firstYearMonths[month] == year ||
lastYearMonths != null && lastYearMonths[month] == year ||
firstYearMonths == null && lastYearMonths == null && this.year == year) {
return true;
}
if (fullYears > 0 && this.year > 0) {
for (int i = 1; i <= fullYears; i++) {
if (this.year + i == year) {
return true;
}
}
}
return false;
}
@ -994,6 +1029,7 @@ public class OpeningHoursParser {
boolean dash = false;
boolean first = true;
int monthAdded = -1;
int dayAdded = -1;
int excludedMonthEnd = -1;
int excludedDayEnd = -1;
int excludedMonthStart = -1;
@ -1036,6 +1072,7 @@ public class OpeningHoursParser {
}
}
}
boolean yearAdded = false;
for (int month = 0; month < dayMonths.length; month++) {
for (int day = 0; day < dayMonths[month].length; day++) {
if (excludedDayStart != -1 && excludedDayEnd != -1) {
@ -1046,7 +1083,7 @@ public class OpeningHoursParser {
}
}
if (dayMonths[month][day]) {
if (day == 0 && dash) {
if (day == 0 && dash && dayMonths[month][1]) {
continue;
}
if (day > 0 && dayMonths[month][day - 1]
@ -1065,11 +1102,13 @@ public class OpeningHoursParser {
b.append(", ");
monthAdded = -1;
}
if (monthAdded != month) {
yearAdded = appendYearString(b, dash ? lastYearMonths : firstYearMonths, month);
if (monthAdded != month || yearAdded) {
b.append(monthNames[month]).append(" ");
monthAdded = month;
}
b.append(day + 1);
dayAdded = day + 1;
b.append(dayAdded);
dash = false;
}
}
@ -1080,9 +1119,18 @@ public class OpeningHoursParser {
} else if (!dash) {
b.append(", ");
}
appendYearString(b, firstYearMonths, excludedMonthStart);
b.append(monthNames[excludedMonthStart]).append(" ").append(excludedDayStart + 1)
.append("-")
.append(monthNames[excludedMonthEnd]).append(" ").append(excludedDayEnd + 1);
.append("-");
appendYearString(b, lastYearMonths, excludedMonthEnd);
b.append(monthNames[excludedMonthEnd]).append(" ").append(excludedDayEnd + 1);
} else if (yearAdded && !dash && monthAdded != -1 && lastYearMonths != null) {
b.append("-");
appendYearString(b, lastYearMonths, monthAdded);
b.append(monthNames[monthAdded]);
if (dayAdded != -1) {
b.append(" ").append(dayAdded);
}
}
if (!first) {
b.append(" ");
@ -1139,6 +1187,17 @@ public class OpeningHoursParser {
return b.toString();
}
private boolean appendYearString(StringBuilder b, int[] yearMonths, int month) {
if (yearMonths != null && yearMonths[month] > 0) {
b.append(yearMonths[month]).append(" ");
return true;
} else if (year > 0) {
b.append(year).append(" ");
return true;
}
return false;
}
private void addArray(boolean[] array, String[] arrayNames, StringBuilder b) {
boolean dash = false;
boolean first = true;
@ -1405,7 +1464,7 @@ public class OpeningHoursParser {
private int calculate(Calendar cal) {
int month = cal.get(Calendar.MONTH);
if (!months[month]) {
if (!containsMonth(cal)) {
return 0;
}
int dmonth = cal.get(Calendar.DAY_OF_MONTH) - 1;
@ -1500,6 +1559,11 @@ public class OpeningHoursParser {
return false;
}
@Override
public boolean containsYear(Calendar cal) {
return false;
}
@Override
public String toRuleString() {
return ruleString;
@ -1547,12 +1611,14 @@ public class OpeningHoursParser {
TOKEN_COMMA(2),
TOKEN_DASH(3),
// order is important
TOKEN_MONTH(4),
TOKEN_DAY_MONTH(5),
TOKEN_HOLIDAY(6),
TOKEN_DAY_WEEK(6),
TOKEN_HOUR_MINUTES (7),
TOKEN_OFF_ON(8);
TOKEN_YEAR(4),
TOKEN_MONTH(5),
TOKEN_DAY_MONTH(6),
TOKEN_HOLIDAY(7),
TOKEN_DAY_WEEK(7),
TOKEN_HOUR_MINUTES (8),
TOKEN_OFF_ON(9);
public final int ord;
private TokenType(int ord) {
@ -1696,22 +1762,21 @@ public class OpeningHoursParser {
}
}
// recognize other numbers
// if there is no on/off and minutes/hours
boolean hoursSpecified = false;
for(int i = 0; i < tokens.size(); i ++) {
if(tokens.get(i).type == TokenType.TOKEN_HOUR_MINUTES ||
tokens.get(i).type == TokenType.TOKEN_OFF_ON) {
hoursSpecified = true;
boolean monthSpecified = false;
for (Token t : tokens) {
if (t.type == TokenType.TOKEN_MONTH) {
monthSpecified = true;
break;
}
}
for(int i = 0; i < tokens.size(); i ++) {
if(tokens.get(i).type == TokenType.TOKEN_UNKNOWN && tokens.get(i).mainNumber >= 0) {
tokens.get(i).type = hoursSpecified ? TokenType.TOKEN_DAY_MONTH : TokenType.TOKEN_HOUR_MINUTES;
if(tokens.get(i).type == TokenType.TOKEN_HOUR_MINUTES) {
tokens.get(i).mainNumber = tokens.get(i).mainNumber * 60;
} else {
tokens.get(i).mainNumber = tokens.get(i).mainNumber - 1;
Token t = tokens.get(i);
if (t.type == TokenType.TOKEN_UNKNOWN && t.mainNumber >= 0) {
if (monthSpecified && t.mainNumber <= 31) {
t.type = TokenType.TOKEN_DAY_MONTH;
t.mainNumber = t.mainNumber - 1;
} else if (t.mainNumber > 1000) {
t.type = TokenType.TOKEN_YEAR;
}
}
}
@ -1727,6 +1792,7 @@ public class OpeningHoursParser {
Token[] currentPair = new Token[2];
listOfPairs.add(currentPair);
Token prevToken = null;
Token prevYearToken = null;
int indexP = 0;
for(int i = 0; i <= tokens.size(); i++) {
Token t = i == tokens.size() ? null : tokens.get(i);
@ -1782,6 +1848,40 @@ public class OpeningHoursParser {
} else if (array != null) {
fillRuleArray(array, pair);
}
int ruleYear = basic.year;
if ((ruleYear > 0 || prevYearToken != null) && firstMonthToken != null && lastMonthToken != null) {
int length = lastMonthToken.mainNumber > firstMonthToken.mainNumber ?
lastMonthToken.mainNumber - firstMonthToken.mainNumber : 12 - firstMonthToken.mainNumber + lastMonthToken.mainNumber;
int month = firstMonthToken.mainNumber;
int endYear = prevYearToken != null ? prevYearToken.mainNumber : ruleYear;
int startYear = ruleYear > 0 ? ruleYear : endYear;
int year = startYear;
if (basic.firstYearMonths == null) {
basic.firstYearMonths = new int[12];
}
int[] yearMonths = basic.firstYearMonths;
int k = 0;
while (k <= length) {
yearMonths[month++] = year;
if (month > 11) {
month = 0;
year = endYear;
if (basic.lastYearMonths == null) {
basic.lastYearMonths = new int[12];
}
yearMonths = basic.lastYearMonths;
}
k++;
}
if (endYear - startYear > 1) {
basic.fullYears = endYear - startYear - 1;
}
if (endYear > startYear && firstMonthToken.mainNumber >= lastMonthToken.mainNumber) {
//basic.dayMonths = null;
Arrays.fill(basic.months, true);
}
}
} else if (pair[0] != null) {
if (pair[0].type == TokenType.TOKEN_HOLIDAY) {
if (pair[0].mainNumber == 0) {
@ -1798,6 +1898,9 @@ public class OpeningHoursParser {
}
if (array != null) {
array[pair[0].mainNumber] = true;
if (prevYearToken != null) {
basic.year = prevYearToken.mainNumber;
}
}
}
}
@ -1813,6 +1916,11 @@ public class OpeningHoursParser {
if (l[0] != null && l[0].mainNumber == 0) {
basic.off = true;
}
} else if (currentParse == TokenType.TOKEN_YEAR) {
Token[] l = listOfPairs.get(0);
if (l[0] != null && l[0].mainNumber > 1000) {
prevYearToken = l[0];
}
}
listOfPairs.clear();
currentPair = new Token[2];
@ -1842,6 +1950,8 @@ public class OpeningHoursParser {
}
} else if (t.type == TokenType.TOKEN_DASH) {
} else if (t.type == TokenType.TOKEN_YEAR) {
prevYearToken = t;
} else if (t.type.ord() == currentParse.ord()) {
if (indexP < 2) {
currentPair[indexP++] = t;

View file

@ -116,7 +116,93 @@ public class OpeningHoursParserTest {
Locale locale = Locale.getDefault();
try {
Locale.setDefault(Locale.forLanguageTag("en-US"));
OpeningHours hours = parseOpenedHours("Apr 05-Oct 24: Fr 08:00-16:00");
OpeningHours hours = parseOpenedHours("2019 Apr 1 - 2020 Apr 1");
System.out.println(hours);
testOpened("01.04.2018 15:00", hours, false);
testOpened("01.04.2019 15:00", hours, true);
testOpened("01.04.2020 15:00", hours, true);
hours = parseOpenedHours("2019 Apr 15 - 2020 Mar 1");
System.out.println(hours);
testOpened("01.04.2018 15:00", hours, false);
testOpened("01.04.2019 15:00", hours, false);
testOpened("15.04.2019 15:00", hours, true);
testOpened("15.09.2019 15:00", hours, true);
testOpened("15.02.2020 15:00", hours, true);
testOpened("15.03.2020 15:00", hours, false);
testOpened("15.04.2020 15:00", hours, false);
hours = parseOpenedHours("2019 Jul 23 05:00-24:00; 2019 Jul 24-2019 Jul 26 00:00-24:00; 2019 Jul 27 00:00-18:00");
System.out.println(hours);
testOpened("23.07.2018 15:00", hours, false);
testOpened("23.07.2019 15:00", hours, true);
testOpened("23.07.2019 04:00", hours, false);
testOpened("23.07.2020 15:00", hours, false);
testOpened("25.07.2018 15:00", hours, false);
testOpened("24.07.2019 15:00", hours, true);
testOpened("25.07.2019 04:00", hours, true);
testOpened("26.07.2019 15:00", hours, true);
testOpened("25.07.2020 15:00", hours, false);
testOpened("27.07.2018 15:00", hours, false);
testOpened("27.07.2019 15:00", hours, true);
testOpened("27.07.2019 19:00", hours, false);
testOpened("27.07.2020 15:00", hours, false);
hours = parseOpenedHours("2019 Sep 1 - 2022 Apr 1");
System.out.println(hours);
testOpened("01.02.2018 15:00", hours, false);
testOpened("29.05.2019 15:00", hours, false);
testOpened("05.09.2019 11:00", hours, true);
testOpened("05.02.2020 11:00", hours, true);
testOpened("03.06.2020 11:00", hours, false);
testOpened("05.02.2021 11:00", hours, true);
testOpened("05.02.2022 11:00", hours, true);
testOpened("05.02.2023 11:00", hours, false);
hours = parseOpenedHours("2019 Apr 15 - 2019 Sep 1: Mo-Fr 00:00-24:00");
System.out.println(hours);
testOpened("06.04.2019 15:00", hours, false);
testOpened("29.05.2019 15:00", hours, true);
testOpened("25.07.2019 11:00", hours, true);
testOpened("12.07.2018 11:00", hours, false);
testOpened("18.07.2020 11:00", hours, false);
testOpened("28.07.2021 11:00", hours, false);
hours = parseOpenedHours("2019 Sep 1 - 2020 Apr 1");
System.out.println(hours);
testOpened("01.04.2019 15:00", hours, false);
testOpened("29.05.2019 15:00", hours, false);
testOpened("05.09.2019 11:00", hours, true);
testOpened("05.02.2020 11:00", hours, true);
testOpened("05.06.2020 11:00", hours, false);
testOpened("05.02.2021 11:00", hours, false);
hours = parseOpenedHours("2019 Apr 15 - 2019 Sep 1");
System.out.println(hours);
testOpened("01.04.2019 15:00", hours, false);
testOpened("29.05.2019 15:00", hours, true);
testOpened("27.07.2019 15:00", hours, true);
testOpened("05.09.2019 11:00", hours, false);
testOpened("05.06.2018 11:00", hours, false);
testOpened("05.06.2020 11:00", hours, false);
hours = parseOpenedHours("Apr 15 - Sep 1");
System.out.println(hours);
testOpened("01.04.2019 15:00", hours, false);
testOpened("29.05.2019 15:00", hours, true);
testOpened("27.07.2019 15:00", hours, true);
testOpened("05.09.2019 11:00", hours, false);
hours = parseOpenedHours("Apr 15 - Sep 1: Mo-Fr 00:00-24:00");
System.out.println(hours);
testOpened("01.04.2019 15:00", hours, false);
testOpened("29.05.2019 15:00", hours, true);
testOpened("24.07.2019 15:00", hours, true);
testOpened("27.07.2019 15:00", hours, false);
testOpened("05.09.2019 11:00", hours, false);
hours = parseOpenedHours("Apr 05-Oct 24: Fr 08:00-16:00");
System.out.println(hours);
testOpened("26.08.2018 15:00", hours, false);
testOpened("29.03.2019 15:00", hours, false);