← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 16580: introduce time/tz in dateUnit (finished), proper fix for dst gaps for jt conversions.

 

------------------------------------------------------------
revno: 16580
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2014-08-29 21:30:21 +0545
message:
  introduce time/tz in dateUnit (finished), proper fix for dst gaps for jt conversions.
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/AbstractCalendar.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/ChronologyBasedCalendar.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateTimeUnit.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitPeriodTypeParser.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/impl/NepaliCalendar.java
  dhis-2/dhis-api/src/test/java/org/hisp/dhis/calendar/DateTimeUnitTest.java


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/AbstractCalendar.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/AbstractCalendar.java	2014-08-29 10:02:21 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/AbstractCalendar.java	2014-08-29 15:45:21 +0000
@@ -128,7 +128,7 @@
     public String formattedIsoDate( DateTimeUnit dateTimeUnit )
     {
         dateTimeUnit = toIso( dateTimeUnit );
-        DateTime dateTime = dateTimeUnit.toDateTime();
+        DateTime dateTime = dateTimeUnit.toJodaDateTime();
         DateTimeFormatter format = DateTimeFormat.forPattern( getDateFormat() );
 
         return format.print( dateTime );

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/ChronologyBasedCalendar.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/ChronologyBasedCalendar.java	2014-08-29 10:02:21 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/ChronologyBasedCalendar.java	2014-08-29 15:45:21 +0000
@@ -245,8 +245,7 @@
     @Override
     public int weekday( DateTimeUnit dateTimeUnit )
     {
-        DateTime dateTime = dateTimeUnit.toJodaDateTime( chronology );
-        return dateTime.getDayOfWeek();
+        return dateTimeUnit.toJodaDateTime( chronology ).getDayOfWeek();
     }
 
     @Override

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateTimeUnit.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateTimeUnit.java	2014-08-29 10:02:21 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateTimeUnit.java	2014-08-29 15:45:21 +0000
@@ -28,13 +28,17 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+import com.google.common.base.Objects;
 import org.joda.time.Chronology;
 import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.joda.time.IllegalInstantException;
+import org.joda.time.LocalDateTime;
 import org.joda.time.chrono.ISOChronology;
 
 import javax.validation.constraints.NotNull;
 import java.util.Date;
-import java.util.GregorianCalendar;
+import java.util.TimeZone;
 
 /**
  * Class representing a specific calendar date.
@@ -93,6 +97,11 @@
      */
     private int millis;
 
+    /**
+     * TimeZone for this dateTime instance, defaults to the local tz, used when converting to/from joda/jdk calenders.
+     */
+    private TimeZone timeZone = TimeZone.getDefault();
+
     public DateTimeUnit( boolean iso8601 )
     {
         this.iso8601 = iso8601;
@@ -149,6 +158,21 @@
         this( year, month, day, dayOfWeek, false );
     }
 
+    public void setDate( int year, int month, int day )
+    {
+        this.year = year;
+        this.month = month;
+        this.day = day;
+    }
+
+    public void setTime( int hour, int minute, int second, int millis )
+    {
+        this.hour = hour;
+        this.minute = minute;
+        this.second = second;
+        this.millis = millis;
+    }
+
     public int getYear()
     {
         return year;
@@ -234,19 +258,40 @@
         this.millis = millis;
     }
 
+    public TimeZone getTimeZone()
+    {
+        return timeZone;
+    }
+
+    public void setTimeZone( TimeZone timeZone )
+    {
+        this.timeZone = timeZone;
+    }
+
+    public DateTimeUnit toUtc()
+    {
+        return DateTimeUnit.fromJodaDateTime( toJodaDateTime().toDateTime( DateTimeZone.UTC ), true );
+    }
+
     /**
      * Converts dateUnit to Joda-Time DateTime
      *
      * @return Populated DateTime object
      */
-    public DateTime toDateTime()
+    public DateTime toJodaDateTime()
     {
-        if ( !iso8601 )
-        {
-            throw new RuntimeException( "Cannot convert non-ISO8601 DateUnit to DateTime." );
-        }
-
-        return new DateTime( year, month, day, 12, 0, ISOChronology.getInstance() );
+        try
+        {
+            return new DateTime( year, month, day, hour, minute, second, millis, ISOChronology.getInstance( DateTimeZone.forTimeZone( timeZone ) ) );
+        }
+        catch ( IllegalInstantException ex )
+        {
+            LocalDateTime localDateTime = new LocalDateTime( year, month, day, hour, minute, second, millis,
+                ISOChronology.getInstance( DateTimeZone.forTimeZone( timeZone ) ) );
+
+            return localDateTime.toLocalDate().toDateTimeAtStartOfDay();
+        }
+
     }
 
     /**
@@ -257,7 +302,7 @@
      */
     public DateTime toJodaDateTime( Chronology chronology )
     {
-        return new DateTime( year, month, day, 12, 0, chronology );
+        return toJodaDateTime().withChronology( chronology );
     }
 
     /**
@@ -267,15 +312,7 @@
      */
     public java.util.Calendar toJdkCalendar()
     {
-        if ( !iso8601 )
-        {
-            throw new RuntimeException( "Cannot convert non-ISO8601 DateUnit to JDK Calendar." );
-        }
-
-        java.util.Calendar calendar = new GregorianCalendar( year, month - 1, day );
-        calendar.setTime( calendar.getTime() );
-
-        return calendar;
+        return toJodaDateTime().toGregorianCalendar();
     }
 
     /**
@@ -285,7 +322,7 @@
      */
     public Date toJdkDate()
     {
-        return toJdkCalendar().getTime();
+        return toJodaDateTime().toDate();
     }
 
     /**
@@ -308,7 +345,13 @@
      */
     public static DateTimeUnit fromJodaDateTime( DateTime dateTime, boolean iso8601 )
     {
-        return new DateTimeUnit( dateTime.getYear(), dateTime.getMonthOfYear(), dateTime.getDayOfMonth(), dateTime.getDayOfWeek(), iso8601 );
+        DateTimeUnit dateTimeUnit = new DateTimeUnit( iso8601 );
+        dateTimeUnit.setDate( dateTime.getYear(), dateTime.getMonthOfYear(), dateTime.getDayOfMonth() );
+        dateTimeUnit.setDayOfWeek( dateTime.getDayOfWeek() );
+        dateTimeUnit.setTime( dateTime.getHourOfDay(), dateTime.getMinuteOfHour(), dateTime.getSecondOfMinute(), dateTime.getMillisOfSecond() );
+        dateTimeUnit.setTimeZone( dateTime.getZone().toTimeZone() );
+
+        return dateTimeUnit;
     }
 
     /**
@@ -319,8 +362,7 @@
      */
     public static DateTimeUnit fromJdkCalendar( java.util.Calendar calendar )
     {
-        return new DateTimeUnit( calendar.get( java.util.Calendar.YEAR ), calendar.get( java.util.Calendar.MONTH ) + 1,
-            calendar.get( java.util.Calendar.DAY_OF_MONTH ), calendar.get( java.util.Calendar.DAY_OF_WEEK ), true );
+        return fromJodaDateTime( new DateTime( calendar ) );
     }
 
     /**
@@ -334,18 +376,24 @@
         return fromJodaDateTime( new DateTime( date.getTime() ), true );
     }
 
+    // Note that we do not include dayOfWeek in equals/hashCode, this might not always be set
     @Override
     public boolean equals( Object o )
     {
         if ( this == o ) return true;
         if ( o == null || getClass() != o.getClass() ) return false;
 
-        DateTimeUnit dateTimeUnit = (DateTimeUnit) o;
+        DateTimeUnit that = (DateTimeUnit) o;
 
-        if ( day != dateTimeUnit.day ) return false;
-        if ( iso8601 != dateTimeUnit.iso8601 ) return false;
-        if ( month != dateTimeUnit.month ) return false;
-        if ( year != dateTimeUnit.year ) return false;
+        if ( day != that.day ) return false;
+        if ( hour != that.hour ) return false;
+        if ( iso8601 != that.iso8601 ) return false;
+        if ( millis != that.millis ) return false;
+        if ( minute != that.minute ) return false;
+        if ( month != that.month ) return false;
+        if ( second != that.second ) return false;
+        if ( year != that.year ) return false;
+        if ( !timeZone.equals( that.timeZone ) ) return false;
 
         return true;
     }
@@ -357,17 +405,28 @@
         result = 31 * result + month;
         result = 31 * result + day;
         result = 31 * result + (iso8601 ? 1 : 0);
+        result = 31 * result + hour;
+        result = 31 * result + minute;
+        result = 31 * result + second;
+        result = 31 * result + millis;
+        result = 31 * result + timeZone.hashCode();
         return result;
     }
 
     @Override
     public String toString()
     {
-        return "DateUnit{" +
-            "year=" + year +
-            ", month=" + month +
-            ", day=" + day +
-            ", iso8601=" + iso8601 +
-            '}';
+        return Objects.toStringHelper( this )
+            .add( "year", year )
+            .add( "month", month )
+            .add( "day", day )
+            .add( "dayOfWeek", dayOfWeek )
+            .add( "iso8601", iso8601 )
+            .add( "hour", hour )
+            .add( "minute", minute )
+            .add( "second", second )
+            .add( "millis", millis )
+            .add( "timeZone", timeZone )
+            .toString();
     }
 }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitPeriodTypeParser.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitPeriodTypeParser.java	2014-08-29 10:02:21 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/DateUnitPeriodTypeParser.java	2014-08-29 15:45:21 +0000
@@ -106,7 +106,7 @@
             int day = Integer.parseInt( matcher.group( 3 ) );
 
             DateTimeUnit dateTimeUnit = new DateTimeUnit( year, month, day );
-            dateTimeUnit.setDayOfWeek(calendar.weekday( dateTimeUnit ));
+            dateTimeUnit.setDayOfWeek( calendar.weekday( dateTimeUnit ) );
 
             return new DateInterval( dateTimeUnit, dateTimeUnit );
         }
@@ -115,27 +115,27 @@
             int year = Integer.parseInt( matcher.group( 1 ) );
             int week = Integer.parseInt( matcher.group( 2 ) );
 
-            if ( week < 1 || week > calendar.weeksInYear(year) )
+            if ( week < 1 || week > calendar.weeksInYear( year ) )
             {
                 return null;
             }
 
             DateTimeUnit start = new DateTimeUnit( year, 1, 1 );
-            start = calendar.minusDays(start, calendar.weekday(start) - 1); // rewind to start of week
+            start = calendar.minusDays( start, calendar.weekday( start ) - 1 ); // rewind to start of week
 
             // since we rewind to start of week, we might end up in the previous years weeks, so we check and forward if needed
-            if ( calendar.isoWeek(start) == calendar.weeksInYear(year) )
+            if ( calendar.isoWeek( start ) == calendar.weeksInYear( year ) )
             {
-                start = calendar.plusWeeks(start, 1);
+                start = calendar.plusWeeks( start, 1 );
             }
 
-            start = calendar.plusWeeks(start, week - 1);
+            start = calendar.plusWeeks( start, week - 1 );
             DateTimeUnit end = new DateTimeUnit( start );
-            end = calendar.plusWeeks(end, 1);
-            end = calendar.minusDays(end, 1);
+            end = calendar.plusWeeks( end, 1 );
+            end = calendar.minusDays( end, 1 );
 
-            start.setDayOfWeek( calendar.weekday(start) );
-            end.setDayOfWeek( calendar.weekday(end) );
+            start.setDayOfWeek( calendar.weekday( start ) );
+            end.setDayOfWeek( calendar.weekday( end ) );
 
             return new DateInterval( start, end );
         }
@@ -145,10 +145,10 @@
             int month = Integer.parseInt( matcher.group( 2 ) );
 
             DateTimeUnit start = new DateTimeUnit( year, month, 1 );
-            DateTimeUnit end = new DateTimeUnit( year, month, calendar.daysInMonth(start.getYear(), start.getMonth()) );
+            DateTimeUnit end = new DateTimeUnit( year, month, calendar.daysInMonth( start.getYear(), start.getMonth() ) );
 
-            start.setDayOfWeek( calendar.weekday(start) );
-            end.setDayOfWeek(calendar.weekday(end));
+            start.setDayOfWeek( calendar.weekday( start ) );
+            end.setDayOfWeek( calendar.weekday( end ) );
 
             return new DateInterval( start, end );
         }
@@ -164,11 +164,11 @@
 
             DateTimeUnit start = new DateTimeUnit( year, (month * 2) - 1, 1 );
             DateTimeUnit end = new DateTimeUnit( start );
-            end = calendar.plusMonths(end, 2);
-            end = calendar.minusDays(end, 1);
+            end = calendar.plusMonths( end, 2 );
+            end = calendar.minusDays( end, 1 );
 
-            start.setDayOfWeek( calendar.weekday(start) );
-            end.setDayOfWeek(calendar.weekday(end));
+            start.setDayOfWeek( calendar.weekday( start ) );
+            end.setDayOfWeek( calendar.weekday( end ) );
 
             return new DateInterval( start, end );
         }
@@ -185,11 +185,11 @@
 
             DateTimeUnit start = new DateTimeUnit( year, ((quarter - 1) * 3) + 1, 1 );
             DateTimeUnit end = new DateTimeUnit( start );
-            end = calendar.plusMonths(end, 3);
-            end = calendar.minusDays(end, 1);
+            end = calendar.plusMonths( end, 3 );
+            end = calendar.minusDays( end, 1 );
 
-            start.setDayOfWeek( calendar.weekday(start) );
-            end.setDayOfWeek(calendar.weekday(end));
+            start.setDayOfWeek( calendar.weekday( start ) );
+            end.setDayOfWeek( calendar.weekday( end ) );
 
             return new DateInterval( start, end );
         }
@@ -206,11 +206,11 @@
 
             DateTimeUnit start = new DateTimeUnit( year, semester == 1 ? 1 : 7, 1 );
             DateTimeUnit end = new DateTimeUnit( start );
-            end = calendar.plusMonths(end, 6);
-            end = calendar.minusDays(end, 1);
+            end = calendar.plusMonths( end, 6 );
+            end = calendar.minusDays( end, 1 );
 
-            start.setDayOfWeek( calendar.weekday(start) );
-            end.setDayOfWeek(calendar.weekday(end));
+            start.setDayOfWeek( calendar.weekday( start ) );
+            end.setDayOfWeek( calendar.weekday( end ) );
 
             return new DateInterval( start, end );
         }
@@ -227,11 +227,11 @@
 
             DateTimeUnit start = new DateTimeUnit( year, semester == 1 ? 4 : 10, 1 );
             DateTimeUnit end = new DateTimeUnit( start );
-            end = calendar.plusMonths(end, 6);
-            end = calendar.minusDays(end, 1);
+            end = calendar.plusMonths( end, 6 );
+            end = calendar.minusDays( end, 1 );
 
-            start.setDayOfWeek( calendar.weekday(start) );
-            end.setDayOfWeek(calendar.weekday(end));
+            start.setDayOfWeek( calendar.weekday( start ) );
+            end.setDayOfWeek( calendar.weekday( end ) );
 
             return new DateInterval( start, end );
         }
@@ -241,10 +241,10 @@
 
             DateTimeUnit start = new DateTimeUnit( year, 1, 1 );
             DateTimeUnit end = new DateTimeUnit( year, calendar.monthsInYear(),
-                calendar.daysInMonth(start.getYear(), calendar.monthsInYear()) );
+                calendar.daysInMonth( start.getYear(), calendar.monthsInYear() ) );
 
-            start.setDayOfWeek(calendar.weekday(start));
-            end.setDayOfWeek( calendar.weekday(end) );
+            start.setDayOfWeek( calendar.weekday( start ) );
+            end.setDayOfWeek( calendar.weekday( end ) );
 
             return new DateInterval( start, end );
         }
@@ -254,11 +254,11 @@
 
             DateTimeUnit start = new DateTimeUnit( year, 4, 1 );
             DateTimeUnit end = new DateTimeUnit( start );
-            end = calendar.plusYears(end, 1);
-            end = calendar.minusDays(end, 1);
+            end = calendar.plusYears( end, 1 );
+            end = calendar.minusDays( end, 1 );
 
-            start.setDayOfWeek( calendar.weekday(start) );
-            end.setDayOfWeek(calendar.weekday(end));
+            start.setDayOfWeek( calendar.weekday( start ) );
+            end.setDayOfWeek( calendar.weekday( end ) );
 
             return new DateInterval( start, end );
         }
@@ -268,11 +268,11 @@
 
             DateTimeUnit start = new DateTimeUnit( year, 7, 1 );
             DateTimeUnit end = new DateTimeUnit( start );
-            end = calendar.plusYears(end, 1);
-            end = calendar.minusDays(end, 1);
+            end = calendar.plusYears( end, 1 );
+            end = calendar.minusDays( end, 1 );
 
-            start.setDayOfWeek( calendar.weekday(start) );
-            end.setDayOfWeek(calendar.weekday(end));
+            start.setDayOfWeek( calendar.weekday( start ) );
+            end.setDayOfWeek( calendar.weekday( end ) );
 
             return new DateInterval( start, end );
         }
@@ -282,11 +282,11 @@
 
             DateTimeUnit start = new DateTimeUnit( year, 10, 1 );
             DateTimeUnit end = new DateTimeUnit( start );
-            end = calendar.plusYears(end, 1);
-            end = calendar.minusDays(end, 1);
+            end = calendar.plusYears( end, 1 );
+            end = calendar.minusDays( end, 1 );
 
-            start.setDayOfWeek( calendar.weekday(start) );
-            end.setDayOfWeek(calendar.weekday(end));
+            start.setDayOfWeek( calendar.weekday( start ) );
+            end.setDayOfWeek( calendar.weekday( end ) );
 
             return new DateInterval( start, end );
         }

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/impl/NepaliCalendar.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/impl/NepaliCalendar.java	2014-08-29 10:02:21 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/calendar/impl/NepaliCalendar.java	2014-08-29 15:45:21 +0000
@@ -72,7 +72,7 @@
             return dateTimeUnit;
         }
 
-        DateTime dateTime = startIso.toDateTime();
+        DateTime dateTime = startIso.toJodaDateTime();
 
         int totalDays = 0;
 
@@ -96,8 +96,8 @@
     @Override
     public DateTimeUnit fromIso( DateTimeUnit dateTimeUnit )
     {
-        DateTime start = startIso.toDateTime();
-        DateTime end = dateTimeUnit.toDateTime();
+        DateTime start = startIso.toJodaDateTime();
+        DateTime end = dateTimeUnit.toJodaDateTime();
 
         return plusDays( startNepal, Days.daysBetween( start, end ).getDays() );
     }

=== modified file 'dhis-2/dhis-api/src/test/java/org/hisp/dhis/calendar/DateTimeUnitTest.java'
--- dhis-2/dhis-api/src/test/java/org/hisp/dhis/calendar/DateTimeUnitTest.java	2014-08-29 10:02:21 +0000
+++ dhis-2/dhis-api/src/test/java/org/hisp/dhis/calendar/DateTimeUnitTest.java	2014-08-29 15:45:21 +0000
@@ -28,14 +28,15 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-import static org.junit.Assert.assertEquals;
+import org.joda.time.DateTime;
+import org.junit.Test;
 
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
+import java.util.TimeZone;
 
-import org.joda.time.DateTime;
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
 
 /**
  * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
@@ -80,7 +81,7 @@
     public void toDateTimeTest()
     {
         DateTimeUnit dateTimeUnit = new DateTimeUnit( 2014, 3, 20, true );
-        DateTime dateTime = dateTimeUnit.toDateTime();
+        DateTime dateTime = dateTimeUnit.toJodaDateTime();
 
         assertEquals( 2014, dateTime.getYear() );
         assertEquals( 3, dateTime.getMonthOfYear() );
@@ -107,4 +108,40 @@
         assertEquals( 3, dateTimeUnit.getMonth() );
         assertEquals( 20, dateTimeUnit.getDay() );
     }
+
+    @Test
+    public void defaultTimeZoneTest()
+    {
+        assertEquals( TimeZone.getDefault(), new DateTimeUnit().getTimeZone() );
+    }
+
+    @Test
+    public void adjustedTimeZoneTest()
+    {
+        TimeZone timeZone = TimeZone.getTimeZone( "Asia/Ho_Chi_Minh" ); // UTC/GMT +7.00 hours
+
+        DateTimeUnit dateTimeUnit = new DateTimeUnit( true );
+        dateTimeUnit.setDate( 2014, 3, 20 );
+        dateTimeUnit.setTime( 14, 0, 0, 0 );
+        dateTimeUnit.setTimeZone( timeZone );
+
+        assertEquals( 7, dateTimeUnit.toUtc().getHour() );
+    }
+
+    // Test for JT conversion exception:
+    // Illegal instant due to time zone offset transition (daylight savings time 'gap'): 1986-01-01T00:00:00.000 (Asia/Kathmandu)
+    @Test
+    public void illegalInstantGapTest()
+    {
+        TimeZone timeZone = TimeZone.getTimeZone( "Asia/Kathmandu" );
+
+        DateTimeUnit dateTimeUnit = new DateTimeUnit( true );
+        dateTimeUnit.setDate( 1986, 1, 1 );
+        dateTimeUnit.setTime( 0, 0, 0, 0 );
+        dateTimeUnit.setTimeZone( timeZone );
+
+        dateTimeUnit.toJodaDateTime();
+
+        System.err.println( "tz: " + timeZone );
+    }
 }