代码之家  ›  专栏  ›  技术社区  ›  Venkat

Java中两个日期之间的天数差异?

  •  80
  • Venkat  · 技术社区  · 14 年前

    我需要找到 :一个来自报告,一个是当前日期。我的代码片段:

      int age=calculateDifference(agingDate, today);
    

    在这里 calculateDifference 是一个私有方法, agingDate today Date Thread 1 / Thread 2

    它在一个独立的程序中工作得很好,尽管当我把它包含到我的逻辑中去阅读报告时,我得到了一个不寻常的值差异。

    编辑:

    public static int calculateDifference(Date a, Date b)
    {
        int tempDifference = 0;
        int difference = 0;
        Calendar earlier = Calendar.getInstance();
        Calendar later = Calendar.getInstance();
    
        if (a.compareTo(b) < 0)
        {
            earlier.setTime(a);
            later.setTime(b);
        }
        else
        {
            earlier.setTime(b);
            later.setTime(a);
        }
    
        while (earlier.get(Calendar.YEAR) != later.get(Calendar.YEAR))
        {
            tempDifference = 365 * (later.get(Calendar.YEAR) - earlier.get(Calendar.YEAR));
            difference += tempDifference;
    
            earlier.add(Calendar.DAY_OF_YEAR, tempDifference);
        }
    
        if (earlier.get(Calendar.DAY_OF_YEAR) != later.get(Calendar.DAY_OF_YEAR))
        {
            tempDifference = later.get(Calendar.DAY_OF_YEAR) - earlier.get(Calendar.DAY_OF_YEAR);
            difference += tempDifference;
    
            earlier.add(Calendar.DAY_OF_YEAR, tempDifference);
        }
    
        return difference;
    }
    

    注:

    不幸的是,没有一个答案能帮我解决这个问题。我已经完成了 this problem 在…的帮助下 Joda-time

    20 回复  |  直到 7 年前
        1
  •  149
  •   kingston    10 年前

    我建议你用最好的 Joda Time 而不是有缺陷的java.util.Date和friends。你可以简单地写

    import java.util.Date;
    import org.joda.time.DateTime;
    import org.joda.time.Days;
    
    Date past = new Date(110, 5, 20); // June 20th, 2010
    Date today = new Date(110, 6, 24); // July 24th 
    int days = Days.daysBetween(new DateTime(past), new DateTime(today)).getDays(); // => 34
    
        2
  •  48
  •   Suji    14 年前

    我可能来不及参加比赛了,但怎么回事

    你认为这是线程问题吗?例如,您如何使用此方法的输出?或者

    我们能否将您的代码更改为执行以下简单的操作:

    Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();
        calendar1.set(<your earlier date>);
        calendar2.set(<your current date>);
        long milliseconds1 = calendar1.getTimeInMillis();
        long milliseconds2 = calendar2.getTimeInMillis();
        long diff = milliseconds2 - milliseconds1;
        long diffSeconds = diff / 1000;
        long diffMinutes = diff / (60 * 1000);
        long diffHours = diff / (60 * 60 * 1000);
        long diffDays = diff / (24 * 60 * 60 * 1000);
        System.out.println("\nThe Date Different Example");
        System.out.println("Time in milliseconds: " + diff
     + " milliseconds.");
        System.out.println("Time in seconds: " + diffSeconds
     + " seconds.");
        System.out.println("Time in minutes: " + diffMinutes 
    + " minutes.");
        System.out.println("Time in hours: " + diffHours 
    + " hours.");
        System.out.println("Time in days: " + diffDays 
    + " days.");
      }
    
        3
  •  23
  •   Eric Leschinski Mr. Napik    11 年前

    diff/(24*etc)不考虑时区,因此如果您的默认时区中有DST,则可以取消计算。

    这个 link 有一个很好的小实现。

    如果链接断开,以上链接的来源如下:

    /** Using Calendar - THE CORRECT WAY**/  
    public static long daysBetween(Calendar startDate, Calendar endDate) {  
      //assert: startDate must be before endDate  
      Calendar date = (Calendar) startDate.clone();  
      long daysBetween = 0;  
      while (date.before(endDate)) {  
        date.add(Calendar.DAY_OF_MONTH, 1);  
        daysBetween++;  
      }  
      return daysBetween;  
    }  
    

    /** Using Calendar - THE CORRECT (& Faster) WAY**/  
    public static long daysBetween(final Calendar startDate, final Calendar endDate)
    {
      //assert: startDate must be before endDate  
      int MILLIS_IN_DAY = 1000 * 60 * 60 * 24;  
      long endInstant = endDate.getTimeInMillis();  
      int presumedDays = 
        (int) ((endInstant - startDate.getTimeInMillis()) / MILLIS_IN_DAY);  
      Calendar cursor = (Calendar) startDate.clone();  
      cursor.add(Calendar.DAY_OF_YEAR, presumedDays);  
      long instant = cursor.getTimeInMillis();  
      if (instant == endInstant)  
        return presumedDays;
    
      final int step = instant < endInstant ? 1 : -1;  
      do {  
        cursor.add(Calendar.DAY_OF_MONTH, step);  
        presumedDays += step;  
      } while (cursor.getTimeInMillis() != endInstant);  
      return presumedDays;  
    }
    
        4
  •  16
  •   Basil Bourque    8 年前

    java.time文件

    在Java8及更高版本中,使用 java.time framework ( Tutorial ).

    Duration

    这个 Duration

    ZonedDateTime now = ZonedDateTime.now();
    ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10);
    Duration duration = Duration.between(oldDate, now);
    System.out.println(duration.toDays());
    

    ChronoUnit

    如果您只需要天数,也可以使用 ChronoUnit enum long 而不是 int .

    long days = ChronoUnit.DAYS.between( then, now );
    
        5
  •  13
  •   athspk RNJ    12 年前
    import java.util.Calendar;
    import java.util.Date;
    
    public class Main {
        public static long calculateDays(String startDate, String endDate)
        {
            Date sDate = new Date(startDate);
            Date eDate = new Date(endDate);
            Calendar cal3 = Calendar.getInstance();
            cal3.setTime(sDate);
            Calendar cal4 = Calendar.getInstance();
            cal4.setTime(eDate);
            return daysBetween(cal3, cal4);
        }
    
        public static void main(String[] args) {
            System.out.println(calculateDays("2012/03/31", "2012/06/17"));
    
        }
    
        /** Using Calendar - THE CORRECT WAY**/
        public static long daysBetween(Calendar startDate, Calendar endDate) {
            Calendar date = (Calendar) startDate.clone();
            long daysBetween = 0;
            while (date.before(endDate)) {
                date.add(Calendar.DAY_OF_MONTH, 1);
                daysBetween++;
            }
            return daysBetween;
        }
    }
    
        6
  •  12
  •   Peter Lawrey    14 年前

    long day1 = ...; // in milliseconds.
    long day2 = ...; // in milliseconds.
    long days = (day2 - day1) / 86400000;
    
        7
  •  9
  •   angelcervera    11 年前

    使用毫秒时间差的解决方案,并对DST日期进行正确的舍入:

    public static long daysDiff(Date from, Date to) {
        return daysDiff(from.getTime(), to.getTime());
    }
    
    public static long daysDiff(long from, long to) {
        return Math.round( (to - from) / 86400000D ); // 1000 * 60 * 60 * 24
    }
    

    注意:当然,日期必须在某个时区。

    重要代码:

    Math.round( (to - from) / 86400000D )
    

    如果不想轮换,可以使用UTC日期,

        8
  •  4
  •   Himanshu THE ONLY ONE    12 年前

    问题的说明:(我的代码是以周为单位计算delta,但同样的问题也适用于以天为单位的delta)

    下面是一个看起来非常合理的实现:

    public static final long MILLIS_PER_WEEK = 7L * 24L * 60L * 60L * 1000L;
    
    static public int getDeltaInWeeks(Date latterDate, Date earlierDate) {
        long deltaInMillis = latterDate.getTime() - earlierDate.getTime();
        int deltaInWeeks = (int)(deltaInMillis / MILLIS_PER_WEEK);
        return deltaInWeeks; 
    }
    

    public void testGetDeltaInWeeks() {
        delta = AggregatedData.getDeltaInWeeks(dateMar09, dateFeb23);
        assertEquals("weeks between Feb23 and Mar09", 2, delta);
    }
    

    原因是:


    2月23日星期一 美国东部时间2009年00:00:00=1235365200000
    毫秒周= 604,800,000
    因此,
    (2009年3月至2月23日)/毫秒周=
    1,206,000,000 / 604,800,000 = 1.994...

        9
  •  3
  •   cesin    11 年前

    我使用这个函数:

    DATEDIFF("31/01/2016", "01/03/2016") // me return 30 days
    

    我的职能:

    import java.util.Date;
    
    public long DATEDIFF(String date1, String date2) {
            long MILLISECS_PER_DAY = 24 * 60 * 60 * 1000;
            long days = 0l;
            SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy"); // "dd/MM/yyyy HH:mm:ss");
    
            Date dateIni = null;
            Date dateFin = null;        
            try {       
                dateIni = (Date) format.parse(date1);
                dateFin = (Date) format.parse(date2);
                days = (dateFin.getTime() - dateIni.getTime())/MILLISECS_PER_DAY;                        
            } catch (Exception e) {  e.printStackTrace();  }   
    
            return days; 
         }
    
        10
  •  2
  •   Peter Elliott    11 年前

    getFragmentInDays apache commons lang类中的方法 DateUtils

        11
  •  2
  •   Chris.Jenkins    11 年前

    基于@Mad\u Troll的答案,我开发了这个方法。

    我已经针对它运行了大约30个测试用例,这是唯一能够正确处理子日时间片段的方法。

    1-1-13 23:59:59.098 1-1-13 23:59:59.099 返回0天,正确;此处发布的其他方法的分配将无法正确执行此操作。

    /**
     * This is not quick but if only doing a few days backwards/forwards then it is very accurate.
     *
     * @param startDate from
     * @param endDate   to
     * @return day count between the two dates, this can be negative if startDate is after endDate
     */
    public static long daysBetween(@NotNull final Calendar startDate, @NotNull final Calendar endDate) {
    
        //Forwards or backwards?
        final boolean forward = startDate.before(endDate);
        // Which direction are we going
        final int multiplier = forward ? 1 : -1;
    
        // The date we are going to move.
        final Calendar date = (Calendar) startDate.clone();
    
        // Result
        long daysBetween = 0;
    
        // Start at millis (then bump up until we go back a day)
        int fieldAccuracy = 4;
        int field;
        int dayBefore, dayAfter;
        while (forward && date.before(endDate) || !forward && endDate.before(date)) {
            // We start moving slowly if no change then we decrease accuracy.
            switch (fieldAccuracy) {
                case 4:
                    field = Calendar.MILLISECOND;
                    break;
                case 3:
                    field = Calendar.SECOND;
                    break;
                case 2:
                    field = Calendar.MINUTE;
                    break;
                case 1:
                    field = Calendar.HOUR_OF_DAY;
                    break;
                default:
                case 0:
                    field = Calendar.DAY_OF_MONTH;
                    break;
            }
            // Get the day before we move the time, Change, then get the day after.
            dayBefore = date.get(Calendar.DAY_OF_MONTH);
            date.add(field, multiplier);
            dayAfter = date.get(Calendar.DAY_OF_MONTH);
    
            // This shifts lining up the dates, one field at a time.
            if (dayBefore == dayAfter && date.get(field) == endDate.get(field))
                fieldAccuracy--;
            // If day has changed after moving at any accuracy level we bump the day counter.
            if (dayBefore != dayAfter) {
                daysBetween += multiplier;
            }
        }
        return daysBetween;
    }
    

    您可以删除 @NotNull 注解,这些注解被Intellij用来动态地进行代码分析

        12
  •  1
  •   Carl Manaster    14 年前

    你说它“在一个独立的程序中工作得很好”,但当你“把它包含到我的逻辑中去阅读报告”时,你会得到“不寻常的差异值”。这表明您的报表有一些无法正常工作的值,而您的独立程序没有这些值。我建议使用一个测试用例,而不是一个独立的程序。编写一个测试用例就像编写一个独立程序一样,从JUnit的TestCase类中进行子类化。现在,您可以运行一个非常具体的示例,知道您期望的值是什么(今天不要给出测试值,因为今天会随着时间的推移而变化)。如果您输入在独立程序中使用的值,您的测试可能会通过。太好了-你想让那些案子继续运作。现在,从报告中添加一个值,一个不正确的值。你的新考试可能会失败。找出它失败的原因,修复它,然后进入绿色(所有测试都通过)。运行你的报告。看看还有什么东西坏了;写一个测试;让它过去。很快你就会发现你的报告起作用了。

        13
  •  1
  •   JRr    10 年前

    这个基本函数有一百行代码???

    只是一个简单的方法:

    protected static int calculateDayDifference(Date dateAfter, Date dateBefore){
        return (int)(dateAfter.getTime()-dateBefore.getTime())/(1000 * 60 * 60 * 24); 
        // MILLIS_IN_DAY = 1000 * 60 * 60 * 24;
    }
    
        14
  •  1
  •   user1091978    10 年前
    public static int getDifferenceIndays(long timestamp1, long timestamp2) {
        final int SECONDS = 60;
        final int MINUTES = 60;
        final int HOURS = 24;
        final int MILLIES = 1000;
        long temp;
        if (timestamp1 < timestamp2) {
            temp = timestamp1;
            timestamp1 = timestamp2;
            timestamp2 = temp;
        }
        Calendar startDate = Calendar.getInstance(TimeZone.getDefault());
        Calendar endDate = Calendar.getInstance(TimeZone.getDefault());
        endDate.setTimeInMillis(timestamp1);
        startDate.setTimeInMillis(timestamp2);
        if ((timestamp1 - timestamp2) < 1 * HOURS * MINUTES * SECONDS * MILLIES) {
            int day1 = endDate.get(Calendar.DAY_OF_MONTH);
            int day2 = startDate.get(Calendar.DAY_OF_MONTH);
            if (day1 == day2) {
                return 0;
            } else {
                return 1;
            }
        }
        int diffDays = 0;
        startDate.add(Calendar.DAY_OF_MONTH, diffDays);
        while (startDate.before(endDate)) {
            startDate.add(Calendar.DAY_OF_MONTH, 1);
            diffDays++;
        }
        return diffDays;
    }
    
        15
  •  1
  •   Community Bob Smith    7 年前

    额外的310

    这个 Answer by Vitalii Fedorenko 是正确的,描述了如何使用 java.time 班级( Duration ChronoUnit )内置于Java8及更高版本(和 back-ported to Java 6 & 7 to Android ).

    Days

    如果您在代码中常规使用天数,则可以使用类来替换整数。这个 Days 类可以在 ThreeTen-Extra 类提供了一种类型安全的方法来表示应用程序中的天数。该类包含方便的常量 ZERO ONE .

    java.util.Date 问题中的对象,首先将它们转换为现代对象 java.time.Instant 物体。旧的日期时间类有新添加的方法,以便于转换为java.time,例如 java.util.Date::toInstant .

    Instant start = utilDateStart.toInstant(); // Inclusive.
    Instant stop = utilDateStop.toInstant();  // Exclusive.
    

    Instant 对象到工厂方法 org.threeten.extra.Days .

    在当前的实现(2016-06)中,这是一个包装调用 java.time.temporal.ChronoUnit.DAYS.between ,阅读 时辰 有关详细信息,请参见类文档。需要说明的是:全部大写 DAYS 时辰 初始cap

    Days days = Days.between( start , stop );
    

    你可以通过这些 ISO 8601 toString . 这种格式的 PnD 使用 P D 指天,中间有几天。在生成和解析表示日期时间值的字符串时,java.time类和ThreeTen Extra默认都使用这些标准格式。

    String output = days.toString();
    

    第3d页

    Days days = Days.parse( "P3D" );  
    
        16
  •  0
  •   Kayvan Tehrani    10 年前

    此代码计算两个日期字符串之间的天数:

        static final long MILLI_SECONDS_IN_A_DAY = 1000 * 60 * 60 * 24;
        static final String DATE_FORMAT = "dd-MM-yyyy";
        public long daysBetween(String fromDateStr, String toDateStr) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);
        Date fromDate;
        Date toDate;
        fromDate = format.parse(fromDateStr);
        toDate = format.parse(toDateStr);
        return (toDate.getTime() - fromDate.getTime()) / MILLI_SECONDS_IN_A_DAY;
    }
    
        17
  •  0
  •   tomrozb    10 年前

    如果你正在寻找一个解决方案,返回正确的数字或天数之间,例如。 11/30/2014 23:59 12/01/2014 00:01

    private int getDayDifference(long past, long current) {
        DateTime currentDate = new DateTime(current);
        DateTime pastDate = new DateTime(past);
        return currentDate.getDayOfYear() - pastDate.getDayOfYear();
    } 
    

    此实现将返回 1 作为一个不同的日子。这里发布的大多数解决方案都以毫秒为单位计算两个日期之间的差异。意思是 0 会被退回,因为这两个日期之间只有2分钟的差距。

        18
  •  0
  •   Å ime Tokić    8 年前

    您应该使用Joda时间库,因为Java Util Date有时返回错误的值。

    Joda vs Java Util日期

    例如,从昨天(dd-mm-yyy,12-07-2016)到1957年的第一天(dd-mm-yyy,01-01-1957)之间的几天:

    public class Main {
    
    public static void main(String[] args) {
        SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
    
        Date date = null;
        try {
            date = format.parse("12-07-2016");
        } catch (ParseException e) {
            e.printStackTrace();
        }
    
        //Try with Joda - prints 21742
        System.out.println("This is correct: " + getDaysBetweenDatesWithJodaFromYear1957(date));
        //Try with Java util - prints 21741
        System.out.println("This is not correct: " + getDaysBetweenDatesWithJavaUtilFromYear1957(date));    
    }
    
    
    private static int getDaysBetweenDatesWithJodaFromYear1957(Date date) {
        DateTime jodaDateTime = new DateTime(date);
        DateTimeFormatter formatter = DateTimeFormat.forPattern("dd-MM-yyyy");
        DateTime y1957 = formatter.parseDateTime("01-01-1957");
    
        return Days.daysBetween(y1957 , jodaDateTime).getDays();
    }
    
    private static long getDaysBetweenDatesWithJavaUtilFromYear1957(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy");
    
        Date y1957 = null;
        try {
            y1957 = format.parse("01-01-1957");
        } catch (ParseException e) {
            e.printStackTrace();
        }
    
        return TimeUnit.DAYS.convert(date.getTime() - y1957.getTime(), TimeUnit.MILLISECONDS);
    }
    

        19
  •  -6
  •   Dayadra Lakmal    11 年前

    Date d1 = jDateChooserFrom.getDate();
    Date d2 = jDateChooserTo.getDate();
    
    Calendar day1 = Calendar.getInstance();
    day1.setTime(d1);
    
    Calendar day2 = Calendar.getInstance();
    day2.setTime(d2);
    
    int from = day1.get(Calendar.DAY_OF_YEAR);
    int to = day2.get(Calendar.DAY_OF_YEAR);
    
    int difference = to-from;