Uploaded image for project: 'PUBLIC - Liferay Portal Community Edition'
  1. PUBLIC - Liferay Portal Community Edition
  2. LPS-29395

DateUtil.getDaysBetween(Date, Date, TimeZone) does not recognize Daylight Saving Time.

    Details

      Description

      DateUtil.getDaysBetween(Date, Date, TimeZone) has a one-off-error around midnight during the TimeZone's Daylight Savings timespan.

      Reproduction is problematic (it's only noticeable in the FriendsActivities Portlet during daylight savings time either when checking between 23:00 and 23:59 or when looking later at an activity from that timespan – the "today" and "yesterday" headers are in the wrong position).

      For testing, I added this code in view.jsp of the FriendsActivities portlet:

      <%!
               public int getDaysCountBetween(Date date1, Date date2, TimeZone timeZone) {
               // copy of com.liferay.portal.kernel.util.DateUtil.getDaysBetween()
               // one line was changed (marked by a comment below)
                       if (date1.after(date2)) {
                               Date tempDate = date1;
                               date1 = date2;
                               date2 = tempDate;
                       }
                       Calendar startCal = null;
                       Calendar endCal = null;
                       int offset = 0; 
                       if (timeZone == null) {
                               startCal = new GregorianCalendar();
                               endCal = new GregorianCalendar();
                       }
                       else {
                               startCal = new GregorianCalendar(timeZone);
                               endCal = new GregorianCalendar(timeZone);
                               offset = timeZone.getOffset(date2.getTime()); // this line is changed compared to trunk
                       }
                       startCal.setTime(date1);
                       startCal.add(Calendar.MILLISECOND, offset);
                       endCal.setTime(date2);
                       endCal.add(Calendar.MILLISECOND, offset);
                       int daysBetween = 0; 
                       while (CalendarUtil.beforeByDay(startCal.getTime(), endCal.getTime())) {
                               startCal.add(Calendar.DAY_OF_MONTH, 1);
       
                               daysBetween++;
                       }
                       return daysBetween;
               }
               %>
      <%
      Format df = FastDateFormatFactoryUtil.getSimpleDateFormat("dd.MM.yyyy HH:mm z", locale, TimeZone.getTimeZone("Europe/Berlin"));
      Date date0 = new SimpleDateFormat().parse("07.07.2012 20:30"); //parsing UTC time!
      Date date1 = new SimpleDateFormat().parse("07.07.2012 21:30");
      Date date2 = new SimpleDateFormat().parse("07.07.2012 22:30");
      Date date3 = new SimpleDateFormat().parse("07.07.2012 23:30");
      Date date4 = new SimpleDateFormat().parse("07.07.2012 24:30");
      %>
      Date0: <%= df.format(date0) %><br/>
      Date1: <%= df.format(date1) %><br/>
      Date2: <%= df.format(date2) %><br/>
      Date3: <%= df.format(date3) %><br/>
      Date4: <%= df.format(date4) %><br/>
      getDaysCountBetween(0, 1): <%= getDaysCountBetween(date0, date1, TimeZone.getTimeZone("Europe/Berlin")) %><br/>
      DateUtil.getDaysBetween(0, 1): <%= DateUtil.getDaysBetween(date0, date1, TimeZone.getTimeZone("Europe/Berlin")) %><br/>
      getDaysCountBetween(1, 2): <%= getDaysCountBetween(date1, date2, TimeZone.getTimeZone("Europe/Berlin")) %><br/>
      DateUtil.getDaysBetween(1, 2): <%= DateUtil.getDaysBetween(date1, date2, TimeZone.getTimeZone("Europe/Berlin")) %><br/>
      getDaysCountBetween(2, 3): <%= getDaysCountBetween(date2, date3, TimeZone.getTimeZone("Europe/Berlin")) %><br/>
      DateUtil.getDaysBetween(2, 3): <%= DateUtil.getDaysBetween(date2, date3, TimeZone.getTimeZone("Europe/Berlin")) %><br/>
      getDaysCountBetween(3, 4): <%= getDaysCountBetween(date3, date4, TimeZone.getTimeZone("Europe/Berlin")) %><br/>
      DateUtil.getDaysBetween(3, 4): <%= DateUtil.getDaysBetween(date3, date4, TimeZone.getTimeZone("Europe/Berlin")) %><br/>
      
      

      The output of this is as follows (getDaysCountBetween is my patched function, DateUtil.getDaysBetween the trunk method; comments added manually):

      Date0: 07.07.2012 22:30 MESZ
      Date1: 07.07.2012 23:30 MESZ
      Date2: 08.07.2012 00:30 MESZ
      Date3: 08.07.2012 01:30 MESZ
      Date4: 08.07.2012 02:30 MESZ
      getDaysCountBetween(0, 1): 0      //correct
      DateUtil.getDaysBetween(0, 1): 0  //correct
      getDaysCountBetween(1, 2): 1      //correct
      DateUtil.getDaysBetween(1, 2): 0  //incorrect
      getDaysCountBetween(2, 3): 0      //correct
      DateUtil.getDaysBetween(2, 3): 1  //incorrect
      getDaysCountBetween(3, 4): 0      //correct
      DateUtil.getDaysBetween(3, 4): 0  //correct
      

      As you see, DateUtil.getDaysBetween() returns the "one day difference" in the wrong case while my corrected version above returns the correct differences. All I did was replacing the line

                                  offset = timeZone.getRawOffset();
      

      with

                                  offset = timeZone.getOffset(date2);
      

      in com.liferay.portal.kernel.util.DateUtil line 153 (method getDaysBetween).

      getRawOffset() is the wrong method to use; I cite from it's javadoc: "Because this value is not affected by daylight saving time, it is called raw offset." (see http://docs.oracle.com/javase/6/docs/api/java/util/TimeZone.html#getRawOffset%28%29)

        Attachments

          Activity

            People

            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since last comment:
                6 years, 19 weeks, 5 days ago

                Packages

                Version Package
                6.2.0 CE M4