JDateTime is an elegant, developer-friendly and yet very precise way to track dates and time. It uses well-defined and proven astronomical algorithms for time manipulation. Everyone who has ever experienced frustration working with JDK Calendar will find this class a big relief.

Julian day

The Julian day or Julian day number (JDN) is the integer number of days that have elapsed since noon Greenwich Mean Time Monday, January 1, 4713 BC. The Julian Date (JD) is the number of days (with decimal fraction of the day) that have elapsed since the same epoch. JDs are the recommended way how to specify time in astronomy.

The Julian day number can be considered a very simple calendar, where its calendar date is just an integer, and time is its fraction. This is useful for reference, computations, and conversions. The beauty of JD lays in the fact that it is easy to calculate time ranges and to roll dates, since just basic math operations addition and subtraction are used. JD allows the time between any two dates in history to be computed by simple subtraction.

The Julian day system was introduced by astronomers to provide a single system of dates that could be used when working with different calendars and to unify different historical chronologies.

Apart from the choice of the zero point and name, this Julian day and Julian date are not directly related to the Julian calendar, although it is possible to convert any date from one calendar to the other.


JDateTime uses JD internally to track current date and time. It uses proven and well tested astronomical algorithms to do all calculations. JDateTime offers precision up to 1 millisecond in all calculations.

Date and time setting

JDateTime can be created in various ways: by specifying desired date and/or time, or by passing a reference of some other date/time related JDK class, by specifying number of system milliseconds, and so on.

JDateTime can be created using specific date/time data. Once created, date and time may be changed in various ways. It is possible to change the complete date/time information (equally to creating new JDateInstance) or just to change it partially (just days, or minutes…).

Using constructor:

    JDateTime jdt = new JDateTime();            // current date and time
    jdt = new JDateTime(2012, 12, 21):          // 21st December 2012, midnight
    jdt = new JDateTime(System.currentTimeMillis());    // current date and time
    jdt = new JDateTime(2012, 12, 21, 11, 54, 22, 124); // 21.Dec.2012,11:54:22.124
    jdt = new JDateTime("2012-12-21 11:54:22.124");     // -//-
    jdt = new JDateTime("12/21/2012", "MM/DD/YYYY");    // 21st Dec. 2012, midnight

Using method:

    JDateTime jdt = new JDateTime();         // current date and time
    jdt.set(2012, 12, 21, 11, 54, 22, 124);  // 21st December 2012, 11:54:22.124
    jdt.set(2012, 12, 21);                   // 21st December 2012, midnight
    jdt.setDate(2012, 12, 21);               // change just date to 21st Dec. 2012
    jdt.setCurrentTime();                    // set current date and time
    jdt.setYear(1973);                       // change the year
    jdt.setHour(22);                         // change the hour
    jdt.setTime(18, 00 12, 853);             // change just time

Reading date and time

Obviously, it is possible to read date/time information from JDateTime. There are getter methods for reading each part: years, months, hours and so on. Days and months are 1-base integers, therefore, JDateTime.JANUARY is 1.

Besides methods for reading single part of date/time information, there are some more convenient methods that return date time information.

getDateTimeStamp() returns DateTimeStamp instance used internally by JDateTime. This class just holds all date/time information in one place.

getJulianDate() returns JulianDateStamp instance used internally by JDateTime. JulianDateStamp holds information about current JD. Due to accuracy problem of floating points, JD information is stored in two separate fields: integer and fraction (JD = integer + fraction). It is possible to get the JD as double value, but this is not accurate (regarding the time), due to fact that integer is very big which leads that fraction looses precision.

Time traveling

JDateTime provides methods for adding or subtracting specific amount of time from current date/time. It is possible to change just single part of date/information or to change more at once.

    jdt.add(1, 2, 3, 4, 5, 6, 7);  // add 1 year, 2 months, 3 days, 4 hours...
    jdt.add(4, 2, 0);              // add 4 years and 2 months
    jdt.addMonth(-120);            // go back 120 months
    jdt.subYear(1);                // go back one year
    jdt.addHour(1234);             // add 1234 hours

It is better to replace sequential time adding/subtraction with single method call, due to performance issues. For example, if some amount of months, minutes and seconds has to be added to current time, it would be faster to add them at once by invoking: add(0, months, 0, 0, minutes, seconds, 0); instead of calling three add methods for month, minutes and seconds respectively.

Adding months is dubious because of variable month length. There are two ways how months may be considered during adding, what will be shown in following example: what is one month from 2003-01-31?

JDateTime has a monthFix flag that defines the month adding behavior. When this flag is off, months are approximated to 31 days. So the result is: 2003-01-31 + 0-1-0 = 2003-03-03.

When monthFix is on (default), month length is ignored. In that case, adding one month will always give the very next month: 2003-01-31 + 0-1-0 = 2003-02-28.

Since adding months is dubious because of variable month length it is a good practice to add days instead.


With JDateTime its easy to calculate period duration in days: just by subtracting two Julian numbers. However, to calculate period duration including hours, minutes, seconds, and milliseconds; its somewhat easier and faster to use class Period.


