如何解析 Java 中的 iCal RRULE
How to parse an iCal RRULE in Java
我有以下 iCal recurrence rule 个示例:
"RRULE:FREQ=YEARLY;INTERVAL=2"
"RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,TH"
我需要一个 Java 库来解析 RRULE 模式以在对象中处理。有什么好的 Java 图书馆吗?
- ical library 构建不正确;
- google ical implementation 不支持年龄;
- maven repository可以提出很多实现方案,但我没有得到任何实际的。
<dependency>
<groupId>org.scala-saddle</groupId>
<artifactId>google-rfc-2445</artifactId>
<version>20110304</version>
</dependency>
几个例子:
1 转换为 java 对象:
rule = new RRule("RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,TH");
2 转换回来:
rule.toIcal();
您可以使用lib-recur
仍然支持并处理 RFC 5545 和 RFC 2445。
RecurrenceRule rule = new RecurrenceRule("FREQ=YEARLY;BYMONTHDAY=23;BYMONTH=5");
DateTime start = new DateTime(1982, 4 /* 0-based month numbers! */,23);
RecurrenceRuleIterator it = rule.iterator(start);
int maxInstances = 100; // limit instances for rules that recur forever
while (it.hasNext() && (!rule.isInfinite() || maxInstances-- > 0))
{
DateTime nextInstance = it.nextDateTime();
// do something with nextInstance
}
可以用maven安装
<!-- https://mvnrepository.com/artifact/org.dmfs/lib-recur -->
<dependency>
<groupId>org.dmfs</groupId>
<artifactId>lib-recur</artifactId>
<version>0.10.2</version>
</dependency>
或 gradle
// https://mvnrepository.com/artifact/org.dmfs/lib-recur
compile group: 'org.dmfs', name: 'lib-recur', version: '0.10.2'
此处提供更多文档:https://github.com/dmfs/lib-recur
下面是我如何使用 https://github.com/mangstadt/biweekly 库生成几个 (dateStart - dateEnd)。
收入是:
- 开始日期
- 结束日期(facultatif)
- 一个 RRULE,由 |
分隔
DTSTART:2019-07-01T16:00:00Z|DTEND:2019-07-01T17:00:00Z|RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR,SA,SU;UNTIL=2019-07-31T23:59:59Z
代码:
// A. split filter $iCalFilter
Map<String, String> iCalFilterMap = new HashMap<>();
for (String part : iCalFilter.split("\|")) {
if (part.contains(":")) {
String[] subparts = part.split(":", 2);
iCalFilterMap.put(subparts[0], subparts[1]);
}
}
// B. generate couples of dates starts and dates ends
ParseContext context = new ParseContext();
context.setVersion(ICalVersion.V2_0);
RecurrenceRuleScribe scribe = new RecurrenceRuleScribe();
RecurrenceRule rrule = scribe.parseText(iCalFilterMap.get(iCalFilterConstant.RRULE), ICalDataType.DATE_TIME, new ICalParameters(), context);
TimeZone timezone = TimeZone.getTimeZone(iCalFilterConstant.UTC);
int iCalFilterMaximumDayToGenerate = 365;
// DTSTART && DTEND
List<DateTime> listeDateStart = new ArrayList<>();
List<DateTime> listeDateEnd = new ArrayList<>();
if (null != inCalendarMap.get(InCalendarConstant.DTSTART)) {
DateTime dateTimeStart = new DateTime(inCalendarMap.get(InCalendarConstant.DTSTART)).withZone(InCalendarConstant.DATE_TIME_ZONE_UTC);
DateTime dateTimeEnd;
if (null != inCalendarMap.get(InCalendarConstant.DTEND)) {
dateTimeEnd = new DateTime(inCalendarMap.get(InCalendarConstant.DTEND)).withZone(InCalendarConstant.DATE_TIME_ZONE_UTC);
} else {
// Si le DTEND n'est pas renseigné par le client, alors on le met par défaut en fin de journée
dateTimeEnd = new DateTime(inCalendarMap.get(InCalendarConstant.DTSTART)).withZone(InCalendarConstant.DATE_TIME_ZONE_UTC).withTime(23, 59, 59, 999);
}
Interval interval = new Interval(dateTimeStart, dateTimeEnd);
DateIterator ditStart = rrule.getDateIterator(dateTimeStart.toDate(), timezone);
int compteurDateStart = 0;
while (ditStart.hasNext()) {
DateTime dateStart = new DateTime(ditStart.next()).withZone(InCalendarConstant.DATE_TIME_ZONE_UTC);
listeDateStart.add(dateStart);
DateTime dateEnd = dateStart.plus(interval.toDurationMillis());
listeDateEnd.add(new DateTime(dateEnd).withZone(InCalendarConstant.DATE_TIME_ZONE_UTC));
logger.logDebug(dateStart + "---" + dateEnd);
// Pour éviter une boucle infinie, ou une date de génération en 9999-12-12T23:59:59 , on limite le nombre de jours
compteurDateStart++;
if(compteurDateStart > inCalendarMaximumDayToGenerate) {
break;
}
}
}
// C. on set le couple dans le filters LesHalles pour utilisation dans la requete bdd voir CourseJdbcDaoImpl.addInCalendar
if(listeDateStart.size() == 0 || listeDateEnd.size() == 0) {
throw new ServiceFunctionalException(new Object[] { inCalendar }, MessageFonctionnelTheorique.IN_CALENDAR_RRULE_AUCUNE_DATE_GENEREE);
}
ImmutablePair<List<DateTime>, List<DateTime>> pairListeDatesStartsDatesEnds = new ImmutablePair<>(listeDateStart, listeDateEnd);
filters.setInCalendarDateStartDateEnds(pairListeDatesStartsDatesEnds);
}
您现在可以将这对日期开始日期结束用于您的数据库查询
我有以下 iCal recurrence rule 个示例:
"RRULE:FREQ=YEARLY;INTERVAL=2"
"RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,TH"
我需要一个 Java 库来解析 RRULE 模式以在对象中处理。有什么好的 Java 图书馆吗?
- ical library 构建不正确;
- google ical implementation 不支持年龄;
- maven repository可以提出很多实现方案,但我没有得到任何实际的。
<dependency>
<groupId>org.scala-saddle</groupId>
<artifactId>google-rfc-2445</artifactId>
<version>20110304</version>
</dependency>
几个例子:
1 转换为 java 对象:
rule = new RRule("RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,TH");
2 转换回来:
rule.toIcal();
您可以使用lib-recur
仍然支持并处理 RFC 5545 和 RFC 2445。
RecurrenceRule rule = new RecurrenceRule("FREQ=YEARLY;BYMONTHDAY=23;BYMONTH=5");
DateTime start = new DateTime(1982, 4 /* 0-based month numbers! */,23);
RecurrenceRuleIterator it = rule.iterator(start);
int maxInstances = 100; // limit instances for rules that recur forever
while (it.hasNext() && (!rule.isInfinite() || maxInstances-- > 0))
{
DateTime nextInstance = it.nextDateTime();
// do something with nextInstance
}
可以用maven安装
<!-- https://mvnrepository.com/artifact/org.dmfs/lib-recur -->
<dependency>
<groupId>org.dmfs</groupId>
<artifactId>lib-recur</artifactId>
<version>0.10.2</version>
</dependency>
或 gradle
// https://mvnrepository.com/artifact/org.dmfs/lib-recur
compile group: 'org.dmfs', name: 'lib-recur', version: '0.10.2'
此处提供更多文档:https://github.com/dmfs/lib-recur
下面是我如何使用 https://github.com/mangstadt/biweekly 库生成几个 (dateStart - dateEnd)。
收入是:
- 开始日期
- 结束日期(facultatif)
- 一个 RRULE,由 |
DTSTART:2019-07-01T16:00:00Z|DTEND:2019-07-01T17:00:00Z|RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR,SA,SU;UNTIL=2019-07-31T23:59:59Z
代码:
// A. split filter $iCalFilter
Map<String, String> iCalFilterMap = new HashMap<>();
for (String part : iCalFilter.split("\|")) {
if (part.contains(":")) {
String[] subparts = part.split(":", 2);
iCalFilterMap.put(subparts[0], subparts[1]);
}
}
// B. generate couples of dates starts and dates ends
ParseContext context = new ParseContext();
context.setVersion(ICalVersion.V2_0);
RecurrenceRuleScribe scribe = new RecurrenceRuleScribe();
RecurrenceRule rrule = scribe.parseText(iCalFilterMap.get(iCalFilterConstant.RRULE), ICalDataType.DATE_TIME, new ICalParameters(), context);
TimeZone timezone = TimeZone.getTimeZone(iCalFilterConstant.UTC);
int iCalFilterMaximumDayToGenerate = 365;
// DTSTART && DTEND
List<DateTime> listeDateStart = new ArrayList<>();
List<DateTime> listeDateEnd = new ArrayList<>();
if (null != inCalendarMap.get(InCalendarConstant.DTSTART)) {
DateTime dateTimeStart = new DateTime(inCalendarMap.get(InCalendarConstant.DTSTART)).withZone(InCalendarConstant.DATE_TIME_ZONE_UTC);
DateTime dateTimeEnd;
if (null != inCalendarMap.get(InCalendarConstant.DTEND)) {
dateTimeEnd = new DateTime(inCalendarMap.get(InCalendarConstant.DTEND)).withZone(InCalendarConstant.DATE_TIME_ZONE_UTC);
} else {
// Si le DTEND n'est pas renseigné par le client, alors on le met par défaut en fin de journée
dateTimeEnd = new DateTime(inCalendarMap.get(InCalendarConstant.DTSTART)).withZone(InCalendarConstant.DATE_TIME_ZONE_UTC).withTime(23, 59, 59, 999);
}
Interval interval = new Interval(dateTimeStart, dateTimeEnd);
DateIterator ditStart = rrule.getDateIterator(dateTimeStart.toDate(), timezone);
int compteurDateStart = 0;
while (ditStart.hasNext()) {
DateTime dateStart = new DateTime(ditStart.next()).withZone(InCalendarConstant.DATE_TIME_ZONE_UTC);
listeDateStart.add(dateStart);
DateTime dateEnd = dateStart.plus(interval.toDurationMillis());
listeDateEnd.add(new DateTime(dateEnd).withZone(InCalendarConstant.DATE_TIME_ZONE_UTC));
logger.logDebug(dateStart + "---" + dateEnd);
// Pour éviter une boucle infinie, ou une date de génération en 9999-12-12T23:59:59 , on limite le nombre de jours
compteurDateStart++;
if(compteurDateStart > inCalendarMaximumDayToGenerate) {
break;
}
}
}
// C. on set le couple dans le filters LesHalles pour utilisation dans la requete bdd voir CourseJdbcDaoImpl.addInCalendar
if(listeDateStart.size() == 0 || listeDateEnd.size() == 0) {
throw new ServiceFunctionalException(new Object[] { inCalendar }, MessageFonctionnelTheorique.IN_CALENDAR_RRULE_AUCUNE_DATE_GENEREE);
}
ImmutablePair<List<DateTime>, List<DateTime>> pairListeDatesStartsDatesEnds = new ImmutablePair<>(listeDateStart, listeDateEnd);
filters.setInCalendarDateStartDateEnds(pairListeDatesStartsDatesEnds);
}
您现在可以将这对日期开始日期结束用于您的数据库查询