OLEDate java implementation

六月ゝ 毕业季﹏ 提交于 2019-11-29 15:48:59

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.

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;
}

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());
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!