HOWTO use POJava DateTime

DateTime is a class used for parsing, storing, and manipulating Date and Time. It provides a number of advances over Java's Date object, including immutability, nanosecond precision, and calculation functions such as "add" and "truncate". It can parse dates and times without requiring a specific format, and has integrated formatting into its toString() output to make custom formatting simple and elegant.

DateTime has excellent support for business use cases involving multiple time zones, languages, locales and formats. Default behaviors can be customized either globally, for a set of dates sharing a common isolated configuration, or catered to individual DateTime instances.

Parsing Flexibility

DateTime will correctly parse precise date and time from the following strings without specifying any formats.

It supports both MDY and DMY ordering of month and day

A date specified as, say, "11/10/2014" is ambiguous from an international perspective. In some locales, such as the United States or the Phillipines, that date would be interpreted as "2014-11-10" (November 10, 2014). In the vast majority of the world, such as Europe or Brazil, that same date string is interpreted as "2014-10-11" (October 11, 2014). The DateTime object always uses an IDateTimeConfig to resolve such differences, either from the default specified in the DateTimeConfig singleton, or from a custom IDateTimeConfig passed to the constructor as a parameter to determine which interpretation to use.

Let's look at the default behavior. When a DateTime is constructed with no IDateTimeConfig parameter, it looks to DateTimeConfig.getGlobalDefault() to provide a default. If it's defined, it will use it. If not, it will construct and and retain a static instance of DateTimeConfig, which it will initialize based on the system's TimeZone and Locale registered in Java. Specifically, both the parser and formatter will be registered to use the system's default time zone, and the interpretation of DMY vs MDY order will be determined by the system's Locale. A desktop app or a local server using DateTime will typically need no special configuration and things will just work as one would expect.

DateTime dt1=new DateTime("01/02/2003");
// This would, by default, be interpreted by a server in France as 2003-02-01, and as 2003-01-02 on a server in the U.S.

Now, let's say you're hosting a server near the Brazillian west coast, and processing data from a customer in the U.S. east coast which is outputting localized dates in Pacific Daylight Time. You don't want your system defaults to be configured that way, so one way to handle this is to build a custom DateTimeConfig and use that one config to process all dates in the batch.

DateTimeConfigBuilder builder = DateTimeConfigBuilder.newInstance();
builder.setDmyOrder(false);
builder.setInputTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); // Used by parser
builder.setOutputTimeZone(TimeZone.getTimeZone("America/Porto_Velho")); // Used by formatter
IDateTimeConfig config=DateTimeConfig.fromBuilder(builder);
DateTime dt1=new DateTime("01/02/2003 13:30", config);
// This would be interpreted as 2003-01-02 13:30:00 PDT, which is 3 hours behind.
// The toString() output would be "2013-01-02 16:30:00", based on the output time zone.

How do I work with this DateTime class?

Working with DateTime is both easy and powerful. It's designed so that simple tasks are simple and difficult tasks are possible. While mostly intuitive, it helps to understand a few basic concepts.

  1. Internal Representation

    A DateTime represents an instant in time in UTC (Universal Time, Coordinated), informally GMT or Zulu time. You can select the time zone, format, and locale (language) of displayed or printed output.

  2. Relationship with DateTimeConfig

    Every DateTime value is associated with an implementation of IDateTimeConfig. That object holds several variables affecting how DateTime will perform during input, processing, and output of values. When unspecified, the static DateTimeConfig.globalDefault is used. You can specify a time zone or locale in the constructor to override the default. In that case, a wrapper class called LocalConfig is used as a proxy which overrides a few of the variables and serves the others as a pass-through.

  3. Input Rules

    The config.inputTimeZone determines the default time zone assumed for an input string when no time zone is specified in the string itself. The DateTime object will use that time zone to calculate the internal UTC representation of that instant in time, as well as any other input calculations. All formatted outputs are based on config.outputTimeZone.

    DMY vs MDY formatting of dates can be a source of ambiguity, as one may interpret the date 01/02/2003 as February 1, and the other as January 2. You can choose whether the parser interprets such dates in Day/Month/Year order or Month/Day/Year order by setting the value dmyOrder to true or false. Two digit years are also ambiguous. By default, POJava treats such dates as 80 years in the past and 20 years into the future. When a date to parse is known to always be in the past, such as a date of birth, you can set the value config.unspecifiedCenturyAlwaysInPast to true to map 2-digit years to the past 100 years.

  4. Processing Rules

    The config.outputTimeZone is used for DateTime calculations. For example, if a date was parsed from a string specifying "GMT" as the time zone, and the config.OutputTimeZone was set to the "PST" time zone, then the DateTime's truncate(CalendarUnit.Day) would round down to midnight as of the PST time zone. The original config is transferred to the newly calculated DateTime.

  5. Output Rules

    The config.outputTimeZone, config.locale, and config.format values determine the appearance of the toString() output. OutputTimeZone affects what date and hour is displayed for that instant in time. The locale affects the presentation of word values such as month names or days of the week.

Some Examples of DateTime in Use

Basic Parsing in Default Time Zone

String date="26-Feb-2020 9:43:17 pm";
DateTime dt=new DateTime(date);
System.out.println(dt.toString());

Conversion of UTC to Eastern Standard Time

One method is by overriding the toString() format.
String utc="2011/12/13T14:15:16Z";
DateTime dt=new DateTime(utc);
System.out.println(dt.toString("yyyy-MM-dd HH:mm:ss z", TimeZone.getTimeZone("EST"));
Another method is to declare both input and output timezones in the constructor.
String utc="2011/12/13T14:15:16Z";
TimeZone tzUTC=TimeZone.getTimeZone("UTC");
TimeZone tzEST=TimeZone.getTimeZone("EST");
System.out.println(new DateTime(utc, tzUTC, tzEST).toString());