生成Java中两个给定日期之间的所有日期

时间:2015-09-03 09:47:56

标签: java date simpledateformat timeunit

我正在尝试获取一系列日期,而我的输入是'from'/'to'结​​构。 所以我的意见是:

String date1 = "2014-01-01";
String date2 = "2014-05-01";

我的输出应该是一个Arraylist,其中所有日期都在date1和date2之间。 我已经找到了这个,但我只能找到关于两个日期之间差异的问题:

SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
String inputString1 = "23 01 1997";
String inputString2 = "27 04 1997";

try {
    Date date1 = myFormat.parse(inputString1);
    Date date2 = myFormat.parse(inputString2);
    long diff = date2.getTime() - date1.getTime();
    System.out.println ("Days: " + TimeUnit.DAYS.convert(diff,TimeUnit.MILLISECONDS));
} catch (ParseException e) {
e.printStackTrace();
}

任何提示或建议?所有其他问题都适用于iOS或SQL。

6 个答案:

答案 0 :(得分:4)

看看JodaTime:http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTime.html

DateTime dateTime1 = new DateTime(date1);
DateTime dateTime2 = new DateTime(date2);

List<Date> allDates = new ArrayList();

while( dateTime1.before(dateTime2) ){
   allDates.add( dateTime1.toDate() );
   dateTime1 = dateTime1.plusDays(1);
}

答案 1 :(得分:1)

如果您不想使用第三方库,可以使用Calendar

检查here a working demo

public static void main(String[] args) throws Exception {
    SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
    String inputString1 = "23 01 1997";
    String inputString2 = "27 04 1997";
    ArrayList<Date> dates = new ArrayList<Date>();

    try {
        Date date1 = myFormat.parse(inputString1);
        Calendar c1 = DateToCalendar(date1);
        Date date2 = myFormat.parse(inputString2);
        Calendar c2 = DateToCalendar(date2);

        while (!areEqualDate(c1, c2)) {
            dates.add(c1.getTime());
            System.out.println (c1.getTime());
            c1.add(Calendar.DAY_OF_YEAR, 1);
        }
    } catch (ParseException e) {
        e.printStackTrace();
    }


    // ArrayList<Date> dates >> contain all dates between both given days.
}


private static boolean areEqualDate(Calendar c1, Calendar c2) {
    if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR)) return false; 
    if (c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH)) return false; 
    if (c1.get(Calendar.DAY_OF_YEAR) != c2.get(Calendar.DAY_OF_YEAR)) return false; 
    return true;
}

public static Calendar DateToCalendar(Date date) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    return cal;
}

答案 2 :(得分:1)

我喜欢JodaTime,但是使用java.util.Calendar也可以在没有第三方库的情况下完成。给定一个Calendar对象,可以使用其add方法来增加日期的某些字段,同时遵守日历规则(比如在1月31日添加1天会让您到2月1日,而不是到1月32日)。

首先按照正确的时间顺序将日期分别放入一个Calendar个对象中,以便稍后添加正确的方向:

    Calendar cStart = Calendar.getInstance(),
             cStop = Calendar.getInstance();

    if (date1.before(date2)) {
        cStart.setTime(date1);
        cStop.setTime(date2);
    } else {
        cStart.setTime(date2);
        cStop.setTime(date1);

date1date2是您问题中已解析的Date个对象,为简单起见。

接下来,循环播放&#34;将1添加到每年的日期&#34;指示直到超过停止日期:

do {
        System.out.println(pretty(cStart));
        cStart.add(Calendar.DAY_OF_YEAR, 1);
} while (cStart.before(cStop));

最后打印停止日期

    System.out.println(pretty(cStop));

pretty()只是通过SDF发送日历的一些迷你方法,就像你首先用来解析字符串一样。

此解决方案将打印日期范围,包括开始日期和停止日期,并且可能需要围绕边缘情况进行一些调整(如date1==date2)。可以轻松调整以排除开始和停止日期。当然可以交换打印以进行聚合。要从日历中获取Date对象,请使用getTime()方法(返回快照,而不是实时参考)。

可以找到相关(Gregorian)Calendar的文档here

答案 3 :(得分:1)

以下是两个字符串日期之间获取日期数组的代码。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
public class DateFormatExample {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        SimpleDateFormat myFormat = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");  
        String date1 = "2014-01-01";
        String date2 = "2014-05-01";
        try {
            Date d1 = myFormat.parse(date1);
            Date d2 = myFormat.parse(date2);
            List<Date> allDates = new ArrayList<Date>();
            List<String> allDatesString = new ArrayList<String>();
            while( d1.before(d2) ){
                d1 = addDays(d1, 1);  
                allDates.add(d1);
                allDatesString.add(formatter.format(d1));
            }
            System.out.println(allDates);
            System.out.println(allDatesString);
        } catch (ParseException e) {
        e.printStackTrace();
        }
    }
    private static Date addDays(Date d1, int i) {
        GregorianCalendar cal = new GregorianCalendar();
        cal.setTime(d1);
        cal.add(Calendar.DATE, 1);
        return cal.getTime();
    }

}

