将 java.sql.Timestamp 转换为 javax.xml.datatype.XMLGregorianCalendar 而不会丢失 nanos

Posted

技术标签:

【中文标题】将 java.sql.Timestamp 转换为 javax.xml.datatype.XMLGregorianCalendar 而不会丢失 nanos【英文标题】:convert java.sql.Timestamp to javax.xml.datatype.XMLGregorianCalendar without losing nanos 【发布时间】:2013-11-14 10:27:43 【问题描述】:

java.sql.Timestamp 转换为javax.xml.datatype.XMLGregorianCalendar 的最简洁方法是什么?

鉴于XMLGregorianCalendar 在小数秒内具有BigDecimal 精度,因此不会损失精度,但是鉴于java.sql.Timestamp 与时区无关,我不确定应该在XMLGregorianCalendar 对象上设置哪个时区.

在how to convert java.util.Date to XMLGregorianCalendar 上有一个关于 SO 的答案,所以我可以将我的 Timestamp 转换为 java.util.Date 但这会导致亚毫秒范围内的精度损失,这对于目标数据类型是不必要的 (XMLGregorianCalendar ) 可以保存源数据类型 (Timestamp) 的纳秒部分。

【问题讨论】:

【参考方案1】:

AlexCG answer 在某些情况下不能正常工作(当我们在 nanos 中给出少于 9 位的数字时),例如当我们将 nanos 设置为 25 时,我们会收到如下输出:

Timestamp::2020-01-02 16:30:01.000000025
Calendar:::2020-01-02T16:30:01.25

这不是真的。 这个方法我稍微修改了一下,现在是:

    @Test
    public void convertLocalDataTimeToXmlGCal() throws Exception 

        Timestamp ts = new Timestamp(new Date().getTime());
        ts.setNanos(25);

        LocalDateTime ldt = ts.toLocalDateTime();

        XMLGregorianCalendar cal = DatatypeFactory.newInstance().newXMLGregorianCalendar();

        cal.setYear(ldt.getYear());
        cal.setMonth(ldt.getMonthValue());
        cal.setDay(ldt.getDayOfMonth());
        cal.setHour(ldt.getHour());
        cal.setMinute(ldt.getMinute());
        cal.setSecond(ldt.getSecond());
        String nanos = "0." + StringUtils.leftPad(String.valueOf(ldt.getNano()), 9, '0');
        cal.setFractionalSecond(new BigDecimal(nanos));

        System.out.println("Timestamp::" + ts);
        System.out.println("Calendar:::" + cal);
    

现在输出是正确的:

Timestamp::2020-01-02 16:33:02.000000025
Calendar:::2020-01-02T16:33:02.000000025

需要 Apache Commons 库。

【讨论】:

【参考方案2】:

我正在这样做:

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Date;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

public class ApiRuntime 

    public static void main(String[] args) throws Exception 

        Timestamp ts = new Timestamp(new Date().getTime());
        ts.setNanos(123456789);

        LocalDateTime ldt = ts.toLocalDateTime();

        XMLGregorianCalendar cal = DatatypeFactory.newInstance().newXMLGregorianCalendar();

        cal.setYear(ldt.getYear());
        cal.setMonth(ldt.getMonthValue());
        cal.setDay(ldt.getDayOfMonth());
        cal.setHour(ldt.getHour());
        cal.setMinute(ldt.getMinute());
        cal.setSecond(ldt.getSecond());
        cal.setFractionalSecond(new BigDecimal("0." + ldt.getNano()));

        System.out.println("Timestamp::" + ts);
        System.out.println("Calendar:::" + cal);
    

该示例输出:

Timestamp::2015-08-25 20:59:35.123456789  
Calendar:::2015-08-25T20:59:35.123456789

【讨论】:

【参考方案3】:

java.sql.Timestamp 保存自 1970 年 1 月 1 日 00:00:00 GMT/UTC + nanos 以来的毫秒数。因此,除非您在两者之间做任何愚蠢的事情,否则我建议 based on the XMLGregorianCalendar docs 您将时区设置为 0(UTC)。

【讨论】:

以上是关于将 java.sql.Timestamp 转换为 javax.xml.datatype.XMLGregorianCalendar 而不会丢失 nanos的主要内容,如果未能解决你的问题,请参考以下文章

将 java.time.Instant 转换为没有区域偏移的 java.sql.Timestamp

将 java.sql.Timestamp 转换为 Java 8 ZonedDateTime?

将 java.sql.Timestamp 转换为 javax.xml.datatype.XMLGregorianCalendar 而不会丢失 nanos

如何从 java.sql.Timestamp 转换为 java.util.Date?

无法在 Spring Data Cloud Spanner 中将 java.sql.Timestamp 转换为 com.google.cloud.Timestamp

java的date转换为oracle中的timestamp