OLEDate java implementation

1.9k views Asked by At

I need a good OLEDate java implementation, and this one does not seem to be working. Is there any known good opensource implementations (like in apache commons)? If not, where do I read about it, so that I write my own implementation?

3

There are 3 answers

0
Chris K On BEST ANSWER

This Old New Thing blog entry seems to be a decent treatise on the topic:

The OLE automation date format is a floating point value, counting days since midnight 30 December 1899. Hours and minutes are represented as fractional days.

If you have access to Visual Studio and the MFC COleDateTime source, you can reimplement that in Java.

0
Koss On

Try this code:

public static Date getDateFromCOMDate(float comtime) {
    String floatstr = String.valueOf(comtime);
    String [] ss = floatstr.split("\\.");
    long nulltime = -2209183200000L;
    long dayms = 86400000;
    int days = Integer.valueOf(ss[0]);
    float prop = comtime - days;
    long cdayms = Math.round(dayms * prop);
    long time = nulltime + days*dayms + cdayms;
    Date d = new Date(time);
    return d;
}
0
Alexander On

The previous implementation is buggy, e.g. wrong dates for 1.0 and -1.25. The implementation below conforms to OLE date described in MSDN, e.g. here: https://msdn.microsoft.com/en-us/library/system.datetime.tooadate(v=vs.110).aspx

Implementation below does conform to the MSDN documentation. It converts a BigDecimal value to Joda LocalDateTime. BigDecimal is better than float and double since it is able to hold a precise value.

class COMDateToRegularDateConverter {
    private static final LocalDateTime ZERO_COM_TIME = new LocalDateTime(1899, 12, 30, 0, 0);
    private static final BigDecimal MILLIS_PER_DAY = new BigDecimal(86400000);

    LocalDateTime toLocalDateTime(BigDecimal comTime) {
        BigDecimal daysAfterZero = comTime.setScale(0, RoundingMode.DOWN);
        BigDecimal fraction = comTime.subtract(daysAfterZero).abs(); //fraction always represents the time of that day
        BigDecimal fractionMillisAfterZero = fraction.multiply(MILLIS_PER_DAY).setScale(0, RoundingMode.HALF_DOWN);

        return ZERO_COM_TIME.plusDays(daysAfterZero.intValue()).plusMillis(fractionMillisAfterZero.intValue());
    }
}