You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by rw...@apache.org on 2017/10/23 18:02:33 UTC
svn commit: r1813048 - in /pivot/trunk/core:
src/org/apache/pivot/util/CalendarDate.java
src/org/apache/pivot/util/Time.java
test/org/apache/pivot/util/test/CalendarDateTest.java
test/org/apache/pivot/util/test/TimeTest.java
Author: rwhitcomb
Date: Mon Oct 23 18:02:33 2017
New Revision: 1813048
URL: http://svn.apache.org/viewvc?rev=1813048&view=rev
Log:
PIVOT-1010: Add LocalDate and LocalTime support to our CalendarDate and Time
classes to facilitate interaction with the new Java 8 time classes.
Also make some other changes:
* Add a CalendarDateTest class to test these things.
* Beef up the TimeTest class to actually do some asserts, and to test the
LocalTime conversions.
* Add more supported formats in CalendarDate.Range and Time.Range "decode"
methods: JSON array/list format, and simple CSV list (similar to other
changes to Bounds, Span, etc.)
* Add "equals" and "hashCode" methods to these Range classes.
* Use Utils methods to check parameters.
Added:
pivot/trunk/core/test/org/apache/pivot/util/test/CalendarDateTest.java
Modified:
pivot/trunk/core/src/org/apache/pivot/util/CalendarDate.java
pivot/trunk/core/src/org/apache/pivot/util/Time.java
pivot/trunk/core/test/org/apache/pivot/util/test/TimeTest.java
Modified: pivot/trunk/core/src/org/apache/pivot/util/CalendarDate.java
URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/util/CalendarDate.java?rev=1813048&r1=1813047&r2=1813048&view=diff
==============================================================================
--- pivot/trunk/core/src/org/apache/pivot/util/CalendarDate.java (original)
+++ pivot/trunk/core/src/org/apache/pivot/util/CalendarDate.java Mon Oct 23 18:02:33 2017
@@ -18,12 +18,16 @@ package org.apache.pivot.util;
import java.io.Serializable;
import java.text.NumberFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.pivot.collections.Dictionary;
+import org.apache.pivot.collections.List;
import org.apache.pivot.json.JSONSerializer;
import org.apache.pivot.serialization.SerializationException;
@@ -54,24 +58,24 @@ public final class CalendarDate implemen
this.end = end;
}
+ public Range(String date) {
+ this.start = this.end = CalendarDate.decode(date);
+ }
+
public Range(String start, String end) {
this.start = CalendarDate.decode(start);
this.end = CalendarDate.decode(end);
}
public Range(Range range) {
- if (range == null) {
- throw new IllegalArgumentException("range is null.");
- }
+ Utils.checkNull(range, "range");
this.start = range.start;
this.end = range.end;
}
public Range(Dictionary<String, ?> range) {
- if (range == null) {
- throw new IllegalArgumentException("range is null.");
- }
+ Utils.checkNull(range, "range");
Object startRange = range.get(START_KEY);
Object endRange = range.get(END_KEY);
@@ -102,9 +106,7 @@ public final class CalendarDate implemen
}
public boolean contains(Range range) {
- if (range == null) {
- throw new IllegalArgumentException("range is null.");
- }
+ Utils.checkNull(range, "range");
Range normalizedRange = range.normalize();
@@ -119,9 +121,7 @@ public final class CalendarDate implemen
}
public boolean contains(CalendarDate calendarDate) {
- if (calendarDate == null) {
- throw new IllegalArgumentException("calendarDate is null.");
- }
+ Utils.checkNull(calendarDate, "calendarDate");
boolean contains;
if (this.start.compareTo(this.end) < 0) {
@@ -134,9 +134,7 @@ public final class CalendarDate implemen
}
public boolean intersects(Range range) {
- if (range == null) {
- throw new IllegalArgumentException("range is null.");
- }
+ Utils.checkNull(range, "range");
Range normalizedRange = range.normalize();
@@ -156,10 +154,24 @@ public final class CalendarDate implemen
return new Range(earlier, later);
}
+ @Override
+ public boolean equals(Object o) {
+ if (o != null && o instanceof Range) {
+ Range r = (Range)o;
+ return r.start.equals(this.start) &&
+ r.end.equals(this.end);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ // TODO: is this is a good calculation?
+ return start.hashCode() * end.hashCode();
+ }
+
public static Range decode(String value) {
- if (value == null) {
- throw new IllegalArgumentException();
- }
+ Utils.checkNull(value, "value");
Range range;
if (value.startsWith("{")) {
@@ -168,8 +180,23 @@ public final class CalendarDate implemen
} catch (SerializationException exception) {
throw new IllegalArgumentException(exception);
}
+ } else if (value.startsWith("[")) {
+ try {
+ @SuppressWarnings("unchecked")
+ List<String> values = (List<String>)JSONSerializer.parseList(value);
+ range = new Range(values.get(0), values.get(1));
+ } catch (SerializationException exception) {
+ throw new IllegalArgumentException(exception);
+ }
} else {
- range = new Range(CalendarDate.decode(value));
+ String[] parts = value.split("\\s*[,;]\\s*");
+ if (parts.length == 2) {
+ range = new Range(parts[0], parts[1]);
+ } else if (parts.length == 1) {
+ range = new Range(value);
+ } else {
+ throw new IllegalArgumentException("Invalid format for Range: " + value);
+ }
}
return range;
@@ -212,8 +239,22 @@ public final class CalendarDate implemen
* @param calendar The calendar containing the year, month, and day fields.
*/
public CalendarDate(GregorianCalendar calendar) {
- this(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
- calendar.get(Calendar.DAY_OF_MONTH) - 1);
+ this(calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH),
+ calendar.get(Calendar.DAY_OF_MONTH) - 1);
+ }
+
+ /**
+ * Creates a new <tt>CalendarDate</tt> from the given {@link LocalDate}
+ * (new in Java 8). This does not represent a moment in time, but only
+ * represents a date (as in year, month and day).
+ *
+ * @param localDate The date value containing year, month and day fields.
+ */
+ public CalendarDate(LocalDate localDate) {
+ this(localDate.getYear(),
+ localDate.getMonthValue() - 1,
+ localDate.getDayOfMonth() - 1);
}
/**
@@ -358,6 +399,26 @@ public final class CalendarDate implemen
}
/**
+ * @return An equivalent {@link LocalDate} that represents the same calendar date
+ * as this date.
+ */
+ public LocalDate toLocalDate() {
+ return LocalDate.of(this.year, this.month + 1, this.day + 1);
+ }
+
+ /**
+ * @return A date and time representing this calendar date along with the given
+ * wall clock time.
+ *
+ * @param time The wall clock time to combine with this calendar date.
+ */
+ public LocalDateTime toLocalDateTime(Time time) {
+ LocalTime localTime = LocalTime.of(time.hour, time.minute, time.second, time.millisecond * 1_000_000);
+ LocalDate localDate = toLocalDate();
+ return localDate.atTime(localTime);
+ }
+
+ /**
* Compares this calendar date with another calendar date.
*
* @param calendarDate The calendar date against which to compare.
Modified: pivot/trunk/core/src/org/apache/pivot/util/Time.java
URL: http://svn.apache.org/viewvc/pivot/trunk/core/src/org/apache/pivot/util/Time.java?rev=1813048&r1=1813047&r2=1813048&view=diff
==============================================================================
--- pivot/trunk/core/src/org/apache/pivot/util/Time.java (original)
+++ pivot/trunk/core/src/org/apache/pivot/util/Time.java Mon Oct 23 18:02:33 2017
@@ -18,14 +18,17 @@ package org.apache.pivot.util;
import java.io.Serializable;
import java.text.NumberFormat;
+import java.time.LocalTime;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.pivot.collections.Dictionary;
+import org.apache.pivot.collections.List;
import org.apache.pivot.json.JSONSerializer;
import org.apache.pivot.serialization.SerializationException;
+import org.apache.pivot.util.Utils;
/**
* Class representing a time of day, independent of any particular time zone.
@@ -52,24 +55,24 @@ public final class Time implements Compa
this.end = end;
}
+ public Range(String time) {
+ this.start = this.end = Time.decode(time);
+ }
+
public Range(String start, String end) {
this.start = Time.decode(start);
this.end = Time.decode(end);
}
public Range(Range range) {
- if (range == null) {
- throw new IllegalArgumentException("range is null.");
- }
+ Utils.checkNull(range, "range");
this.start = range.start;
this.end = range.end;
}
public Range(Dictionary<String, ?> range) {
- if (range == null) {
- throw new IllegalArgumentException("range is null.");
- }
+ Utils.checkNull(range, "range");
Object startRange = range.get(START_KEY);
Object endRange = range.get(END_KEY);
@@ -100,9 +103,7 @@ public final class Time implements Compa
}
public boolean contains(Range range) {
- if (range == null) {
- throw new IllegalArgumentException("range is null.");
- }
+ Utils.checkNull(range, "range");
Range normalizedRange = range.normalize();
@@ -117,9 +118,7 @@ public final class Time implements Compa
}
public boolean contains(Time time) {
- if (time == null) {
- throw new IllegalArgumentException("time is null.");
- }
+ Utils.checkNull(time, "time");
boolean contains;
if (this.start.compareTo(this.end) < 0) {
@@ -132,9 +131,7 @@ public final class Time implements Compa
}
public boolean intersects(Range range) {
- if (range == null) {
- throw new IllegalArgumentException("range is null.");
- }
+ Utils.checkNull(range, "range");
Range normalizedRange = range.normalize();
@@ -154,10 +151,24 @@ public final class Time implements Compa
return new Range(earlier, later);
}
+ @Override
+ public boolean equals(Object o) {
+ if (o != null && o instanceof Range) {
+ Range r = (Range)o;
+ return r.start.equals(this.start) &&
+ r.end.equals(this.end);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ // TODO: is this is a good calculation?
+ return start.hashCode() * end.hashCode();
+ }
+
public static Range decode(String value) {
- if (value == null) {
- throw new IllegalArgumentException();
- }
+ Utils.checkNull(value, "value");
Range range;
if (value.startsWith("{")) {
@@ -166,8 +177,23 @@ public final class Time implements Compa
} catch (SerializationException exception) {
throw new IllegalArgumentException(exception);
}
+ } else if (value.startsWith("[")) {
+ try {
+ @SuppressWarnings("unchecked")
+ List<String> values = (List<String>)JSONSerializer.parseList(value);
+ range = new Range(values.get(0), values.get(1));
+ } catch (SerializationException exception) {
+ throw new IllegalArgumentException(exception);
+ }
} else {
- range = new Range(Time.decode(value));
+ String[] parts = value.split("\\s*[,;]\\s*");
+ if (parts.length == 2) {
+ range = new Range(parts[0], parts[1]);
+ } else if (parts.length == 1) {
+ range = new Range(value);
+ } else {
+ throw new IllegalArgumentException("Invalid format for Range: " + value);
+ }
}
return range;
@@ -199,16 +225,16 @@ public final class Time implements Compa
public static final int MILLISECONDS_PER_HOUR = 60 * MILLISECONDS_PER_MINUTE;
public static final int MILLISECONDS_PER_DAY = 24 * MILLISECONDS_PER_HOUR;
- private static final Pattern PATTERN = Pattern.compile("^(\\d{2}):(\\d{2}):(\\d{2})(\\.(\\d{3}))?$");
+ public static final int NANOS_PER_MILLI = 1_000_000;
+
+ private static final Pattern PATTERN = Pattern.compile("^(\\d{1,2}):(\\d{2}):(\\d{2})(\\.(\\d{3}))?$");
public Time() {
this(new GregorianCalendar());
}
public Time(Calendar calendar) {
- if (calendar == null) {
- throw new IllegalArgumentException();
- }
+ Utils.checkNull(calendar, "calendar");
this.hour = calendar.get(Calendar.HOUR_OF_DAY);
this.minute = calendar.get(Calendar.MINUTE);
@@ -220,22 +246,17 @@ public final class Time implements Compa
this(hour, minute, second, 0);
}
- public Time(int hour, int minute, int second, int millisecond) {
- if (hour < 0 || hour > 23) {
- throw new IllegalArgumentException("Invalid hour.");
- }
-
- if (minute < 0 || minute > 59) {
- throw new IllegalArgumentException("Invalid minute.");
- }
-
- if (second < 0 || second > 59) {
- throw new IllegalArgumentException("Invalid second.");
+ private void check(int value, int limit, String part) {
+ if (value < 0 || value > limit) {
+ throw new IllegalArgumentException("Invalid " + part + ".");
}
+ }
- if (millisecond < 0 || millisecond > 999) {
- throw new IllegalArgumentException("Invalid millisecond.");
- }
+ public Time(int hour, int minute, int second, int millisecond) {
+ check(hour, 23, "hour");
+ check(minute, 59, "minute");
+ check(second, 59, "second");
+ check(millisecond, 999, "millisecond");
this.hour = hour;
this.minute = minute;
@@ -262,6 +283,20 @@ public final class Time implements Compa
}
/**
+ * Construct a <tt>Time</tt> from a {@link LocalTime}, rounding
+ * up the nanosecond value to our milliseconds.
+ *
+ * @param localTime The local time to convert.
+ * @see #NANOS_PER_MILLI
+ */
+ public Time(LocalTime localTime) {
+ this(localTime.getHour(),
+ localTime.getMinute(),
+ localTime.getSecond(),
+ ((localTime.getNano() + (NANOS_PER_MILLI / 2)) / NANOS_PER_MILLI));
+ }
+
+ /**
* Adds the specified milliseconds of days to this time and returns the
* resulting time. The number of milliseconds may be negative, in which case
* the result will be a time prior to this time.
@@ -284,25 +319,26 @@ public final class Time implements Compa
* @return The number of milliseconds in between this time and <tt>time</tt>.
*/
public int subtract(Time time) {
- if (time == null) {
- throw new IllegalArgumentException();
- }
+ Utils.checkNull(time, "time");
return toMilliseconds() - time.toMilliseconds();
}
/**
- * Returns the number of milliseconds since midnight represented by this
- * time.
- *
- * @return The number of milliseconds since midnight represented by this
- * time.
+ * @return The number of milliseconds since midnight represented by this time.
*/
public int toMilliseconds() {
return this.hour * MILLISECONDS_PER_HOUR + this.minute * MILLISECONDS_PER_MINUTE
+ this.second * MILLISECONDS_PER_SECOND + this.millisecond;
}
+ /**
+ * @return This time converted to a {@link LocalTime}.
+ */
+ public LocalTime toLocalTime() {
+ return LocalTime.of(this.hour, this.minute, this.second, this.millisecond * NANOS_PER_MILLI);
+ }
+
@Override
public int compareTo(Time time) {
int result = this.hour - time.hour;
Added: pivot/trunk/core/test/org/apache/pivot/util/test/CalendarDateTest.java
URL: http://svn.apache.org/viewvc/pivot/trunk/core/test/org/apache/pivot/util/test/CalendarDateTest.java?rev=1813048&view=auto
==============================================================================
--- pivot/trunk/core/test/org/apache/pivot/util/test/CalendarDateTest.java (added)
+++ pivot/trunk/core/test/org/apache/pivot/util/test/CalendarDateTest.java Mon Oct 23 18:02:33 2017
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.util.test;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import org.apache.pivot.util.CalendarDate;
+import org.apache.pivot.util.Time;
+
+
+public class CalendarDateTest {
+ private static final String d1 = "1941-12-07";
+ private static final String d2 = "1929-10-29";
+ private static final String d3 = "2008-09-29";
+
+ @Test
+ public void test1() {
+ CalendarDate.Range r1 = new CalendarDate.Range(d1);
+ CalendarDate.Range r1a = new CalendarDate.Range(d1, d1);
+ CalendarDate.Range r2 = new CalendarDate.Range(d2, d3);
+ CalendarDate.Range r3 = CalendarDate.Range.decode("{ \"start\" : \"1929-10-29\", \"end\" : \"2008-09-29\"}");
+ CalendarDate.Range r3a = CalendarDate.Range.decode("[ \"1929-10-29\", \"2008-09-29\" ]");
+ CalendarDate.Range r3b = CalendarDate.Range.decode("1929-10-29, 2008-09-29");
+
+ CalendarDate cd1 = CalendarDate.decode(d1);
+ CalendarDate cd2 = CalendarDate.decode(d2);
+ CalendarDate cd3 = CalendarDate.decode(d3);
+
+ assertTrue(r2.contains(r1));
+ assertEquals(r1, r1a);
+ assertEquals(r1.getLength(), 1);
+ assertTrue(r2.normalize().equals(r2));
+ // TODO: more tests of range methods: intersects, etc.
+
+ assertEquals(r3, r3a);
+ assertEquals(r3, r3b);
+ assertEquals(r3a, r3b);
+
+ assertEquals(cd1.year, 1941);
+ assertEquals(cd1.month, 11);
+ assertEquals(cd1.day, 6);
+ assertEquals(cd1.toString(), d1);
+ }
+
+ @Test
+ public void test2() {
+ // PIVOT-1010: test interaction with LocalDate, etc. (new Java 8 classes)
+ LocalDate ld1 = LocalDate.of(1941, 12, 7);
+ CalendarDate cd1 = new CalendarDate(ld1);
+ CalendarDate cd1a = CalendarDate.decode(d1);
+ LocalDate ld1a = cd1a.toLocalDate();
+
+ assertEquals(cd1, cd1a);
+ assertEquals(ld1, ld1a);
+
+ Time t1 = Time.decode("07:48:00");
+ LocalDateTime dt1 = LocalDateTime.of(1941, 12, 7, 7, 48, 0);
+ LocalDateTime dt1a = cd1.toLocalDateTime(t1);
+
+ assertEquals(dt1, dt1a);
+ }
+}
Modified: pivot/trunk/core/test/org/apache/pivot/util/test/TimeTest.java
URL: http://svn.apache.org/viewvc/pivot/trunk/core/test/org/apache/pivot/util/test/TimeTest.java?rev=1813048&r1=1813047&r2=1813048&view=diff
==============================================================================
--- pivot/trunk/core/test/org/apache/pivot/util/test/TimeTest.java (original)
+++ pivot/trunk/core/test/org/apache/pivot/util/test/TimeTest.java Mon Oct 23 18:02:33 2017
@@ -16,8 +16,11 @@
*/
package org.apache.pivot.util.test;
+import java.time.LocalTime;
+
import org.apache.pivot.util.Time;
import org.junit.Test;
+import static org.junit.Assert.assertEquals;
public class TimeTest {
@Test
@@ -32,33 +35,87 @@ public class TimeTest {
System.out.println(time);
time = new Time(0, 0, 0);
- System.out.println(time.subtract(new Time(0, 0, 1)));
- System.out.println(time.subtract(new Time(23, 59, 59, 999)));
-
- time = new Time(0, 0, 0);
- System.out.println(time.add(1));
- System.out.println(time.add(Time.MILLISECONDS_PER_DAY + 1));
- System.out.println(time.add(-1));
- System.out.println(time.add(-Time.MILLISECONDS_PER_DAY - 1));
- System.out.println(time.add(1000));
- System.out.println(time.add(-1000));
+ int i1 = time.subtract(new Time(0, 0, 1));
+ System.out.println(i1);
+ assertEquals(i1, -1000);
+
+ int i2 = time.subtract(new Time(23, 59, 59, 999));
+ System.out.println(i2);
+ assertEquals(i2, -(Time.MILLISECONDS_PER_DAY - 1));
+
+ Time time0 = new Time(0, 0, 0);
+ time = time0;
+ Time time1 = time.add(1);
+ System.out.println(time1);
+ assertEquals(time1.toString(), "00:00:00.001");
+
+ Time time2 = time.add(Time.MILLISECONDS_PER_DAY + 1);
+ System.out.println(time2);
+ assertEquals(time1, time2);
+ assertEquals(time2.toString(), "00:00:00.001");
+
+ Time time3 = time.add(-1);
+ System.out.println(time3);
+ assertEquals(time3.toString(), "23:59:59.999");
+
+ Time time4 = time.add(-Time.MILLISECONDS_PER_DAY - 1);
+ System.out.println(time4);
+ assertEquals(time4.toString(), "23:59:59.999");
+
+ Time time5 = time.add(1000);
+ Time time5a = new Time(0, 0, 1);
+ System.out.println(time5);
+ assertEquals(time5, time5a);
+ assertEquals(time5.toString(), "00:00:01");
+
+ Time time6 = time.add(-1000);
+ Time time6a = new Time(23, 59, 59);
+ System.out.println(time6);
+ assertEquals(time6, time6a);
+ assertEquals(time6.toString(), "23:59:59");
time = Time.decode("00:00:00");
System.out.println(time);
+ assertEquals(time, time0);
time = Time.decode("00:00:00.000");
System.out.println(time);
+ assertEquals(time, time0);
try {
time = Time.decode("00:00");
} catch (IllegalArgumentException exception) {
System.out.println(exception);
+ assertEquals(exception.toString(), "java.lang.IllegalArgumentException: Invalid time format: 00:00");
}
try {
time = Time.decode("00:00:00.00");
} catch (IllegalArgumentException exception) {
System.out.println(exception);
+ assertEquals(exception.toString(), "java.lang.IllegalArgumentException: Invalid time format: 00:00:00.00");
}
}
+
+ @Test
+ public void localTimeTest() {
+ LocalTime localTime = LocalTime.of(7, 48);
+ Time t1 = new Time(localTime);
+ Time t1a = Time.decode("07:48:00.000");
+
+ assertEquals(t1, t1a);
+ assertEquals(t1.toString(), "07:48:00");
+
+ // Test rounding of nanoseconds to milliseconds
+ LocalTime lt1 = LocalTime.of(7, 48, 10, 499999);
+ LocalTime lt2 = LocalTime.of(7, 48, 10, 500000);
+ Time t2 = new Time(lt1);
+ Time t2a = new Time(7, 48, 10, 0);
+ Time t3 = new Time(lt2);
+ Time t3a = new Time(7, 48, 10, 1);
+ assertEquals(t2, t2a);
+ assertEquals(t3, t3a);
+ assertEquals(t2.toString(), "07:48:10");
+ assertEquals(t3.toString(), "07:48:10.001");
+ }
}