SQL日期的Java日期模式(ISO 9075)

Java date pattern for SQL date (ISO 9075)

我试图解析SQL日期字符串(ISO 9075)并使用微秒(!)而不是毫秒,例如

1
2010-11-22 08:08:08.123456

但是,SimpleDateFormat拒绝识别像"yyyy-MM-dd HH:mm:ss.SSSSSS"这样的模式,而"yyyy-MM-dd HH:mm:ss.SSS"也不起作用。

我使用的代码看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
String dateString ="2010-11-22 08:08:08.123456";
String pattern ="yyyy-MM-dd HH:mm:ss.SSSSSS";

try
{
    format = new SimpleDateFormat(pattern);
    format.setLenient(false);
    position.setIndex(0);
    Date date1 = format.parse(dateString, position);
    System.out.println("Date 1:" + date1);
    Date date2 = format.parse(dateString);
    System.out.println("Date 2:" + date1);
}
catch (Exception e) // Should not happen
{
    e.printStackTrace();
}

无论我使用哪两种模式("。SSS"或".SSSSSS"),date1都是打印机为null,而date2会导致解析异常(java.text.ParseException:Unparseable date)。


TL;博士

插入/更新。

1
2
3
4
myPreparedStatement.setObject(
    … ,
    Instant.parse("2010-11-22 08:08:08.123456".replace("" ,"T" ) +"Z" )
) ;

恢复。

1
2
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
String output = ldt.toString().replace("T" ,"" ) ;  // Remove the standard ISO 8601 format’s use of `T` in the middle with the SQL-style SPACE.

java.time

Java 8带来了新的java.time包,以取代臭名昭着的旧java.util.Date,.Calendar和SimpleDateFormat类。那些旧的遗留类限制为毫秒分辨率,而输入字符串具有微秒。您不能将六位小数填充到限制为三的数据类型中。

java.time中的日期时间值具有纳秒分辨率,足以支持您的微秒。这意味着小数秒的最多九位小数。

使用JDBC 4.2及更高版本,直接使用Instant类。

解析输入字符串。要符合java.time类中默认使用的ISO 8601格式,请使用T替换中间的SPACE。您的给定示例必须来自列类型TIMESTAMP WITHOUT TIME ZONE,这意味着不是特定时刻,而不是时间轴上的点。

1
2
String input ="2010-11-22 08:08:08.123456".replace("" ,"T" ) ;
LocalDateTime ldt = LocalDateTime.parse( input ) ;

如果此输入是UTC时刻,请附加Z。然后你有一个时刻,时间轴上的一个特定点。用于列类型TIMESTAMP WITH TIME ZONE

1
2
String input ="2010-11-22 08:08:08.123456".replace("" ,"T" ) +"Z" ;
Instant instant = Instant.parse( input ) ;

发送到您的数据库。

1
myPreparedStatement.setObject( … , instant ) ;

…和…

1
Instant instant = myResultSet.getObject( … , Instant.class ) ;

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧遗留日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在处于维护模式的Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参阅Oracle教程。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。

您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

  • Java SE 8,Java SE 9及更高版本

    • 内置。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小功能和修复。
  • Java SE 6和Java SE 7

    • 许多java.time功能都被反向移植到Java 6& 7在ThreeTen-Backport。
  • Android的

    • 更高版本的Android捆绑java.time类的实现。
    • 对于早期的Android,ThreeTenABP项目采用ThreeTen-Backport(如上所述)。请参见如何使用ThreeTenABP ....

ThreeTen-Extra项目使用其他类扩展了java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的类,例如IntervalYearWeekYearQuarter等。

更新:Joda-Time项目现在处于维护模式,团队建议迁移到java.time类。将此部分保留为历史记录。

乔达时间

如上所述,您应该避免使用java.util.Date,.Calendar和SimpleDateFormat类。从Java 8开始,您可以选择使用java.time或Joda-Time或两者,因为它们各有优缺点。 Joda-Time也适用于早期版本的Java。

您可以使用Joda-Time解析该字符串。

或者,如果您可以访问生成字符串的java.sql.Timestamp,则只需将Timestamp对象传递给DateTime的构造函数即可。我建议也传递一个时区,因为DateTime对象知道他们自己指定的时区。

1
DateTime dateTime = new DateTime( mySqlTimestamp, DateTimeZone.UTC );

要么

1
DateTime dateTime = new DateTime( mySqlTimestamp, DateTimeZone.forID("Europe/Paris" ) );

Joda-Time的分辨率为毫秒。因此,无论采用哪种方式生成DateTime(解析或传递),您都将丢失第二个更精细的部分(忽略/截断,而不是舍入)。


在解析日期之前,可能会从dateString中删除剩余的小数部分?我有以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    String dateString ="2010-11-22 08:08:08.123456";
    String fraction = dateString.substring(dateString.length() - 3);
    String formatString = dateString.substring(0, dateString.length() - 3);
    String pattern ="yyyy-MM-dd HH:mm:ss.SSS";
    ParsePosition position = new ParsePosition(0);

    try
    {

        SimpleDateFormat format = new SimpleDateFormat(pattern);
        format.setLenient(false);
        position.setIndex(0);
        Date date1 = format.parse(formatString, position);          
        System.out.println("Date 1:" + date1);
        System.out.println("Date 1 fraction:" + fraction);
        Date date2 = format.parse(formatString);
        System.out.println("Date 2:" + date2);
        System.out.println("Date 2 fraction:" + fraction);
    }
    catch (Exception e) // Should not happen
    {
        e.printStackTrace();
    }

这允许日期解析到毫秒级精度,同时仍然保留微小部分。


你可能想调用DateFormat解析,因为我认为它会切断字符串。尝试:

1
Date date1 = format.parse(dateString);

另外,请勿使用"SSSSS"。根据规格,只有"SSS"对dateformat有效。

除此之外,我同意在SQL中删除它或解析它。

另外,你有setLenient为false,所以它是严格的。所以字符串越长就会导致它失败。也许这就是它返回null的原因。不确定,将不得不测试。


您可能希望查看DATE4J,它专门尝试处理数据库日期,达到纳秒级精度。


嗯。鉴于Date没有微秒分辨率,如果您知道所有SQL日期字符串在秒小数点后面都有完整的六位数(例如2010-11-22 08:08:08.000000),为什么不切断最后三位数并使用剩下的SimpleDateFormat


如果您可以控制作为java代码输入的SQL日期,您可以尝试以一种可行的格式从SQL中检索日期("yyyy-MM-dd HH:mm:ss.SSS")。