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



我试图获得日期数组,而我的输入是'从'/'到'结构。所以我的输入是:

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

我的输出应该是一个数组列表,所有日期在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的

看一下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);
}

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

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

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

查看这里的工作演示。

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;
}

我喜欢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对象。

接下来,循环执行"add 1 to day-of-year"指令,直到超出停止日期:

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的文档可以在这里找到

如果您正在使用Guava,这里有一个非常优雅的解决方案。

Guava有两个简洁的类,例如Range和毗连集,它们实现了您所需要的:第一个类操作值的范围,第二个类-能够将范围转换为离散值的集合。

两者(连同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. 需要创建一个特殊的"离散域"类,Guava使用它来理解一个日期结束和另一个日期开始的位置。

localdateddomain实现的示例,它作为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();
    }
}

我已经知道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这样的软件包-简单地计算你的时间/日期值和格式他们为你选择的地区…这才是正确的做法。

如果你需要转换时间输入,在时间api中也有一些有用的函数,我建议你做一个关于这个主题的彻底的教程,一些好的介绍可能是这样的,尤其是那个:

有两种表示时间的基本方法。一种方式表示时间人的术语,指的是人的时间,比如年、月、日,小时、分、秒。另一种方式,机器时间,测量时间连续地沿着时间轴从一个原点开始,称为纪元纳秒分辨率。Date-Time包提供了丰富的类用于表示日期和时间。一些类在日期-时间API用于表示机器时间,其他API更适合来表示人类的时间。

最新更新