【问题标题】:Conversion of string with AM/PM date-time, from Oracle database从 Oracle 数据库转换具有 AM/PM 日期时间的字符串
【发布时间】:2012-05-04 15:57:42
【问题描述】:

我有03-AUG-12 08.15.00.000000000 PM -05:00 形式的时间戳 我无法在yyyy-MM-dd HH:mm:ss 上以表格形式获得String 代表。

这是我的代码:

public static void convert() {

    String oldstring = "03-AUG-12 08.15.00.000000000 PM -05:00";
    Date date = null;
    try {
        date = new SimpleDateFormat("dd-MMM-yy HH.mm.ss.S aa").parse(oldstring);
    }
    catch (ParseException e) {
        e.printStackTrace();
    }

    String newstring = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
    System.out.println(newstring);
}

基本上它是来自 Oracle 数据库的具有时区格式的时间戳。

【问题讨论】:

  • 你的预期输出是什么?
  • 预期输出为:2012-08-03 20:15:00 检索输出为:2012-08-03 08:15:00 即 PM 部分未反映在输出中。
  • 看我的回答。 PM 部分被忽略,因为您在解析日期时使用HH 而不是hh
  • @Java:您还忽略了时间戳字符串中的时区。看我的回答。

标签: java parsing simpledateformat java.util.date


【解决方案1】:

你不能使用 SimpleDateFormat 来解析这样一个字符串,至少不是没有一些限制:

  • Java 7 之前不支持像 -05:00(根据 ISO 8601)这样的时区指示符。使用 Java 7,您可以使用 XXX 模式对其进行解析。

  • 要正确解析月份名称,您应该指定您需要英语语言环境。

  • 以毫秒 (S) 为单位的模式解析无限位数的数字。如果您的字符串包含“08.15.00.100000000”,SimpleDateFormat 会将其解析为 8:15:00 和 100000000 毫秒,从而为预期值增加近 28 小时。如果您确定该值始终为 0,则可以忽略此问题。

如果您可以接受最后一个问题并使用 Java 7,那么您应该使用如下内容:

new SimpleDateFormat("dd-MMM-yy hh.mm.ss.S aa XXX", Locale.ENGLISH)

【讨论】:

  • @Jambjo - 非常感谢您对 Java 7 功能的深入了解,因为我没有意识到这一点。我应该如何在结果集中成功地获取该值(从 oracle db 中带有时间戳的 Timezone 类型的列),因为我没有看到带有 resultSet.getTimeStampWithTimezone 或类似内容的结果集操作? while(resultSet.next()){ java.sql.Timestamp getTimeStamp = resultSet.getTimestamp("date_val"); } 我目前正在使用 Java 6。请帮我解决这个问题。我需要从数据库中获取,将其解析为我在问题中提到的格式并检索一个字符串。等待答复。
  • 为什么需要数据库中的时区? resultSet.getTimestamp() 有什么问题?
【解决方案2】:

像这样改变这一行:

        date = new SimpleDateFormat("dd-MMM-yy hh.mm.ss.S aa").parse(oldstring);

您需要使用小写 h 来解析 AM/PM 小时 1-12。

【讨论】:

  • 感谢您提及小写字母 h。丹克!
【解决方案3】:

tl;博士

DateTimeFormatter f = new DateTimeFormatterBuilder ().parseCaseInsensitive ().appendPattern ( "dd-MMM-yy hh.mm.ss.SSSSSSSSS a ZZZZZ" ).toFormatter ().withLocale ( Locale.US );
OffsetDateTime odt = OffsetDateTime.parse ( "03-AUG-12 08.15.00.000000000 PM -05:00" , f );

对象,而不是字符串

您提到了甲骨文。从数据库中检索数据时,使用对象而不是字符串。向您的 ResultSet 询问 java.sql.Timestamp 对象。

java.sql.Timestamp ts = myResultSet.getTimestamp( … );

从麻烦的旧日期时间类转换为现代 java.time 类型。寻找在旧类上添加的新方法,以促进与 java.time 之间的转换。

Instant instant = ts.toInstant();

或者最好是,如果使用 JDBC 4.2 或更高版本,并且使用 Java 8 或更高版本,您可以通过 ResultSet::getObject 方法检索 java.time.Instant

但如果您必须解析字符串,请继续阅读。

避免使用旧的日期时间类

与最早的 Java 版本捆绑在一起的旧日期时间类既麻烦又令人困惑。现在被 java.time 类所取代。

纳秒

那一串零必须以nanosecond 的分辨率表示几分之一秒,最多九位小数。旧的日期时间类只能处理 milliseconds,但幸运的是现代 java.time 类确实可以处理高达纳秒的分辨率。

使用 java.time

定义一个格式化模式来解析给定的输入。顺便说一句,您的数据格式不是最佳的;将来,对表示日期时间值的字符串使用ISO 8601 标准格式。

我们使用“构建器”来指定不区分大小写的解析。英文月份名称的正确缩写是 initial-cap,Aug,但您的输入使用全大写。

String pattern = "dd-MMM-yy hh.mm.ss.SSSSSSSSS a ZZZZZ";
DateTimeFormatterBuilder fb = new DateTimeFormatterBuilder ().parseCaseInsensitive ().appendPattern ( pattern );

告诉构建器实例化我们的格式化程序。 Locale 决定 (a) 用于翻译日期名称、月份名称等的人类语言,以及 (b) 决定缩写、大写、标点符号等问题的文化规范。

Locale l = Locale.US;
DateTimeFormatter f = fb.toFormatter ().withLocale ( l );

最后,将字符串解析为OffsetDateTime 对象。

String input = "03-AUG-12 08.15.00.000000000 PM -05:00";
OffsetDateTime odt = OffsetDateTime.parse ( input , f );

转储到控制台。请注意我们的晚上 8 点如何转换为 24-hour clock 值 20 小时。

System.out.println ( "input: " + input + " | odt.toString(): " + odt );

输入:03-AUG-12 08.15.00.000000000 PM -05:00 | odt.toString(): 2012-08-03T20:15-05:00

time zoneoffset-from-UTC 加上一组用于处理夏令时 (DST) 等异常的规则。如果需要,请申请 ZoneId 以获取 ZonedDateTime

ZoneId z = ZoneId.of( “America/Montreal” );
ZonedDateTime zdt = odt.atZoneSameInstant( z );

关于java.time

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

Joda-Time 项目现在位于maintenance mode,建议迁移到 java.time。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。

大部分 java.time 功能在ThreeTen-Backport 中向后移植到Java 6 和7,并进一步适应ThreeTenABP 中的Android(参见How to use…)。

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuarter 等等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-16
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多