Java 计算一年中两个日期之间的天数

Java 计算一年中两个日期之间的天数,java,java-8,Java,Java 8,我有“LocalDate”类型的结婚日期列表,我想找到结婚纪念日在未来30天内的人的列表。所有的结婚日期都是在过去的几年里,比如1980年,1990年,2000年 我曾尝试使用ChronoUnit.DAYS.between()函数,但如果日期是今天和未来的日期,它只显示天数 String str = "2019-04-24"; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate da

我有“LocalDate”类型的结婚日期列表,我想找到结婚纪念日在未来30天内的人的列表。所有的结婚日期都是在过去的几年里,比如1980年,1990年,2000年

我曾尝试使用ChronoUnit.DAYS.between()函数,但如果日期是今天和未来的日期,它只显示天数

String str = "2019-04-24";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date = LocalDate.parse(str, formatter);
LocalDate today = LocalDate.now();          
long dd = ChronoUnit.DAYS.between(today, date);

我期待的答案是,如果结婚日期是1990-04-29,那么它应该告诉我这个日期是否在接下来的30天内。也就是说,如果上述日期的周年纪念日在接下来的30天内,或者不在30天内。

尝试计算今年的周年纪念日,并找出现在和该日期之间的差异:

String str=“2008-05-20”;
DateTimeFormatter formatter=模式的DateTimeFormatter.of(“yyyy-MM-dd”);
LocalDate=LocalDate.parse(str,格式化程序);
LocalDate today=LocalDate.now();
long dd=ChronoUnit.DAYS.between(今天,日期);
System.err.println(“您的答案是”+dd);
LocalDate ThisYearsannVersary=LocalDate.of(today.getYear(),date.getMonth(),date.getDayOfMonth());
System.err.println(“本周年纪念日为”+本周年纪念日);
dd=时间单位。天数。介于(今天、今年和周日)之间;
System.err.println(“以“+dd+”天为单位”);
输出

YOUR ANSWER WAS -3981
THIS YEARS ANNIVERSARY IS 2019-05-24
WHICH IS IN 36 days


因为你根本不在乎年份:

private static boolean isWithinNext30Days(LocalDate date, LocalDate today) {

    int todayYear = today.getYear();
    int todayMonth = today.getMonthValue();

    int dateMonth = date.getMonthValue();

    if (todayMonth > dateMonth) {
        date = date.withYear(todayYear + 1);
        return today.plusDays(30).isAfter(date) && date.isAfter(today);
    }

    LocalDate alteredDate = date.withYear(todayYear);
    return today.plusDays(30).isAfter(alteredDate) && alteredDate.isAfter(today);

}

此计算所需的测试用例为:

