Java SimpleDataFormat不';不要给出固定的结果

Java SimpleDataFormat不';不要给出固定的结果,java,simpledateformat,Java,Simpledateformat,我需要将Java日期对象格式化为一个字符串,如yyyyMMdd(一天一轮)。例如,20180129。我有以下实施: SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); sdf.format(roundedDate); 代码大部分时间都在工作,但有时它会生成类似于2018129的结果,这不是我想要的。因此,我的数据库中将同时包含20180129

我需要将Java日期对象格式化为一个字符串,如
yyyyMMdd
(一天一轮)。例如,
20180129
。我有以下实施:

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
sdf.format(roundedDate);
代码大部分时间都在工作,但有时它会生成类似于
2018129
的结果,这不是我想要的。因此,我的数据库中将同时包含
20180129
2018129

应用程序使用来自MQ的消息,并将消息中的时间戳转换为Java日期对象。它将日期格式化为上面的字符串

问题是我无法在调试模式下重现该问题。它总是在调试器中生成预期的结果。但当我在服务器(Docker中)上运行了一段时间后,我看到了这样的损坏数据


我想知道为什么在给定有效日期对象的情况下,
SimpleDateFormat
会有如此不确定的行为?任何想法都将受到欢迎。

SimpleDataFormat不是线程安全的,请参阅优秀文章


java.time.format.DateTimeFormatter
是核心java中此功能的现代线程安全实现。

SimpleDataFormat
不是线程安全的,请参阅优秀文章

java.time.format.DateTimeFormatter
是核心java中此功能的现代线程安全实现。

tl;博士 改用线程安全的java.time类

具体地说,使用和

2018-01-29

20180129

线程安全 您没有提供足够的信息来诊断您的问题。我想可能是:

  • 您正在跨线程使用这些遗留日期时间对象,它们不是为线程安全而设计的。取而代之的是使用java.time类,这些类通过模式设计为线程安全的
  • 在这个神秘的“日期舍入”过程中,无论你在做什么,总有一些地方出了问题,你提到了这个问题,却忽略了解释
错误的数据类型 将消息中的时间戳转换为Java日期对象

您正在将仅日期值放入具有日期时间类型的日期中。方钉,圆孔

相反,请将仅日期类型用于仅日期值:

ISO 8601 您所需的格式YYYYMMDD恰好在标准中定义为“基本”变量,在该变量中,分隔符的使用被最小化

Java为此目的提供了一个对象:。因此,无需定义格式化模式

String input = "2018129" ;
LocalDate ld = LocalDate.parse( input , DateTimeFormatter.BASIC_ISO_DATE ) ;
要生成这样的字符串,请使用相同的格式化程序

LocalDate today = LocalDate.now( ZoneId.of( "Africa/Tunis" ) ) ;
String output = today.format( DateTimeFormatter.BASIC_ISO_DATE ) ;
顺便说一下,我建议使用ISO 8601格式的完整版本,而不是紧凑的“基本”变体。根据我的经验,节省的几个字节不值得放弃可读性和减少歧义。另外,java.time类在解析/生成
String
对象时默认使用全长ISO 8601格式,因此您可以完全不用
DateTimeFormatter
对象


关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

您可以直接与数据库交换java.time对象。使用兼容的或更高版本。不需要字符串,也不需要
java.sql.*

从哪里获得java.time类

  • 然后
    • 内置的
    • 标准JavaAPI的一部分,带有捆绑实现
    • Java9添加了一些次要功能和修复
    • 大部分java.time功能都在中向后移植到Java6和Java7
    • 更高版本的Android捆绑包实现了java.time类
    • 对于早期的Android(tl;dr 改用线程安全的java.time类

      具体地说,使用和

      2018-01-29

      20180129

      线程安全 您没有提供足够的信息来诊断您的问题。我猜:

      • 您正在跨线程使用这些遗留日期时间对象,它们不是设计为线程安全的。而是使用java.time类,这些类通过模式设计为线程安全的
      • 在这个神秘的“日期舍入”过程中,无论你在做什么,总有一些地方出了问题,你提到了这个问题,却忽略了解释
      错误的数据类型 将消息中的时间戳转换为Java日期对象

      您正在将仅日期值放入日期类型为“日期时间”的日期中。方钉,圆孔

      相反,请将仅日期类型用于仅日期值:

      ISO 8601 您所需的格式YYYYMMDD恰好在标准中定义为“基本”变量,在该变量中,分隔符的使用被最小化

      Java为此目的提供了一个对象:。因此无需定义格式化模式

      String input = "2018129" ;
      LocalDate ld = LocalDate.parse( input , DateTimeFormatter.BASIC_ISO_DATE ) ;
      
      要生成这样的字符串,请使用相同的格式化程序

      LocalDate today = LocalDate.now( ZoneId.of( "Africa/Tunis" ) ) ;
      String output = today.format( DateTimeFormatter.BASIC_ISO_DATE ) ;
      
      顺便说一下,我建议使用ISO 8601格式的完整版本,而不是紧凑的“basic”变体。根据我的经验,节省的几个字节不值得放弃可读性和减少歧义。此外,java.time类在解析/生成
      字符串
      对象时默认使用全长ISO 8601格式,因此您可以完全免除
      DateTimeFormatter
      对象


      关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,如,&

      该项目现已启动,建议迁移到类

      要了解更多信息,请参阅.和搜索堆栈溢出以获取许多示例和解释。规范为

      您可以直接与数据库交换java.time对象。使用兼容的或更高版本。不需要字符串,也不需要
      java.sql.*