java.text.ParseException: JAVA Android 中无法解析的日期

java.text.ParseException: Unparseable date in JAVA Android

我从 MSSQL 服务器数据库中得到 datetime Default CURRENT_TIMESTAMP 结果,现在我需要解析这个日期、时间等。 数据库结果类似于 2016-05-14 12:54:01.363

我只需要遍历这个日期时间格式。正如我在下面所做的那样。

    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     try
    {
        Date date = format.parse(dateStr);
        SimpleDateFormat todayFormat = new SimpleDateFormat("dd");
        String dateToday = todayFormat.format(date);
        format = dateToday.equals(today) ? new SimpleDateFormat("hh:mm a") : new SimpleDateFormat("dd LLL, hh:mm a");
        String date1 = format.format(date);
        timestamp = date1.toString();
        //
    }
    catch (ParseException e)
    {
        e.printStackTrace();
    }

但我收到以下错误:

    java.text.ParseException: Unparseable date: "{"date":"2016-05-14 12:54:01.363000","timezone":"UTC","timezone_type":3}" (at offset 0)

在第 3 行 .i.e 日期 date = format.parse(dateStr);

需要帮助!

问题取决于您如何构造格式变量,最好使用传入模式而不是默认模式。在你的情况下(参数类似于“2016-05-14 12:54:01.363”,那么格式可能是这样的:

DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date date = format.parse(dateStr);

如果您的 dataStr 由 json 网络服务调用 json 编辑,格式如异常中所示,则您可以将 dateStr 映射到响应类型,例如假设它是名为 MyDate class.

ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"));
MyDate myDate = mapper.readValue(dateStr, MyDate.class);
Date date = myDate.getDate();

如果你不知道 return 类型,你可以简单地将它映射到一个 Map class:

Map dateMap = new ObjectMapper().readValue(dateStr, Map.class);
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
Date date = format.parse(dateMap.get("date"));

微秒

您的问题文本将输入字符串引用为 2016-05-14 12:54:01.363,但您的错误消息另有说明 2016-05-14 12:54:01.363000。那些额外的三个数字是 microseconds.

旧的日期时间 classes,例如 java.util.Date 仅解析为 milliseconds(秒的小数点后 3 位数字)。所以 SimpleDateFormat 无法处理这样的输入。要么截断输入字符串,要么更好地使用现代日期时间 classes。

java.time

更大的问题是您使用的是来自 Java 最早版本的旧的过时日期时间 classes。 classes 已被 java.time framework built into Java 8 and later. Much of that java.time functionality has been back-ported to Java 6 & 7 by the ThreeTen-Backport project, and further adapted to Android by ThreeTenABP 取代。因此,没有理由与那些陈旧且臭名昭著的麻烦 classes.

搏斗

java.time classes 具有更细的粒度,解析为 nanoseconds(秒的小数部分的 9 位)。

在 java.time 中,Instant class is a moment on the timeline in UTC with resolution of nanoseconds. An Instant is the equivalent of a java.util.Date 除了更精细的分辨率。

有关旧类型和 java.time 类型之间转换的详细信息,请参阅 另一个问题。

检索日期时间值作为日期时间类型

您应该从数据库中检索日期时间值作为日期时间类型,而不是字符串。如果您的 JDBC 驱动程序符合 JDBC 4.2(对 JSR 221, and described here), you may be able to retrieve directly into an OffsetDateTime. You can think of an OffsetDateTime as an Instant plus an offset-from-UTC 的更新(小时、分钟和秒数)。

java.time.OffsetDateTime odt = resultSet.getObject( 1 );

如果不是,则退回到使用旧的 java.sql types. For date-time, that means java.sql.Timestamp

java.sql.Timestamp ts = resultSet.getTimestamp( 1 );

尽量减少对旧 java.sql 类型的使用,因为它们是 java.util.Date/.Calendar 等混乱的一部分。立即转换为 java.time。要转换,请寻找添加到旧 classes 的新方法,例如 toInstant.

Instant instant = ts.toInstant();

正在解析

如果您必须解析该输入字符串,最简单的方法是使其符合 ISO 8601 标准格式。当 parsing/generating 个字符串时,java.time classes 默认使用 ISO 8601 格式。

为了遵守,请将中间的 SPACE 替换为 T。并且,假设这个字符串确实代表 UTC 中的一个时刻,附加一个 ZZZulu 的缩写,表示 UTC。

String input = "2016-05-14 12:54:01.363000";
String inputModified = input.replace( " " , "T" );
Instant instant = Instant.parse( inputModified );

时区

这个问题忽略了时区这个关键问题。

最佳做法是以 UTC 格式存储日期时间值。更好的数据库会将传入数据调整为 UTC。当检索为 java.sql.Timestamp 时,您的值采用 UTC,转换为 Instant 时也是如此。

日期和时间取决于时区。将时区 (ZoneId) 应用到您的 Instant 以获得 ZonedDateTime.

ZoneId zoneId = zoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

然后查询得到你需要的日期和时间。

int dayOfMonth = zdt.getDayOfMonth();

如果您希望将一天中的时间本身作为一个对象,请使用 LocalTime class.

LocalTime localTime = zdt.toLocalTime();

如果您确实需要时间字符串,请使用 java.time.format 包。

DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "hh:mm a" );
String output = zdt.format( formatter );

更好的是,让java.time来完成自动格式化的工作。请注意 Locale 的使用,它决定了 (a) 月份名称等人类语言,以及 (b) 文化规范,例如年-月-日等元素的排序。显式指定 Locale 比隐式依赖 JVM 当前的默认 Locale 更好,后者可以在运行时更改。

DateTimeFormatter timeOfDayFormatter = DateTimeFormatter.ofLocalizedTime( FormatStyle.SHORT );
timeOfDayFormatter = timeOfDayFormatter.withLocale( Locale.CANADA_FRENCH );
String output = zdt.toLocalTime().format( timeOfDayFormatter );