#60 Time API modifications and tests

open
nobody
None
5
2014-07-21
2010-03-16
No

I've been using net.fortuna.ical4j.model.Time instances a bit, and ended up add that some minor API changes to mirror DateTime:

* Added a new single-argument String constructor that interprets the string as a time. If the value has a trailing "Z", then the value is treated as a UTC based time. Otherwise it is treated as a floating time.

* Added a method to fetch the time's timezone.

And I added some tests.

This approach isn't ideal as it doesn't allow separating the different forms of Time. I'll submit an alternative proposal shortly for your consideration.

[These changes are placed in the public domain; relicense them as you like.]

--- source/net/fortuna/ical4j/model/Time.java 2010-03-15 15:55:41 +0000
+++ source/net/fortuna/ical4j/model/Time.java 2010-03-16 23:07:22 +0000
@@ -35,7 +35,9 @@
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
+import java.util.regex.Pattern;

+import net.fortuna.ical4j.util.CompatibilityHints;
import net.fortuna.ical4j.util.Dates;
import net.fortuna.ical4j.util.TimeZones;

@@ -118,6 +120,21 @@
this.utc = utc;
}

+ private static final Pattern UTC_TIME_SPECIFICATION = Pattern.compile("[0-9]+Z");
+ /**
+ * Interpret a string representation of a time instance. If the string has
+ * a trailing "Z", then interpret it as a UTC value. Otherwise interpret it
+ * as a floating time
+ * @param value the time string representing
+ * @throws ParseException where the specified value is not a valid time string
+ */
+ public Time(String value) throws ParseException {
+ this(value,
+ UTC_TIME_SPECIFICATION.matcher(value).matches() ? TimeZone.getTimeZone(TimeZones.UTC_ID)
+ : TimeZones.getDateTimeZone(),
+ UTC_TIME_SPECIFICATION.matcher(value).matches());
+ }
+
/**
* @param value
* @param timezone
@@ -140,12 +157,14 @@
private static java.util.Date parseDate(String value, TimeZone timezone) throws ParseException {
DateFormat df = new SimpleDateFormat(DEFAULT_PATTERN);
df.setTimeZone(timezone);
+ df.setLenient(CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING));
try {
return df.parse(value);
}
catch (ParseException e) {
df = new SimpleDateFormat(UTC_PATTERN);
df.setTimeZone(timezone);
+ df.setLenient(CompatibilityHints.isHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING));
}
return df.parse(value);
}
@@ -156,4 +175,8 @@
public final boolean isUtc() {
return utc;
}
+
+ public java.util.TimeZone getTimeZone() {
+ return getFormat().getTimeZone();
+ }
}

--- test/net/fortuna/ical4j/model/TimeTest.java 2010-03-15 15:55:41 +0000
+++ test/net/fortuna/ical4j/model/TimeTest.java 2010-03-16 20:43:44 +0000
@@ -31,28 +31,170 @@
*/
package net.fortuna.ical4j.model;

+import java.text.DateFormat;
import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;

-import junit.framework.Assert;
import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import net.fortuna.ical4j.util.CompatibilityHints;
+import net.fortuna.ical4j.util.TimeZones;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;

