【问题标题】:How to parse an iCal RRULE in Java [closed]如何在 Java 中解析 iCal RRULE [关闭]
【发布时间】:2017-09-05 06:02:29
【问题描述】:

我有以下iCal recurrence rule 示例:

"RRULE:FREQ=YEARLY;INTERVAL=2"
"RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,TH"

我需要一个 Java 库来解析 RRULE 模式以在对象中处理。有没有好的 Java 库?


【问题讨论】:

    标签: java icalendar rrule


    【解决方案1】:

    以下是我如何使用 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);
        }
    

    您现在可以将这两个 datestart 日期结束用于您的数据库查询

    【讨论】:

      【解决方案2】:

      您可以使用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

      【讨论】:

        【解决方案3】:

        solution is to use:

                <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();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-17
          • 2013-01-26
          • 2012-09-29
          • 1970-01-01
          • 2014-03-13
          • 2021-03-04
          相关资源
          最近更新 更多