繁体   English   中英

Oracle - 如何在不格式化的情况下将 Java 项目中的时间戳作为字符串插入

[英]Oracle - How can i insert timestamp from Java Project as String without formatting

在 spring 项目中,有一个 sql 数据将值插入到 oracle 数据库中。 如果我尝试插入时间戳,我会收到 ORA-Exception(无效月份)。

INSERT INTO TAB (colTimestamp)
VALUES ('2020-05-07-10.05.05.301011')

为什么那不是一个有效月份?

在 DB2 中没有问题。 那么我应该以哪种格式插入时间戳? 我也试过2019-05-05 10:10:10但我得到了同样的异常 如何插入时间戳? oracle 中时间戳的默认格式是什么?

您需要使用使用 ISO 格式格式化的正确时间戳文字:

timestamp '2020-05-07 10:05:05.301011'

所以没有-在日期和时间之间,和:分隔小时、分钟和秒。 我相信同样适用于 DB2。

如果您通过 JDBC 进行插入,则不应以字符串开头。 使用PreparedStatement并传递java.time.LocalDateTime或至少java.sql.Timestamp的实例

a_horse_with_no_name答案是正确的。 这里有更多的细节和例子。

您的输入字符串不符合以下两个条件:

  • SQL 格式:YYYY-MM-DD HH:MM:SS
  • ISO 8601格式:YYYY-MM-DDTHH:MM:SS(用T分隔日期和时间)

相比之下,您的输入字符串中间有一个连字符,并且无法使用冒号字符来分隔小时-分钟-秒。

java.time解析或生成字符串时,默认使用 ISO 8601 格式。

String input = "2020-05-07T10:05:05.301011" ;
LocalDateTime ldt = LocalDateTime.parse( input ) ;

对于在 Java 中工作,您应该在准备好的语句中将对象作为占位符的值而不是作为String对象中的文本传递。

String sql = "INSERT INTO some_table ( some_timestamp ) VALUES ( ? ) ;" ;
myPreparedStatement.setObject( 1 , ldt ) ;

如果您坚持使用纯文本而不是对象,请对日期时间输入使用 SQL 格式。 我会简单地采用java.time 中默认生成的 ISO 8601 输出并将T替换为空格。

String sql = String sql = "INSERT INTO some_table ( some_timestamp ) VALUES ( " + ldt.toString().replace( "T" , " " ) + " ) ;" ;

或者,您可以使用DateTimeFormatter对象生成该文本。 搜索堆栈溢出,因为它已经被多次覆盖。

片刻

您的代码中还有另一个关键问题。 您对“时间戳”一词的使用表明您正在尝试跟踪某个时刻,即时间轴上的特定点。 您的输入字符串无法做到这一点。 您的输入缺少UTC 偏移量(本初子午线之前/之后的时分秒数)或时区Continent/Region格式名称)的上下文。

以您输入的 10 AM 为例。 我们无法知道您是指日本东京的上午 10 点还是美国俄亥俄州托莱多的上午 10 点,这两个非常不同的时刻相隔许多小时。

如果您要跟踪时刻,则必须使用:

  • 类型类似于 SQL 标准TIMESTAMP WITH TIME ZONE数据库列。
  • 这些 Java 类之一: InstantOffsetDateTimeZonedDateTime (JDBC 4.2 中只需要支持OffsetDateTime )。

例子:

OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC ) ;  // Capture the current moment in UTC. 

要将时刻表示为文本,您应该使用 ISO 8601 格式以Z (对于 UTC,偏移量为零)、偏移量(例如+05:30 )或偏移量后跟方括号中的时区名称. 最后一个是java.time.ZonedDateTime类使用的 ISO 8601 的非标准扩展。

Instant instant = Instant.parse( "2020-05-07T10:05:05.301011Z" ) ;

JDBC 4.2 需要支持OffsetDateTime而不是Instant 您的 JDBC 驱动程序可能支持Instant ,但如果不支持,请转换。

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;

跟踪时刻时,切勿使用类似于 SQL 标准类型TIMESTAMP WITHOUT TIME ZONE的数据库类型。 并且永远不要使用 Java 类LocalDateTime片刻。 两者都故意缺少时区或UTC偏移量的上下文。

Java(旧版和现代版)和标准 SQL 中的日期时间类型表

请遵循 ISO 日期格式,以便 Oracle 接受它作为日期。

例1:

INSERT INTO TAB (colTimestamp)
VALUES ('2020-05-07 10:05:05.301011')

例2:

INSERT INTO TAB (colTimestamp)
VALUES ('2020-05-07T10:05:05.301011')

语法是 - YYYY-MM-DD hh:mi:ss.SS

LocalDateTime 的格式,至少由 Java DateFormatter 所采用,将是:


    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-MM-dd hh:mm:ss.SS");
    LocalDateTime localDateTime = LocalDateTime.of(2021, 12, 31, 14, 30, 15, 300);
    System.out.println(formatter.format(localDateTime));

这会给:

2022-12-31 02:30:15.00

时间

下表描述了 ANSI SQL 类型与java.time类型的映射:

ANSI SQL Java SE 8
日期 本地日期
时间 当地时间
时间戳 本地日期时间
时区时间 偏移时间
带时区的时间戳 偏移日期时间

假设您的数据库列的类型为TIMESTAMP ,您可以将给定的日期时间字符串解析为LocalDateTime ,如下所示:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String strDateTime = "2020-05-07-10.05.05.301011";
        
        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                                .append(DateTimeFormatter.ISO_LOCAL_DATE)
                                .appendLiteral("-")
                                .appendPattern("HH.mm.ss")
                                .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
                                .toFormatter(Locale.ENGLISH);
        
        LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);
        System.out.println(ldt);
    }
}

输出:

2020-05-07T10:05:05.301011

在线演示

现在,您可以将此LocalDateTime存储到数据库中,如下所示:

PreparedStatement st = conn.prepareStatement("INSERT INTO mytable (columnfoo) VALUES (?)");
st.setObject(1, ldt);
st.executeUpdate();
st.close();

下面给出了从 columnfoo 检索 LocalDate 的示例代码:

Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM mytable WHERE <some condition>");
while (rs.next()) {
    // Assuming the column index of columnfoo is 1
    LocalDateTime ldt = rs.getObject(1, LocalDateTime.class));
    System.out.println(ldt);
}
rs.close();
st.close();

Trail: Date Time 中了解有关现代日期时间 API * 的更多信息。


* 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 通过 desugaring 可用的 Java 8+ API 请注意,Android 8.0 Oreo 已提供java.time支持

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM