Getting Started

Wondering if ChronicJ is something that could actually make your coding life easier? This page will help get you started by providing

  • details about where the source code, mailing lists, etc. reside
  • info on ChronicJ core and subproject package structure
  • a simple usage example

Get ChronicJ

At the moment, a rather confusing situation exists whereby 'ChronicJ' projects have been created at both Source Forge and java.net. For all intents and purposes, however, the active project (CVS source, mailing lists, source and binary releases, etc.) is hosted courtesy of java.net . Although file releases are also made available at Source Forge , project activity there will likely be light until their anonymous cvs and mailing list features become usable.

Right then, sooo, let's start by downloading a versioned release or building ChronicJ from source.

Logical Project Structure

The ChronicJ project is composed of a core set of classes and a few closely related but distinct subprojects. The core classes depend only on the J2SE 1.4.x standard libraries (test cases depend on JUnit ). Although, currently, unverified, these c lasses should be able to run on 1.2 or greater JDKs. Package dependencies look something like this

package dependecies

As you can see in the diagram above, there are several distinct subprojects in addition the core libraries (org.chronicj.*, org.chronicj.impl.*). If you haven't already done so, now would be a good time to read the section on file structure . If you're familiar with Maven, this will be self-explanatory.

The source code , being rather scarce, is an excellent place to start kicking the tires. There's not much of it yet, but JavaDoc comments for all public interfaces have been carefully written. Also, basic usage patterns can be gleaned from the JUnit tests which are pretty comprehensive.

Preview - Temporal Expressions

Based on patterns created by Martin Fowler , temporal expressions allow you to define points or ranges in time using set expressions . For example, say you wanted to schedule an event that occurred annually on the last Thursday of every August.

You could, of course, do something like this:

List someDates = new ArrayList();            

someDates.add((new GregorianCalendar(2002,7,29)).getTime());

someDates.add((new GregorianCalendar(2003,7,28)).getTime());

someDates.add((new GregorianCalendar(2004,7,29)).getTime());

...etc.
    

This is fine for two or three years, but what about for 20 years? What if you want to say every Monday, Tuesday and Friday, between 3 and 5pm for the next two y ears? As you can see, this gets ugly fast.

Using TemporalExpression s provides a reasonably straightforward API for succinctly defining a given set of dates and/or times:

//Avoid using an enumerated list of dates to build a schedule.
//Rather, use set expressions to build a matching set:

//Last Thursday of the month (any month).
TemporalExpression dayInMonthTE = new DayInMonthTE(5, -1);

//From July through August of any year (year can also be specified). 
TemporalExpression rangeEachYearTE1 = new RangeEachYearTE(7, 8);

//From August through September of any year.     
TemporalExpression rangeEachYearTE2 = new RangeEachYearTE(8, 9);

//A temporal expression for matching elements of sets which overlap.
//Concrete type is used because CollectionTE defines the add() method not
//specified in the TemporalExpression interface.
CollectionTE intersectionTE = new IntersectionTE();

//This expression says: last Thursday in August, please 
intersectionTE.add(dayInMonthTE).add(rangeEachYearTE1).add(rangeEachYearTE2);

//A TimePoint is just a java.util.Date that makes it easier to specify 
//and compare date precision; e.g. date vs. date and time, etc.

//TimePoint => last Thursday in August, 2003
System.out.println(intersectionTE.includes(new TimePoint(2003, 8, 28)));  //true

//TimePoint => last Thursday in August, 2002
System.out.println(intersectionTE.includes(new TimePoint(2002, 8, 29)));  //true

//These (hopefully) will not match:

//TimePoint => last Wednesday in August
System.out.println(intersectionTE.includes(new TimePoint(2003, 8, 27)));  //false

//TimePoint => July 28th
System.out.println(intersectionTE.includes(new TimePoint(2003, 7, 28)));  //false

//A DateRange is just the span of time between two TimePoints.
//An ArbitraryDateRangeTE is for specifying one or more arbitrary periods of time (i.e. not recurring).
//So, this expression matches the following time frame:
//11:20pm, Thursday, August 29th, 2002 to 12:15pm, Friday, August 30th, 2002
ArbitraryDateRangeTE arbitraryDateRangeTE =
    new ArbitraryDateRangeTE(
        new DateRange(
            new TimePoint(2002, 8, 29, 23, 20),
            new TimePoint(2002, 8, 30, 0, 15)));

//DifferenceTE implements set exclusion functionality. In other words, 
//the dates and times matched by expr1 - expr2
//specified as constructor arguments like so: new DifferenceTE(expr1,expr2)
CollectionTE differenceTE = new DifferenceTE(intersectionTE, arbitraryDateRangeTE);

//11:19pm, Thursday, August 29th, 2002
System.out.println(differenceTE.includes(new TimePoint(2002, 8, 29, 23, 19)));  //true

//11:20pm, Thursday, August 29th, 2002
System.out.println(differenceTE.includes(new TimePoint(2002, 8, 29, 23, 20)));  //false!
    

These are simple examples, but they demonstrate how TemporalExpressions can be used to define patterns of occurrence and recurrence. Additionally, there are several other TemporalExpressions, and once you get the hang of it, it's easy to write your own.

See Also: