【问题标题】:Why does Java SimpleDateFormat work on some servers and not others?为什么 Java SimpleDateFormat 可以在某些服务器上运行,而在其他服务器上不行?
【发布时间】:2017-07-27 17:25:49
【问题描述】:

问候堆栈溢出,

我正在为位于雅典的外国办事处实施的应用程序遇到一个奇怪的问题。构建后,应用程序是一个部署在 Tomcat 实例上的 .war 文件。

仅提供一些背景信息,同一应用程序可在美国和其他国家/地区具有不同 Java/Tomcat 配置的多个不同操作系统(Ubuntu 12.04、Windows Server 2012 R2 等)上成功运行。

但是,我用来为雅典安装应用程序的操作系统是 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'

【问题讨论】:

  • 会不会是部署问题?喜欢旧版本的一些 jar?
  • 会不会是日期格式问题?在欧洲,日期将采用其他格式,例如 ""dd/MM/yyyy ...""。
  • 我的意思是,在雅典服务器上 SimpleDateFormat 是使用默认的希腊语言环境创建的。如果您传递美国格式日期字符串,可能您想使用美国语言环境 SimpleDateFormat(String pattern, Locale locale) 创建 SimpleDateFormat
  • 服务器在哪里并不重要,重要的是这些服务器使用哪种语言,并且“AM”看起来不像是一个有效的希腊词/缩写。
  • 您打算在 25 日中午在哪个时区?雅典的中午比纽约的中午早几个小时。

标签: java windows spring-mvc tomcat simpledateformat


【解决方案1】:

与许多其他讲拉丁语的国家/地区不同,希腊使用的上午/下午名称不同。希腊改为使用 π.µ。和µ.µ。因此,当 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);

这将在此服务器上使用美国语言环境的英语语言。不过,您仍然需要确保这是在每种情况下都在输入中传递的格式。

【讨论】:

  • 这对我有用!我会接受这个答案,并感谢 Sergei Sirik 的上述相同建议。
  • 也为我工作!。很好的答案!
【解决方案2】:

tl;博士

Instant.parse( "2017-11-25T12:00:00Z" ) 

详情

Answer by Smith 是正确的。

此外,还有三个问题。解决这些问题将消除您处理本地化文本格式的问题。

时区

您忽略了时区的关键问题。如果未指定,您将隐式依赖 JVM 当前的默认时区。该默认值可能会有所不同,即使在运行时(!)期间也是如此,因此最好明确指定您想要/预期的时区。

除非您有特定原因,否则通常最好使用 UTC。

ISO 8601

ISO 8601 标准为表示日期时间值的文本定义了实用的明确格式。

在 UTC 时间线中使用 YYYY-MM-DDTHH:MM:SS.SSSSSSSSSZ,其中 T 将日期部分与时间部分分开,Z 是 Zulu 的缩写,表示 UTC,并且时间使用 24 小时制(没有 AM/PM)。

在将日期时间值序列化为文本时使用这些标准格式。

java.time

您正在使用麻烦的旧日期时间类,它们现在是遗留的,被现代 java.time 类所取代。

Instant 类表示 UTC 时间线中的时刻,类似于 java.time.Date,但分辨率为纳秒而不是毫秒。

Instant instant = Instant.now() ;

java.time 类在解析/生成字符串时默认使用 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. 

【讨论】:

  • 谢谢!感谢您的宝贵时间,这是非常有用的信息。
猜你喜欢
  • 1970-01-01
  • 2014-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-10
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
相关资源
最近更新 更多