Question

I have a database table, which is filled with data from a mainframe via ETL. One column of that table is called "TOD" as in Time-Of-Day.

This columns stores values such as : "CAE7631DC43DC686" "CAE7631C4AC6DC0B" "CAE6216DF2BC0D04" "CAE621D8F9916E8E"

all these values are around Feb 10th 2013 and Feb 11th 2013. now, on mainframe, this is a time-date representation (TOD clock).

it represents the time past from 01.01.1900 in macroseconds (1/1 000 000 of a second).

What I need is a java library / method / algorithm implementation that could convert these strings to java.util.Date's.

Found these sites on the web : http://paul.saers.com/Tod_howto.html http://www.longpelaexpertise.com.au/toolsTOD.php

This page explains how to calculate it, but it's a little too much for me. I'm sure I'd do some errors somewhere.

So, my question is; do you know about a library (Joda Time ?) that I could use ? I need to convert these value to a java.util.Date and a Date object to a string representation, (like "CAE621D8F9916E8E").

Thanks in advance.

Was it helpful?

Solution 2

Step by step, using Joda:

Data used in the calculation can be found on the website you referred to The other reference you gave states that TOD is expressed in UTC

// we start with your string minus the three last digits
// which are some internal z/Series cruft
BigInteger bi = new BigInteger    ("CAE7631DC43DC", 16); // 686 stripped off
// then, from tables the website we get the TOD value for start of epoch
// here also, minus the three last digits                                 
BigInteger startOfEpoch70 = new BigInteger ("7D91048BCA000", 16); // 000 stripped off
// using that we calculate the offset in microseconds in epoch
BigInteger microsinepoch = bi.subtract(startOfEpoch70);
// and reduce to millis
BigInteger millisinepoch = microsinepoch.divide(new BigInteger("1000"));
// which we convert to a long to feed to Joda
long millisinepochLong = millisinepoch.longValue();
// Et voila, the result in UTC
DateTime result = new DateTime(millisinepochLong).withZone(DateTimeZone.UTC);
// Now, if you want a result in some other timezone, that's equally easy
// with Joda:
DateTime result2 = result.toDateTime(DateTimeZone.forID("EET"));

System.out.println("The result is " + result + " or represented in timezone EET "
                   + result2);

Which gives this output:

The result is 2013-02-10T21:59:46.420Z or represented in timezone EET 2013-02-10T23:59:46.420+02:00

The "cruft" I refer to is explained as follows:

We skip the last 12 bits (normally,some of these bits are used by MVS to tell what processor was used to read the TOD clock and what LPAR was active).

Of course, instead of brutally snipping these bytes off the string, one could also do

bi = bi.divide(new BigInteger("1000", 16));

as dividing by hex 1000 will also get rid of the last 12 bits.

EDIT: as Mehmet pointed out in the comments, TOD is in UTC and this means that the resulting DateTime should be told so. For convenience I also showed how to transpose that DateTime to another time zone (using EET as an example)

OTHER TIPS

In my use case I have a getter method that directly reads the 8 bytes TOD as byte array and translates it into a long, but here to adhere to the poster:

BigInteger bi = new BigInteger    ("CAE7631DC43DC686", 16); //  no strip off of 686 
long tod = bi2.longValue();

I used the following to avoid the BigDecimal calculation overhead:

tod = tod >>> 12;  // remove rightmost 3 bytes and replace with zeros
tod = tod - 2208988800000000l;  // substract 1970
tod = tod/1000; // make millis out of micros
// timeformatter and dateformatter without Joda
SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm:ss.SS z Z", Locale.getDefault());
SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault());
// Display
System.out.println(timeFormatter.format(new Date(tod)));
System.out.println(dateFormatter.format(new Date(tod)));

The output will be:

22:59:46.420 CET +0100

10.02.2013

Parse your hex date using BigInteger:

new BigInteger("CAE7631DC43DC686", 16);

Then do the necessary conversions to the Unix epoch using the various methods offered by BigInteger (multiply, ...).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top