今天是结婚的日子
2000-01-01   ????-01-01     0
2000-01-01   ????-01-02     1
2000-01-01   ????-01-31    30
2000年01月01日12月31日365因为2000年是闰年
因为2001年不是闰年
因为2000年是闰年
2000-12-31   ????-01-01     1
2000年12月01日11月30日364因为2001年不是闰年
1999年12月01日11月30日365因为2000年不是闰年
这些测试用例给出了如何做的提示

  • 以结婚日期为例
  • 在当前年份中尝试该日期
  • 如果是过去的话,那就把它定在明年
  • 计算今天和该日期之间的天数
  • 第四步将考虑闰年

    我建议写这个方法:

    int daysUntilNextAnniversary(LocalDate today, LocalDate anniversary) {
        ...
    }
    
    “周年纪念”一词已经包含了与周年纪念无关的信息,这与上面的测试用例相匹配

    然后您可以像这样轻松地使用它:

    int days = daysUntilNextAnniversary(LocalDate.now(), marriage);
    if (1 <= days && days <= 30) {
        ...
    }
    
    下面是计算的实际代码:

    package de.roland_illig.so;
    
    import java.time.LocalDate;
    import java.time.temporal.ChronoUnit;
    
    public class Anniv {
    
        public static int daysUntilNextAnniversary(LocalDate today, LocalDate anniversary) {
            LocalDate d = anniversary.withYear(today.getYear());
            if (d.isBefore(today)) {
                d = anniversary.withYear(today.getYear() + 1);
            }
            return Math.toIntExact(ChronoUnit.DAYS.between(today, d));
        }
    }
    
    如您所见,测试代码比实际应用程序代码长得多。在处理日期计算时,这是必要的。当不同的时区发挥作用时,情况就更糟了。和闰秒。所以,“基本”的概念是,你想把你的日期列表改成与今年相匹配的年份。“捕获”是,如果结果日期在今天之前,则应将年份增加一,这样,如果现在是12月,则将捕获1月发生的所有周年纪念

    也许像

    LocalDate now = LocalDate.now();
    int year = now.getYear();
    List<LocalDate> dates = ...;
    List<LocalDate> adjusted = new ArrayList<>(10);
    for (LocalDate date : dates) {
        LocalDate warped = date.withYear(year);
        if (warped.isBefore(now)) {
            warped = warped.withYear(year + 1);
        }
        adjusted.add(warped);
    }
    
    Input date 2019-04-19
    +---------------+---------------+--------------+
    | Original Date | Adjusted Date | Within range |
    +---------------+---------------+--------------+
    | 1996-04-13    | 2020-04-13    |              |
    | 1986-04-24    | 2019-04-24    | X            |
    | 1989-04-23    | 2019-04-23    | X            |
    | 1960-05-11    | 2019-05-11    | X            |
    | 1986-05-18    | 2019-05-18    | X            |
    | 1984-04-06    | 2020-04-06    |              |
    | 1997-05-29    | 2019-05-29    |              |
    | 2008-03-31    | 2020-03-31    |              |
    | 2014-04-18    | 2020-04-18    |              |
    | 1982-04-23    | 2019-04-23    | X            |
    +---------------+---------------+--------------+
    
    +---------------+---------------+--------------+
    | Original Date | Adjusted Date | Within range |
    +---------------+---------------+--------------+
    | 2001-12-16    | 2020-12-16    |              |
    | 2005-12-28    | 2019-12-28    | X            |
    | 1988-12-31    | 2019-12-31    | X            |
    | 1989-11-13    | 2020-11-13    |              |
    | 1976-11-13    | 2020-11-13    |              |
    | 1991-01-09    | 2020-01-09    | X            |
    | 1963-11-04    | 2020-11-04    |              |
    | 2001-11-02    | 2020-11-02    |              |
    | 1980-01-11    | 2020-01-11    | X            |
    | 1979-11-17    | 2020-11-17    |              |
    +---------------+---------------+--------------+
    
    所以,使用相同的伪随机生成的日期,我可以得到一个类似于

    LocalDate now = LocalDate.now();
    int year = now.getYear();
    List<LocalDate> dates = ...;
    List<LocalDate> adjusted = new ArrayList<>(10);
    for (LocalDate date : dates) {
        LocalDate warped = date.withYear(year);
        if (warped.isBefore(now)) {
            warped = warped.withYear(year + 1);
        }
        adjusted.add(warped);
    }
    
    Input date 2019-04-19
    +---------------+---------------+--------------+
    | Original Date | Adjusted Date | Within range |
    +---------------+---------------+--------------+
    | 1996-04-13    | 2020-04-13    |              |
    | 1986-04-24    | 2019-04-24    | X            |
    | 1989-04-23    | 2019-04-23    | X            |
    | 1960-05-11    | 2019-05-11    | X            |
    | 1986-05-18    | 2019-05-18    | X            |
    | 1984-04-06    | 2020-04-06    |              |
    | 1997-05-29    | 2019-05-29    |              |
    | 2008-03-31    | 2020-03-31    |              |
    | 2014-04-18    | 2020-04-18    |              |
    | 1982-04-23    | 2019-04-23    | X            |
    +---------------+---------------+--------------+
    
    +---------------+---------------+--------------+
    | Original Date | Adjusted Date | Within range |
    +---------------+---------------+--------------+
    | 2001-12-16    | 2020-12-16    |              |
    | 2005-12-28    | 2019-12-28    | X            |
    | 1988-12-31    | 2019-12-31    | X            |
    | 1989-11-13    | 2020-11-13    |              |
    | 1976-11-13    | 2020-11-13    |              |
    | 1991-01-09    | 2020-01-09    | X            |
    | 1963-11-04    | 2020-11-04    |              |
    | 2001-11-02    | 2020-11-02    |              |
    | 1980-01-11    | 2020-01-11    | X            |
    | 1979-11-17    | 2020-11-17    |              |
    +---------------+---------------+--------------+
    
    如果我们将锚定日期更改为类似于2019-12-20的日期,它可能会生成类似于

    LocalDate now = LocalDate.now();
    int year = now.getYear();
    List<LocalDate> dates = ...;
    List<LocalDate> adjusted = new ArrayList<>(10);
    for (LocalDate date : dates) {
        LocalDate warped = date.withYear(year);
        if (warped.isBefore(now)) {
            warped = warped.withYear(year + 1);
        }
        adjusted.add(warped);
    }
    
    Input date 2019-04-19
    +---------------+---------------+--------------+
    | Original Date | Adjusted Date | Within range |
    +---------------+---------------+--------------+
    | 1996-04-13    | 2020-04-13    |              |
    | 1986-04-24    | 2019-04-24    | X            |
    | 1989-04-23    | 2019-04-23    | X            |
    | 1960-05-11    | 2019-05-11    | X            |
    | 1986-05-18    | 2019-05-18    | X            |
    | 1984-04-06    | 2020-04-06    |              |
    | 1997-05-29    | 2019-05-29    |              |
    | 2008-03-31    | 2020-03-31    |              |
    | 2014-04-18    | 2020-04-18    |              |
    | 1982-04-23    | 2019-04-23    | X            |
    +---------------+---------------+--------------+
    
    +---------------+---------------+--------------+
    | Original Date | Adjusted Date | Within range |
    +---------------+---------------+--------------+
    | 2001-12-16    | 2020-12-16    |              |
    | 2005-12-28    | 2019-12-28    | X            |
    | 1988-12-31    | 2019-12-31    | X            |
    | 1989-11-13    | 2020-11-13    |              |
    | 1976-11-13    | 2020-11-13    |              |
    | 1991-01-09    | 2020-01-09    | X            |
    | 1963-11-04    | 2020-11-04    |              |
    | 2001-11-02    | 2020-11-02    |              |
    | 1980-01-11    | 2020-01-11    | X            |
    | 1979-11-17    | 2020-11-17    |              |
    +---------------+---------------+--------------+
    
    所以它捕捉的是明年登陆的日期


    注意:我随机生成的测试日期在锚定日期的+/-一个月内,以便获得更好的测试数据。

    我认为您需要将其设置为当前年份,以正确计算结束日期。我认为你根本不需要一年来比较开始日期。@shmosel有什么区别?这只是两边的一个常数。闰日可能会影响30天的计算。所以,你想取“原始”日期,将年份改为今年,并检查日期是否在30天之内?@MadProgrammer不,这不是那么简单。计算也应该在12月生效。@RolandIllig这是真的,但我正试图确定另一个例子的基本要求,婚礼是2009-01-14,今天是2019-12-30。预期输出为15天(因此在30天内)。在你的代码片段中,今年的周年纪念日将是2019-01-14,再过-350天。@allanshivji你应该在12月再次问同样的问题,看看它是否仍然适用于你。是的,这是非常相似的代码。我专注于不在代码中重复我自己。由于神奇的数字30,我担心我可能会在代码中犯一些错误,因为只有30作为测试用例会使选择好的测试用例更加困难。我还希望避免将日期拆分为
    (年、月)
    元组,因为它们可能与其他日期混淆。变量更少通常意味着代码更容易理解。哦,我想更多地关注通过良好的测试用例开发可靠代码的过程。