JDateTime may be easily converted to/from any other time-related classes: GregorianCalendar, java.util.Date, java.sql.Date, Timestamp, DateTimeStamp. Moreover, it is possible to set the date/time of existing instance, instead of creating new one.

    Calendar c = jdt.convertToCalendar();
    jdt.convertTo(GregorianCalendar.class);  // generic way of conversion
    jdt = new JDateTime(gregCalInstance);    // create from GregorianCalendar
    jdt.loadFrom(gregCalInstance);       // load time data from GregorianCalendar
    jdt.storeTo(gregCalInstance);        // store time data to GregorianCalendar

Moreover, it is easy to add custom converters for any class needed.

String conversion

Special attention is put into date/time conversion to and parsing from strings. There are two general ways how to perform conversion: internally, by JDateTime instance, or externally, by passing JDateTime instance to some formatting class.

For all internal conversion and parsing, JDateTime uses so-called formatters, i.e. implementations of JdtFormatter. Formatters follow simple contract (interface) with just two methods that defines how to convert to a string and how to parse from a string using provided format. Format is usually a string template that consist of some patterns. Therefore, one formatter instance may be used in whole application. JDateTime holds formatter and default format that are used for conversion and parsing. Default format is used when no format is provided in conversion/parsing methods.

If the application has to switch often between formatters, it is possible to use JdtFormat for more convenient conversion and parsing - that is a immutable class that holds formatter-format pair.

Finally, since JDateTime may be converted to Date easily, it is possible to use JDKs DateFormatter for converting date/time information to string.

DefaultFormatter is the default formatter used by JDateTime. It uses enhanced patterns specified by ISO 8601 specification, both for conversion and parsing - except parsing recognize less patterns.

Pattern Parsing? Value
YYYY yes year
MM yes month
DD yes day of month
D   day of week
MML   month name long
MMS   month name short
DL   day of week name long
DS   day of week name short
hh yes hour
mm yes minute
ss yes seconds
mss yes milliseconds
DDD   day of year
WW   week of year
WWW   week of year with 'W' prefix
W   week of month
E   era (AD or BC)
TZL   time zone name long
TZS   time zone name short

Template strings for conversion may contains other text besides above patterns, even complete sentence. It is possible to escape some part of template to prevent conversion of some text. Escaping text is done by single quote. Any double single-quote characters inside quoted region is replaces with the single character. Moreover, if some parsing pattern is not recognized it will be ignored.

Usage examples:

    JDateTime jdt = new JDateTime(1975, 1, 1);
    jdt.toString();                     // "1975-01-01 00:00:00.000"
    jdt.toString("YYYY.MM.DD");         // "1975.01.01"
    jdt.toString("MM: MML (MMS)");      // "01: January (Jan)"
    jdt.toString("DD is D: DL (DS)");   // "01 is 3: Wednesday (Wed)"
    JDateTime jdt = new JDateTime(1968, 9, 30);
    jdt.toString("'''' is a sign, W is a week number and 'W' is a letter");
    // "' is a sign, 5 is a week number and W is a letter"

    jdt.parse("2003-11-24 23:18:38.173");
    jdt.parse("2003-11-23");                // 2003-11-23 00:00:00.000
    jdt.parse("01.01.1975", "DD.MM.YYYY");  // 1975-01-01
    jdt.parse("2001-01-31", "YYYY-MM-***"); // 2001-01-01, since day is not parsed

    JDateTime jdt = new JDateTime();
    JdtFormatter fmt = new DefaultFormatter();
    fmt.convert(jdt, "YYYY-MM.DD");         // external conversion

    JdtFormat format = new JdtFormat(new DefaultFormatter(), "YYYY+DD+MM");

    DateFormat df = new SimpleDateFormat();
    df.format(jdt.convertToDate());         // date formatter


By setting locale in JDateTime, it is possible to localize names in resulting conversion string, such as month and date short and long names. When no specific locale is set, JDateTime will use system default locale.

Week definition

JDateTime provides two ways how to define the week, i.e. to define the first day of the week and the what is the first week of the year (for week counting).

setWeekDefinition(start, must) defines what is the start day of the week and what day of the week must be in a year in order to week belongs to that year.

setWeekDefinitionAlt(start, min) is an alternative definition that defines the start day of week and the minimum number of days that week must have in order to belong to a year.

JD Alternatives

Because the starting point is so long ago, numbers in the Julian day (JD) can be quite large and cumbersome. A more recent starting point is sometimes used, for instance by dropping the leading digits, in order to fit into limited computer memory with an adequate amount of precision.

JDateTime is able to convert JD to and from:

  • Reduced Julian Day (RJD),
  • Modified Julian Day (MJD), and
  • Truncated Julian Day (TJD), definition as introduced by NASA.

TimeZones and DST

Julian Date, by definition, is not aware of timezones and daylight saving times (DST). However, JDateTime supports timezones and when timezone is changed (and there is a time zone difference) time will be modified by specific offset. When JDateTime is created, the system default timezone is used. By setting the new time zone, current time is changed according to time zone difference. The following example shows the current time in Japan:

    JDateTime jdt = new JDateTime();

Furthermore, it is possible just to set the timezone, without changing the time. And something useful - to change timezone, using method changeTimeZone().

DST is supported only partially, for now. By default, DST tracking is off (flag: trackDST). When DST tracking is on, JDateTime will track DST only during adding/subtracting the time. What remains is that it is still possible to set invalid time (that, for example, doesn't exist).

jdatetime performace test