计算日期差异时的奇怪值

时间:2017-12-08 15:11:11

标签: java date date-difference java.util.date java.util.calendar

我一直在使用以下代码来计算两个日期之间的差异,我收到了一个不寻常的错误:

如果我通过以下日期:

d1 = 08/12/2017 d2 = 31/07/2022

它返回:24055 ..

是不是应该以月数返回的结果?

 public static int CalcDateDiff( java.util.Date  date1,  java.util.Date  date2) {
    if(date1 == null || date2 ==null )
    {
        if(date2 == null)
        {
              Calendar d1 = Calendar.getInstance();
                d1.setTime(date1);
                final Calendar d2 = Calendar.getInstance();
                int diff = (d2.get(Calendar.YEAR) - d1.get(Calendar.YEAR)) * 12 + d2.get(Calendar.MONTH) - d1.get(Calendar.MONTH);

                return diff;
        }
        else
            return -1;
    }
    else
    {

            Calendar d1 = Calendar.getInstance();
            d1.setTime(date1);
            final Calendar d2 = Calendar.getInstance();
            d2.setTime(date2);
            int diff = (d2.get(Calendar.YEAR) - d1.get(Calendar.YEAR)) * 12 + d2.get(Calendar.MONTH) - d1.get(Calendar.MONTH);

            return diff;
        }
}

提前致谢!

2 个答案:

答案 0 :(得分:1)

最佳解决方案:

如果您已经有java.sql.Date个实例,那么

final Date d1 = new java.sql.Date(2017 - 1900, 12, 8);
final Date d2 = new java.sql.Date(2022 - 1900, 07, 31);
  

我知道我在java.sql.Date中使用了一个弃用的构造函数,这只是为了方便在最少的代码行中获得我需要的东西。   永远不要在生产代码中使用此构造函数!

最简单,最简单的自我记录方式来获得你想要的东西:

final long monthsBetween ChronoUnit.MONTHS.between(d1.toLocalDate(),d2.toLocalDate()) + 1;

因为使用这种方法,您不必使用TimeZone信息,因为对于以这种方式创建的LocalDate实例,所有信息都是正确的。

出于某种原因,只有java.sql.Date只有.toLocalDate()这对您有好处,因为这是您从数据库中获取的内容。

  

public LocalDate toLocalDate()   将此Date对象转换为   LocalDate转换创建一个表示相同的LocalDate   日期值作为本地时区的日期

     

返回:表示相同日期值的LocalDate对象   以来:   1.8

对代码更正的评论:

正确的公式是:

(y2 - y1) * 12 + (m2 - m1) + 1

此外,您的代码过于复杂,使用的是非常旧的类。

Java 8解决方案和Java 7兼容的更正解决方案:

public class Q47717075
{
    /*
    https://stackoverflow.com/questions/1086396/java-date-month-difference
     */
    public static void main(@Nonnull final String[] args)
    {
        final Date d1 = new java.sql.Date(2017 - 1900, 12, 8);
        final Date d2 = new java.sql.Date(2022 - 1900, 07, 31);
        System.out.println(CalcDateDiff(d1, d2));
        /* Obtains an instance of Instant from a text string such as 2007-12-03T10:15:30.00Z. */
        System.out.println(intervalInMonths(LocalDate.of(2017,12,8), LocalDate.of(2022,7,31)));
        System.out.println(ChronoUnit.MONTHS.between(d1.toLocalDate(),d2.toLocalDate()) + 1);
    }


    /*
       Alternate Java 8 version
     */
    public static int intervalInMonths(@Nonnull final LocalDate i1, @Nonnull final LocalDate i2)
    {
        final Period p = Period.between(i1, i2);
        return (p.getYears() * 12) + p.getMonths() + 1;
    }

    /**
     * Your versin corrected
     */
    public static int CalcDateDiff(@Nonnull final Date date1, @Nonnull final Date date2)
    {
        final Calendar d1 = Calendar.getInstance();
        d1.setTime(date1);
        final Calendar d2 = Calendar.getInstance();
        d2.setTime(date2);

        return ((d2.get(YEAR) - d1.get(YEAR)) * 12 + (d2.get(MONTH) - d1.get(MONTH)) + 1);
    }
}

正确的输出是:

56
56
56

答案 1 :(得分:0)

TL;博士

ChronoUnit.MONTHS.between(                                           // Use enum method to calculate elapsed time.
    date1.toInstant().atZone( ZoneId.of( "Africa/Casablanca " ) ) ,  // Convert from legacy `Date` class to modern `java.time.Instant` class. Adjust from UTC to a specific time zone. 
    date2.toInstant().atZone( ZoneId.of( "Africa/Casablanca " ) ) 
)                                                                    // Return a number of months elapsed. 

详细

Answer by Roberson很好。这是另一种选择。

您对麻烦的Date课程的使用现已过时。 java.time包中的Instant替换了该遗留类。两者都代表片刻,UTC中时间轴上的一个点。现代课程的分辨率为nanoseconds而不是milliseconds

使用添加到旧类的新方法进行转换。

Instant instant = myUtilDate.toInstant() ;

要确定几个月,我们需要日期。确定日期需要时区。对于任何特定时刻,日期在全球范围内因地区而异。

ZoneId z = ZoneId.of( "Pacific/Auckland " ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

ChronoUnit枚举提供between方法来计算已用时间。

long months = ChronoUnit.MONTHS.between( zdt1 , zdt2 ) ;