【问题标题】:How to iterate through range of Dates in Java?如何遍历Java中的日期范围?
【发布时间】:2011-05-30 21:55:20
【问题描述】:

在我的脚本中,我需要在给定开始日期和结束日期的情况下,在日期范围内执行一组操作。
请指导我使用 Java 实现这一目标。

for ( currentDate = starDate; currentDate < endDate; currentDate++) {

}

我知道上面的代码根本不可能,但我这样做是为了向您展示我想要实现的目标。

【问题讨论】:

    标签: java date iteration


    【解决方案1】:

    好吧,您可以使用 Java 8's time-API 执行类似的操作,特别是针对此问题 java.time.LocalDate(或 Java 7 及更早版本的等效 Joda Time 类)

    for (LocalDate date = startDate; date.isBefore(endDate); date = date.plusDays(1))
    {
        ...
    }
    

    我会彻底推荐在内置的Date/Calendar 类上使用java.time(或Joda Time)。

    【讨论】:

    • 进一步扩展关于 Joda Time 的观点:尝试自己正确实现这一点比人们想象的要困难,因为夏季前后的变化会出现一些极端情况。
    • +1 为 Joda,我希望有一天它会在标准 API 中实现它。
    • @gyabraham:JSR-310 在 Java 8 上的表现相当不错。
    • 可以确认这个完全相同的代码可以使用 Java 8 的 java.time.LocalDate 而不是 Joda。
    • Joda-Time 项目现在处于维护模式,建议迁移到 java.time 类。如 cmets 中所述,此答案的代码在 java.time 中按原样工作,只需更改您的 import 语句即可。
    【解决方案2】:

    JodaTime 很好,但是,为了完整起见和/或如果您更喜欢 API 提供的设施,这里是标准 API 方法。

    java.util.Date 实例开始时,如下所示:

    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
    Date startDate = formatter.parse("2010-12-20");
    Date endDate = formatter.parse("2010-12-26");
    

    如果您还没有使用 Java8,请使用旧版 java.util.Calendar 方法:

    Calendar start = Calendar.getInstance();
    start.setTime(startDate);
    Calendar end = Calendar.getInstance();
    end.setTime(endDate);
    
    for (Date date = start.getTime(); start.before(end); start.add(Calendar.DATE, 1), date = start.getTime()) {
        // Do your job here with `date`.
        System.out.println(date);
    }
    

    这里是 Java8 的 java.time.LocalDate 方法,基本上就是 JodaTime 方法:

    LocalDate start = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    LocalDate end = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    
    for (LocalDate date = start; date.isBefore(end); date = date.plusDays(1)) {
        // Do your job here with `date`.
        System.out.println(date);
    }
    

    如果您想迭代包含结束日期,请分别使用!start.after(end)!date.isAfter(end)

    【讨论】:

      【解决方案3】:

      Java 8 风格,使用java.time 类:

      // Monday, February 29 is a leap day in 2016 (otherwise, February only has 28 days)
      LocalDate start = LocalDate.parse("2016-02-28"),
                end   = LocalDate.parse("2016-03-02");
      
      // 4 days between (end is inclusive in this example)
      Stream.iterate(start, date -> date.plusDays(1))
              .limit(ChronoUnit.DAYS.between(start, end) + 1)
              .forEach(System.out::println);
      

      输出:

      2016-02-28
      2016-02-29
      2016-03-01
      2016-03-02
      

      替代方案:

      LocalDate next = start.minusDays(1);
      while ((next = next.plusDays(1)).isBefore(end.plusDays(1))) {
          System.out.println(next);
      }
      

      Java 9 添加了datesUntil() 方法:

      start.datesUntil(end.plusDays(1)).forEach(System.out::println);
      

      【讨论】:

      • 你能放多个值吗?例如:只有星期一或星期四或两者兼而有之
      • 我不明白这个问题?听起来您可能正在寻找Stream.filter
      【解决方案4】:

      这与 BalusC 给出的答案基本相同,但使用 while 循环代替 for 循环更具可读性:

      Calendar start = Calendar.getInstance();
      start.setTime(startDate);
      
      Calendar end = Calendar.getInstance();
      end.setTime(endDate);
      
      while( !start.after(end)){
          Date targetDay = start.getTime();
          // Do Work Here
      
          start.add(Calendar.DATE, 1);
      }
      

      【讨论】:

      • 如果逻辑涉及“继续”语句,这将不起作用,而 BalusC 的 for 循环版本使用 continue 语句。
      【解决方案5】:

      Apache Commons

          for (Date dateIter = fromDate; !dateIter.after(toDate); dateIter = DateUtils.addDays(dateIter, 1)) {
              // ...
          }
      

      【讨论】:

      • +1,恕我直言,当您使用旧代码时,这是最干净的。只需为 addDays(..) 添加一个额外的静态导入,它就会变得更短。
      【解决方案6】:
      private static void iterateBetweenDates(Date startDate, Date endDate) {
          Calendar startCalender = Calendar.getInstance();
          startCalender.setTime(startDate);
          Calendar endCalendar = Calendar.getInstance();
          endCalendar.setTime(endDate);
      
          for(; startCalender.compareTo(endCalendar)<=0;
                startCalender.add(Calendar.DATE, 1)) {
              // write your main logic here
          }
      
      }
      

      【讨论】:

        【解决方案7】:

        我们可以将逻辑迁移到 Java 7、Java 8 和 Java 9 的各种方法中:

        public static List<Date> getDatesRangeJava7(Date startDate, Date endDate) {
            List<Date> datesInRange = new ArrayList<>();
            Calendar startCalendar = new GregorianCalendar();
            startCalendar.setTime(startDate);
            Calendar endCalendar = new GregorianCalendar();
            endCalendar.setTime(endDate);
            while (startCalendar.before(endCalendar)) {
                Date result = startCalendar.getTime();
                datesInRange.add(result);
                startCalendar.add(Calendar.DATE, 1);
            }
            return datesInRange;
        }
        
        public static List<LocalDate> getDatesRangeJava8(LocalDate startDate, LocalDate endDate) {
            int numOfDays = (int) ChronoUnit.DAYS.between(startDate, endDate);
            return IntStream.range(0, numOfDays)
                    .mapToObj(startDate::plusDays)
                    .collect(Collectors.toList());
        }
        
        public static List<LocalDate> getDatesRangeJava9(LocalDate startDate, LocalDate endDate) {
            return startDate.datesUntil(endDate).collect(Collectors.toList());
        }
        

        然后我们可以调用这些方法:

        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        Date startDate = formatter.parse("2010-12-20");
        Date endDate = formatter.parse("2010-12-26");
        List<Date> dateRangeList = getDatesRangeJava7(startDate, endDate);
        System.out.println(dateRangeList);
        
        LocalDate startLocalDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        List<LocalDate> dateRangeList8 = getDatesRangeJava8(startLocalDate, endLocalDate);
        System.out.println(dateRangeList8);
        List<LocalDate> dateRangeList9 = getDatesRangeJava8(startLocalDate, endLocalDate);
        System.out.println(dateRangeList9);
        

        输出将是:

        [2010 年 12 月 20 日星期一 00:00:00 IST 2010 年 12 月 21 日星期二 00:00:00 IST 2010 年 12 月星期三 22 00:00:00 IST 2010,星期四 12 月 23 日 00:00:00 IST 2010,星期五 12 月 24 日 00:00:00 IST 2010,星期六 12 月 25 日 00:00:00 IST 2010]

        [2010-12-20, 2010-12-21, 2010-12-22, 2010-12-23, 2010-12-24, 2010-12-25]

        [2010-12-20, 2010-12-21, 2010-12-22, 2010-12-23, 2010-12-24, 2010-12-25]

        【讨论】:

        • 可怕的 DateCalendar 类在几年前被 java.time 类所取代。具体来说,替换为InstantZonedDateDate
        • 我喜欢 Java 8 和 9 的方式。对于 Java 6 和 7,我建议使用 the ThreeTen Backport library,然后使用与 Java 8 中相同的方式。您很好地演示了这种方式如何更清晰,对程序员更友好。
        【解决方案8】:
        public static final void generateRange(final Date dateFrom, final Date dateTo)
        {
            final Calendar current = Calendar.getInstance();
            current.setTime(dateFrom);
        
            while (!current.getTime().after(dateTo))
            {
                // TODO
        
                current.add(Calendar.DATE, 1);
            }
        }
        

        【讨论】:

          【解决方案9】:

          从 Java 9 开始内置:LocalDate.datesUntil()

          到目前为止,似乎答案只考虑了 Java 8 及更早版本。 Java 9+的方式是:

              LocalDate startDate = LocalDate.of(2021, Month.JUNE, 29);
              LocalDate endDate = LocalDate.of(2021, Month.JULY, 3);
              
              startDate.datesUntil(endDate).forEach(System.out::println);
          

          这个例子的输出是:

          2021-06-29
          2021-06-30
          2021-07-01
          2021-07-02
          

          虽然开始日期包括在内,但结束日期是唯一的,就像我阅读它的方式一样。如果有人想要包含结束日期,这很简单,只需添加一天即可:

              startDate.datesUntil(endDate.plusDays(1)).forEach(System.out::println);
          
          2021-06-29
          2021-06-30
          2021-07-01
          2021-07-02
          2021-07-03
          

          你显然可以用这种方式迭代几年,就像你可以放一个更长的 lambda 一样,我只是放了方法参考 System.out::println 进行演示。

          链接

          【讨论】:

            【解决方案10】:

            这是 Java 8 代码。我认为这段代码会解决你的问题。Happy Coding

                LocalDate start = LocalDate.now();
                LocalDate end = LocalDate.of(2016, 9, 1);//JAVA 9 release date
                Long duration = start.until(end, ChronoUnit.DAYS);
                System.out.println(duration);
                 // Do Any stuff Here there after
                IntStream.iterate(0, i -> i + 1)
                         .limit(duration)
                         .forEach((i) -> {});
                 //old way of iteration
                for (int i = 0; i < duration; i++)
                 System.out.print("" + i);// Do Any stuff Here
            

            【讨论】:

            • 这是您可以跟进的最佳且简单的方法。
            【解决方案11】:

            为什么不使用 epoch 并轻松循环。

            long startDateEpoch = new java.text.SimpleDateFormat("dd/MM/yyyy").parse(startDate).getTime() / 1000;
            
                long endDateEpoch = new java.text.SimpleDateFormat("dd/MM/yyyy").parse(endDate).getTime() / 1000;
            
            
                long i;
                for(i=startDateEpoch ; i<=endDateEpoch; i+=86400){
            
                    System.out.println(i);
            
                }
            

            【讨论】:

              【解决方案12】:

              您可以编写一个类似的类(实现迭代器接口)并对其进行迭代。

              public class DateIterator implements Iterator<Date>, Iterable<Date>
              {
              
               private Calendar end = Calendar.getInstance();
               private Calendar current = Calendar.getInstance();
              
               public DateIterator(Date start, Date end)
               {
                   this.end.setTime(end);
                   this.end.add(Calendar.DATE, -1);
                   this.current.setTime(start);
                   this.current.add(Calendar.DATE, -1);
               }
              
               @Override
               public boolean hasNext()
               {
                   return !current.after(end);
               }
              
               @Override
               public Date next()
               {
                   current.add(Calendar.DATE, 1);
                   return current.getTime();
               }
              
               @Override
               public void remove()
               {
                   throw new UnsupportedOperationException(
                      "Cannot remove");
               }
              
               @Override
               public Iterator<Date> iterator()
               {
                   return this;
               }
              }
              

              并像这样使用它:

              Iterator<Date> dateIterator = new DateIterator(startDate, endDate);
              while(dateIterator.hasNext()){
                    Date selectedDate = dateIterator .next();
              
              }
              

              【讨论】:

                【解决方案13】:

                你可以试试这个:

                OffsetDateTime currentDateTime = OffsetDateTime.now();
                for (OffsetDateTime date = currentDateTime; date.isAfter(currentDateTime.minusYears(YEARS)); date = date.minusWeeks(1))
                {
                    ...
                }
                

                【讨论】:

                  【解决方案14】:

                  这将帮助您从 30 天开始并循环到今天的日期。您可以轻松更改日期范围和方向。

                  private void iterateThroughDates() throws Exception {
                      Calendar start = Calendar.getInstance();
                      start.add(Calendar.DATE, -30);
                      Calendar end = Calendar.getInstance();
                      for (Calendar date = start; date.before(end); date.add(Calendar.DATE, 1))
                          {
                          System.out.println(date.getTime());
                          }
                  }
                  

                  【讨论】:

                    【解决方案15】:

                    以下 sn-p(使用 Java 8 的 java.time.format)可用于迭代日期范围:

                        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                        // Any chosen date format maybe taken  
                        LocalDate startDate = LocalDate.parse(startDateString,formatter);
                        LocalDate endDate = LocalDate.parse(endDateString,formatter);
                        if(endDate.isBefore(startDate))
                        {
                            //error
                        }
                        LocalDate itr = null;
                        for (itr = startDate; itr.isBefore(endDate)||itr.isEqual(itr); itr = itr.plusDays(1))
                        {
                            //Processing  goes here
                        }
                    

                    plusMonths()/plusYears() 可以选择时间单位增量。 如上图所示,增量为一天。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2010-12-23
                      • 1970-01-01
                      • 2011-02-19
                      • 1970-01-01
                      • 2020-03-06
                      • 2023-02-17
                      相关资源
                      最近更新 更多