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 中的一个时刻,附加一个 Z
。 Z
是 Zulu
的缩写,表示 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 );
我从 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 中的一个时刻,附加一个 Z
。 Z
是 Zulu
的缩写,表示 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 );