为什么 Java SimpleDateFormat 在某些服务器上工作而不在其他服务器上工作?
Why does Java SimpleDateFormat work on some servers and not others?
问候堆栈溢出,
我正在为位于雅典的外国办事处实施的应用程序遇到了一个奇怪的问题运行。构建时,应用程序是一个 .war 文件,部署在 Tomcat 实例上。
只是为了了解一些背景信息,这个相同的应用程序在美国和其他国家/地区的几个不同 OS(Ubuntu 12.04、Windows Server 2012 R2 等)上成功运行Java/Tomcat 配置不同的国家/地区。
然而,我用来安装 Athens 应用程序的 OS 是 Windows Server 2008 R2。此服务器上安装的是 Java JRE 1.8。0_111 由 Tomcat 8.5.4 使用。此服务器位于雅典。
应用程序一切正常,除了我向控制器方法提交日期字段的任何地方。在应用程序的各个不同部分尝试将日期字符串提交到我的控制器时,我收到以下消息:
Failed to convert the value of 'java.lang.String' to required type'java.util.Date';
nested exception is java.lang.illegalArgumentException: Could not parse text
[7/28/2017 7:00 AM] into any available date input formats.
请记住,当我将此应用程序部署到另一台服务器上的 Tomcat 实例时,一切正常,我没有收到此错误消息。
为了解决此错误,我决定更改其中一个请求参数的类型:
@RequestParam("date") Date date
到
@RequestParam("date") String dateString
然后我使用 Java SimpleDateFormat 将字符串转换为日期:
SimpleDateFormat sdf_date = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
String startDate = dateString;
Date date = sdf_date.parse(startDate);
传递给上述函数的日期字符串是:
11/25/2017 12:00 pm
我在几台具有不同 OS/Tomcat 配置的测试服务器上对此进行了测试,效果非常好。但是,在位于雅典的 Windows 2008 R2 服务器上进行测试时,我仍然收到错误消息。我不再收到上述错误,但我确实收到以下内容:
java.text.ParseException: Unparseable date: "11/25/2017 12:00 pm"
我不确定为什么同样的 Java 代码能够在某些服务器上使用相同的 SimpleDateFormat 模式解析相同的日期,而在其他服务器上则不能。这对我来说似乎很奇怪。
如果您需要任何其他信息,请告诉我,我很乐意澄清。
谢谢!
编辑:雅典服务器上的服务器端调试屏幕截图:
'dateString' 正在传递给控制器方法
希腊不使用与许多其他讲拉丁语的国家相同的 am/pm 名称。希腊改为使用 π.µ。和µ.µ。因此,当 SimpleDateFormat 没有收到语言环境时,它假定它与计算机 运行 程序相同。
要解决此问题,请尝试以下操作:
SimpleDateFormat sdf_date = new SimpleDateFormat("MM/dd/yyyy hh:mm a", new Locale("en", "US"));
String startDate = dateString;
Date date = sdf_date.parse(startDate);
这将在此服务器上使用带有美国语言环境的英语。不过,您仍然需要确保这是在每种情况下输入中传递的格式。
tl;博士
Instant.parse( "2017-11-25T12:00:00Z" )
详情
是正确的。
另外,还有3个问题。解决这些问题将消除您在处理本地化文本格式方面的问题。
时区
你忽略了关键的时区问题。如果未指定,您将隐式依赖 JVM 当前的默认时区。该默认值可能会有所不同,即使在运行时(!),所以最好明确指定您 desired/expected 时区。
通常最好使用 UTC,除非您有特定原因。
ISO 8601
ISO 8601 标准为表示日期时间值的文本定义了实用的明确格式。
暂时使用 UTC 时间轴,使用 YYYY-MM-DDTHH:MM:SS.SSSSSSSSSZ,其中 T
将日期部分与时间部分分开,Z
是Zulu的简称,表示UTC,时间采用24小时制(没有AM/PM)。
将日期时间值序列化为文本时使用这些标准格式。
java.time
您正在使用麻烦的旧日期时间 classes,它们现在已成为遗留问题,已被现代 java.time classes 取代。
Instant
class 表示 UTC 时间轴中的一个时刻,类似于 java.time.Date
除了分辨率为纳秒而不是毫秒。
Instant instant = Instant.now() ;
当parsing/generating个字符串时,java.timeclasses默认使用ISO 8601格式。
String output = instant.toString() ;
还有……
Instant instant = Instant.parse( "2017-01-23T12:34:56Z" ) ;
也许你指的是某个时区的 25 日中午,而不是 UTC。
LocalDateTime.parse( "2017-11-25T12:00:00" ) // LocalDateTime has no concept of time zone or offset-from-UTC. Not on the timeline. Has no real meaning until assigned a time zone.
.atZone( ZoneId.of( "America/New_York" ) ) // Assign a time zone to determine a moment on the timeline, a ZonedDateTime.
.toInstant() // Extract a Instant, always in UTC by definition.
.toString() // Generate a string in standard ISO 8601 format.
问候堆栈溢出,
我正在为位于雅典的外国办事处实施的应用程序遇到了一个奇怪的问题运行。构建时,应用程序是一个 .war 文件,部署在 Tomcat 实例上。
只是为了了解一些背景信息,这个相同的应用程序在美国和其他国家/地区的几个不同 OS(Ubuntu 12.04、Windows Server 2012 R2 等)上成功运行Java/Tomcat 配置不同的国家/地区。
然而,我用来安装 Athens 应用程序的 OS 是 Windows Server 2008 R2。此服务器上安装的是 Java JRE 1.8。0_111 由 Tomcat 8.5.4 使用。此服务器位于雅典。
应用程序一切正常,除了我向控制器方法提交日期字段的任何地方。在应用程序的各个不同部分尝试将日期字符串提交到我的控制器时,我收到以下消息:
Failed to convert the value of 'java.lang.String' to required type'java.util.Date';
nested exception is java.lang.illegalArgumentException: Could not parse text
[7/28/2017 7:00 AM] into any available date input formats.
请记住,当我将此应用程序部署到另一台服务器上的 Tomcat 实例时,一切正常,我没有收到此错误消息。
为了解决此错误,我决定更改其中一个请求参数的类型:
@RequestParam("date") Date date
到
@RequestParam("date") String dateString
然后我使用 Java SimpleDateFormat 将字符串转换为日期:
SimpleDateFormat sdf_date = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
String startDate = dateString;
Date date = sdf_date.parse(startDate);
传递给上述函数的日期字符串是:
11/25/2017 12:00 pm
我在几台具有不同 OS/Tomcat 配置的测试服务器上对此进行了测试,效果非常好。但是,在位于雅典的 Windows 2008 R2 服务器上进行测试时,我仍然收到错误消息。我不再收到上述错误,但我确实收到以下内容:
java.text.ParseException: Unparseable date: "11/25/2017 12:00 pm"
我不确定为什么同样的 Java 代码能够在某些服务器上使用相同的 SimpleDateFormat 模式解析相同的日期,而在其他服务器上则不能。这对我来说似乎很奇怪。
如果您需要任何其他信息,请告诉我,我很乐意澄清。
谢谢!
编辑:雅典服务器上的服务器端调试屏幕截图:
'dateString' 正在传递给控制器方法
希腊不使用与许多其他讲拉丁语的国家相同的 am/pm 名称。希腊改为使用 π.µ。和µ.µ。因此,当 SimpleDateFormat 没有收到语言环境时,它假定它与计算机 运行 程序相同。
要解决此问题,请尝试以下操作:
SimpleDateFormat sdf_date = new SimpleDateFormat("MM/dd/yyyy hh:mm a", new Locale("en", "US"));
String startDate = dateString;
Date date = sdf_date.parse(startDate);
这将在此服务器上使用带有美国语言环境的英语。不过,您仍然需要确保这是在每种情况下输入中传递的格式。
tl;博士
Instant.parse( "2017-11-25T12:00:00Z" )
详情
另外,还有3个问题。解决这些问题将消除您在处理本地化文本格式方面的问题。
时区
你忽略了关键的时区问题。如果未指定,您将隐式依赖 JVM 当前的默认时区。该默认值可能会有所不同,即使在运行时(!),所以最好明确指定您 desired/expected 时区。
通常最好使用 UTC,除非您有特定原因。
ISO 8601
ISO 8601 标准为表示日期时间值的文本定义了实用的明确格式。
暂时使用 UTC 时间轴,使用 YYYY-MM-DDTHH:MM:SS.SSSSSSSSSZ,其中 T
将日期部分与时间部分分开,Z
是Zulu的简称,表示UTC,时间采用24小时制(没有AM/PM)。
将日期时间值序列化为文本时使用这些标准格式。
java.time
您正在使用麻烦的旧日期时间 classes,它们现在已成为遗留问题,已被现代 java.time classes 取代。
Instant
class 表示 UTC 时间轴中的一个时刻,类似于 java.time.Date
除了分辨率为纳秒而不是毫秒。
Instant instant = Instant.now() ;
当parsing/generating个字符串时,java.timeclasses默认使用ISO 8601格式。
String output = instant.toString() ;
还有……
Instant instant = Instant.parse( "2017-01-23T12:34:56Z" ) ;
也许你指的是某个时区的 25 日中午,而不是 UTC。
LocalDateTime.parse( "2017-11-25T12:00:00" ) // LocalDateTime has no concept of time zone or offset-from-UTC. Not on the timeline. Has no real meaning until assigned a time zone.
.atZone( ZoneId.of( "America/New_York" ) ) // Assign a time zone to determine a moment on the timeline, a ZonedDateTime.
.toInstant() // Extract a Instant, always in UTC by definition.
.toString() // Generate a string in standard ISO 8601 format.