Saturday, July 23, 2011

Mapping Dates from COBOL to Java

Date (and Time) types are difficult to map between COBOL and java. Here a few comments on why this is hard.

Dates in COBOL

For a very long time, the COBOL compiler on IBM mainframes didn't know anything about dates. Developers typically used structures and managed dates semantics by hand. The Y2K issue was largely a consequence of this situation since the compiler couldn't solve the problem all by itself.

Recently ("recently" on the mainframe time scale means in the last 15 years or so), IBM introduced the DATE FORMAT keyword. This is used to further qualify a regular numeric or alphabetic data item. It introduces some restrictions on what you can store in the data item but fundamentally, the data item remains a numeric (binary, compressed or zoned decimal) or an alphanumeric.

The DATE FORMAT keyword must be followed by a pattern using Y and X characters (no relationship to chromosomes) such as YYXXXX or YYYYXXXX.

  • YY designates a "windowed" date. This is relative to a century window given by the YEARWINDOW compiler option.
  • YYYY is an "expanded" date. This is a regular century + year date.

MOVE of a windowed date to an expanded date will expand it as expected. There are also intrinsic functions such as DATEVAL and UNDATE to convert dates to non date data items.

For more details, see the programming reference in IBM COBOL documentation.

Dates in Java

If dates are messy in COBOL, well, they are even messier in Java.

At the beginning there was an overly simple java.util.Date (with a weird java.sql.Date variation with 9 methods, 6 of which are deprecated!).

Then came java.sql.Timestamp which inherits from java.util.Date but about which the documentation states: "it is recommended that code not view Timestamp values generically as an instance of java.util.Date". It is as if to say: Timestamp inherits from Date, but please don't use that fact in your programs...

But worst, came the dreaded java.util.Calendar. In this article, Joshua Bloch, an ex Sun engineer, says:

As an extreme example of what not to do, consider the case of java.util.Calendar. Very few people understand its state-space -- I certainly don't -- and it's been a constant source of bugs for years.

java.util.Calendar was designed at a time (long gone now) when Java was to overtake the programming world, so this monster was born and several, often used, java.util.Date methods were deprecated as a consequence.

To further complexify things, JAXB has introduced the javax.xml.datatype.XMLGregorianCalendar in order to map the XML Schema date and time.

All in all, at least 5 different ways of representing a Date

Mapping COBOL dates to Java Dates

So far, Legstar has taken the, rather lame, approach of not attempting to map COBOL dates to Java dates automatically.

When starting from COBOL, this means you will never get a java Date/Timestamp/Calendar property, even if the corresponding COBOL data item is marked with a DATE FORMAT. Date semantics are lost in translation...

When starting from Java though, chances are that some property is a Date/Timestamp/Calendar. Actually Date/Calendar, because with Timestamp you would get "error: java.sql.Timestamp does not have a no-arg default constructor" from JAXB.

LegStar maps Java Date/Calendar properties to a COBOL PIC X(32).

At runtime, the PIC X(32) content is assumed to follow the form: "yyyy-mm-dd hh:mm:ss.fffffffff" known as the JDBC timestamp escape format.

This is rudimentary but following this conversation, the latest LegStar has introduced a new annotation, inspired from Patrick's comment: @CobolJavaTypeAdapter(value = SomeClass.class) where SomeClass is code that a developer implements. (Here is a sample).

An extension mechanism is probably the best way to handle COBOL to Java date binding.