SimpleDateFormat在分析过程中返回错误的时区过程中、时区、错误、SimpleDateFormat

2023-09-04 02:11:38 作者:姐的世界没人懂

我在创建Date对象时遇到了一个奇怪的问题。我有以下代码将日期的时区设置为UTC。在parse语句之前,我看到sdfDate的时区是UTC,但在parse语句之后,我看到PunchDate的值是:Sat Mar 30 01:00:00CET2013,我相信这来自我的系统。但如何确保时区即使在分析后也保持不变。

Date punchDate = null;
Date punchTime = null;

SimpleDateFormat sdfDate = new SimpleDateFormat("dd.MM.yyyy");
SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm:ss");

    try
    {
        sdfDate.setTimeZone(TimeZone.getTimeZone("UTC"));
        sdfTime.setTimeZone(TimeZone.getTimeZone("UTC"));
        punchDate = sdfDate.parse(arg1);
        punchTime = sdfTime.parse(arg2);
    }
    catch (ParseException pe)
    {
        System.out.println("Parse exception " +pe.getMessage());
    }

我的要求基本上是需要从字符串输入创建一个Date对象,但时区应该保持UTC。

推荐答案

tl;dr

SimpleDateFormat的用法

我需要从字符串输入创建一个Date对象,但时区应保持UTC。

LocalDate.parse( 
    "23.01.2017" , 
    DateTimeFormatter.ofPattern( "dd.MM.uuuu" ) 
) 

…和…

LocalTime.parse( "12:34:56" ) 

…合并…

OffsetDateTime.of( datePart , timePart , ZoneOffset.UTC )

详细信息

您正在使用令人困惑的旧Date-Time类,现在这些Date-Time类已被java.time类取代。

OffsetDateTime

您说您确定您的输入是针对UTC的,尽管没有这样的指示器。因此,我们将解析日期部分,解析时间部分,然后合并,同时为UTC分配offset-from-UTC零。

DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd.MM.uuuu" ) ;
LocalDate ld = LocalDate.parse( "23.01.2017" , f ) ;

时间输入恰好符合在java.time类中默认使用的标准ISO 8601格式。因此无需指定格式模式。

LocalTime lt = LocalTime.parse( "12:34:56" ) ;

合并。

OffsetDateTime odt = OffsetDateTime.of( ld , lt , ZoneOffset.UTC ) ;

时区

如果要查看与特定地区挂钟时间中显示的时刻相同的时刻,请应用ZoneId以获取ZonedDateTime

指定continent/region格式的proper time zone name,如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用ESTIST等3-4个字母的缩写,因为它们不是真实时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;  // Same simultaneous moment, same point on the timeline.

ISO 8601

提示:要以文本形式交换此类数据,请专门使用标准ISO 8601格式。这些格式被合理地设计为毫不含糊,易于机器处理,并且易于人们跨多种文化阅读。

在分析和生成字符串时,默认情况下,java.time类使用标准格式。

String output = Instant.now().toString() ;  

2017-01-23T12:34:56.123456789Z

转换

避免使用旧版java.util.Date类。但如果你必须这样做,你可以皈依。查看添加到旧类中的新方法。

Instant类表示UTC中时间线上的时刻,分辨率为nanoseconds(最多九(9)位小数位)。

通过调用toStringOffsetDateTime提取Instant对象。

Instant instant = odt.toInstant() ;
java.util.Date date = Date.fromInstant( instant ) ;

…走另一条路…

Instant instant = myJavaUtilDate.toInstant() ;
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;  

关于java.time

框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期-时间类,如java.util.DateCalendar、&;SimpleDateFormat

Joda-Time项目现在位于maintenance mode中,建议迁移到java.time类。

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

从哪里获取java.time类?

Java SE 8、Java SE 9和更高 内置。 带有捆绑实现的标准Java API的一部分。 Java 9添加了一些次要功能和修复。 Java SE 6和Java SE 7 许多java.time功能已在ThreeTen-Backport中重新移植到Java 6&;7。 Android ThreeTenABP项目专门针对Android进行了ThreeTen-Backport适配。 参见How to use ThreeTenABP…。

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能添加到java.time中提供了一个试验场。您可以在此处找到一些有用的类,如IntervalYearWeekYearQuarter和more。