答案 4 :(得分:0)

我已经知道OP不使用Java 8,但这是当前的解决方案 - Java已经过改进,新的java.time API可以完成这方面的所有工作:

//change these values :
LocalDate ld1 = LocalDate.ofEpochDay(0);
LocalDate ld2 = LocalDate.now();

//do NOT change these:
final LocalDate begin = ld1.isBefore(ld2) ? ld1 : ld2;
final LocalDate end = ld2.isAfter(ld1) ? ld2 : ld1;

for (int i = 0; i < begin.until(end, ChronoUnit.DAYS); i++) {
    final LocalDate curDate = begin.plusDays(i);
    System.out.println("current date : " + curDate);
}

这将在两个日期之间输出每个有效日,而大多数其他解决方案也会为您提供无效的日;事实上:时间计算需要在与时区无关的数据上进行 - 另一方面,输出很可能是时区和/或时间顺序依赖的。 这就是为什么有像java.time.format这样的软件包 - 只需计算您所选区域的时间/日期值和格式 ...就是如何正确完成它们。

如果您需要转换时态输入,那么time-API中也有一些有用的功能,我建议您对该主题进行全面的教程,一些好的介绍可能是this,尤其是that

  

表示时间有两种基本方法。一种方式代表时间   人类术语,称为人类时间,如年,月,日,   小时,分钟和秒。另一方面,机器时间,测量时间   连续沿着一个来自原点的时间线,称为时代,在   纳秒分辨率。 Date-Time包提供了丰富的数组   用于表示日期和时间的类。日期时间中的某些类   API旨在表示机器时间,而其他API则更适合   代表人类的时间。

答案 5 :(得分:0)

如果你使用的是番石榴,那么这个问题有一个非常优雅的解决方案。

Guava有两个简洁的类,例如RangeContiguousSet,它们实现了你所需要的:第一个操作值范围,第二个操作 - 能够将范围转换为一组离散值。

两者的使用示例(与JodaTime一起):

LocalDate start = LocalDate.parse("2015-01-01");
LocalDate end = LocalDate.parse("2019-02-01");
Range<LocalDate> range = Range.closed(start, end); //Creates a "closed" range, that is both dates are inclusive. There are also options like "openClosed", "closedOpen" and "open"
final Set<LocalDate> daySet = ContiguousSet.create(range, LocalDateDomain.INSTANCE); //Create a "virtual" set of days in given the range. "virtual" part means that if you create a set of 10 thousand years, it will not eat your memory at all
for (LocalDate day : daySet) {
  //...operation...
}

就个人而言,我真的更喜欢这种方式,因为它消除了理解封闭/开放范围的一些问题,并使代码更容易阅读和理解,同时不会影响性能。此外,它适用于任何类型的日期,任何库(您可以将YodaTime交换为Java8日期甚至Java7-基于日期的实现)。

此外,它允许你在交叉点,联合,范围跨度,令人难以置信的快速“包含”等范围内进行一些巧妙的操作。

唯一的缺点是:

  1. 对番石榴的依赖。
  2. 需要创建一个特殊的“DiscreteDomain”类,Guava用它来了解一个日期结束和其他日期的开始。
  3. LocalDateDomain实现示例,它作为Guava和JodaTime之间的桥梁运行:

    public class LocalDateDomain extends DiscreteDomain<LocalDate> {
        public static final LocalDateDomain INSTANCE = new LocalDateDomain();
    
        @Override
        public LocalDate next(LocalDate value) {
            return value.plusDays(1);
        }
    
        @Override
        public LocalDate previous(LocalDate value) {
            return value.minusDays(1);
        }
    
        @Override
        public long distance(LocalDate start, LocalDate end) {
            return Days.daysBetween(start, end).getDays();
        }
    }