=== 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 @@ -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 ); + } }