/**
- * @author fortuna
- *
+ * @author Brian de Alwis
*/
public class TimeTest extends TestCase {

- private final TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
+ private final static TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
+
+ private static Log log = LogFactory.getLog(TimeTest.class);
+

/**
* {@inheritDoc}
*/
protected void setUp() throws Exception {
super.setUp();
+
+ // ensure relaxing parsing is disabled for these tests
+ CompatibilityHints.setHintEnabled(CompatibilityHints.KEY_RELAXED_PARSING, false);
+ }
+
+ /**
+ * @param testMethod
+ */
+ public TimeTest(String testMethod) {
+ super(testMethod);
+ }
+
+ public String getName() {
+ if (StringUtils.isNotEmpty(expectedToString)) {
+ return super.getName() + " [" + expectedToString + "]";
+ }
+ return super.getName();
+ }
+
+ private Time time;
+
+ private String expectedToString;
+
+ /**
+ * Default constructor.
+ */
+ public TimeTest(Time time, String expectedToString) {
+ super("testToString");
+ this.time = time;
+ this.expectedToString = expectedToString;
+ }
+
+ /**
+ * Verify that {@link Time#toString()} on {@code #time} is equivalent to {@code #expectedToString}.
+ */
+ public void testToString() {
+ assertNotNull("Null input time", time);
+ assertEquals("Incorrect string representation", expectedToString, time.toString());
+ }
+
+ /**
+ * @return
+ */
+ public static TestSuite suite() throws ParseException {
+ TestSuite suite = new TestSuite();
+
+ // test Time(Date): test that Time on a date only formats the time
+ Calendar cal = Calendar.getInstance(registry.getTimeZone("Australia/Melbourne"));
+ cal.set(Calendar.YEAR, 1984);
+ cal.set(Calendar.MONTH, 3); // months are zero-based...
+ cal.set(Calendar.DAY_OF_MONTH, 17);
+ cal.set(Calendar.HOUR_OF_DAY, 3);
+ cal.set(Calendar.MINUTE, 15);
+ cal.set(Calendar.SECOND, 34);
+ suite.addTest(new TimeTest(new Time(cal.getTime(), cal.getTimeZone()), "031534"));
+
+ // Test(long):
+ suite.addTest(new TimeTest(new Time(cal.getTimeInMillis(), cal.getTimeZone()), "031534"));
+
+
+ // test Time(String) for various formats, including UTC formats
+ suite.addTest(new TimeTest(new Time("020000", TimeZones.getDateTimeZone(), false), "020000"));
+ suite.addTest(new TimeTest(new Time("080000", TimeZones.getDateTimeZone(), false), "080000"));
+ suite.addTest(new TimeTest(new Time("093000", TimeZones.getDateTimeZone(), false), "093000"));
+
+ suite.addTest(new TimeTest(new Time("093000Z", TimeZones.getDateTimeZone(), true), "093000Z"));
+
+ // test Time(String, TimeZone)
+ suite.addTest(new TimeTest(new Time("020000",
+ registry.getTimeZone("Australia/Melbourne")), "020000"));
+ suite.addTest(new TimeTest(new Time("020000", registry.getTimeZone("Australia/Melbourne")), "020000"));
+
+ // other tests..
+ suite.addTest(new TimeTest("testInvalidTimeString"));
+ suite.addTest(new TimeTest("testTimeToStringEquals"));
+ suite.addTest(new TimeTest("testUtc"));
+
+ return suite;
+ }
+
+ /*
+ * Class under test for void Time(String)
+ */
+ public void testInvalidTimeString() throws Exception {
+ try {
+ new Time("1230", java.util.TimeZone.getDefault());
+ fail("Should throw ParseException");
+ }
+ catch (ParseException pe) {
+ log.info("Exception occurred: " + pe.getMessage());
+ }
+
+ try {
+ new Time("1213149",
+ registry.getTimeZone("America/Los_Angeles"));
+ fail("Should throw ParseException");
+ }
+ catch (ParseException pe) {
+ log.info("Exception occurred: " + pe.getMessage());
}
+ }
+
+ /**
+ * Test equality of Time instances {@link #toString()} when created
+ * using different constructors.
+ * @throws ParseException
+ */
+ public void testTimeToStringEquals() throws ParseException {
+ Time date1 = new Time("093000", registry.getTimeZone("Australia/Melbourne"));
+
+ Calendar calendar = Calendar.getInstance(registry.getTimeZone("Australia/Melbourne"));
+ calendar.clear();
+ calendar.set(2005, 0, 1, 9, 30, 00);
+ calendar.set(Calendar.MILLISECOND, 1);
+ Time date2 = new Time(calendar.getTime(), calendar.getTimeZone());

- public void testTimeString() throws ParseException {
- Time time = new Time("020000", registry.getTimeZone("America/Los_Angeles"));
- Assert.assertEquals("020000", time.toString());
+ assertEquals(date1.toString(), date2.toString());
}
+
+ /**
+ * Test UTC date-times.
+ */
+ public void testUtc() throws ParseException {
+ // ordinary date..
+ Time date1 = new Time("093000", registry.getTimeZone("Australia/Melbourne"));
+ assertFalse(date1.isUtc());
+
+ TimeZone utcTz = registry.getTimeZone(TimeZones.UTC_ID);
+ utcTz.setID(TimeZones.UTC_ID);
+
+ // Defined in UTC
+ Time date3 = new Time("093000", utcTz);
+ assertTrue(date3.isUtc());
+ assertEquals("093000Z", date3.toString());
+ }
+
+
}

Discussion

  • Ben Fortuna

    Ben Fortuna - 2010-03-20

    Hi Brian,

    Eclipse doesn't seem to like the format of these patches, are you able to generate them in a different way? Perhaps try attaching to this ticket as a file..

    Thanks for the enhancement, very much appreciated.

    regards,
    ben

     
  • Brian de Alwis

    Brian de Alwis - 2010-04-30

    Sorry Ben, I neglected to update my sourceforge account and your reply went missing. I'll attach a new patch shortly.

     
  • Brian de Alwis

    Brian de Alwis - 2010-04-30

    Reworked patch against HEAD

     

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks