Java.util.Date转换的简单Java字符串增加了不需要的夏令时

时间:2017-02-03 21:22:16

标签: java date

这是我的程序代码段

import java.lang.Math;
import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

public class Main
{

  public static void main(String[] args)
  {
    String dateTime = "2017-03-12 02:46:00";

    // convert string to java.util.Date
    try {
        SimpleDateFormat e = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d = e.parse(dateTime);
        System.out.println(d);
    } catch (ParseException e) {
        e.printStackTrace(); 
    }

  }
}

这是该程序的输出

Sun Mar 12 03:46:00 PDT 2017

预期产出

Sun Mar 12 02:46:00 PDT/PST 2017

显然,它正在加入夏令时,这发生在太平洋标准时间2017-03-12 02:00:00

我受限制的事情很少。

  • 我无法更改服务器默认时区或任何特定于JVM的内容
  • 我必须将java.util.Date作为最终值返回。

编辑: 有些评论指出我java.util.Date如何只存储长时间戳。你能告诉我这个功能的工作方式

java.util.Date convertStringToDate(String str) {
   // code to convert String to Date
}

convertStringToDate("2017-03-12 02:46:00");

应该在Date类中给我2017-03-12 02:46:00的值?我不关心它提供的时区。它应具有该值,无论打印时的时区如何。我的JVM再次在PST中。

1 个答案:

答案 0 :(得分:1)

使用java.time,而不是旧版日期时间类

您正在使用麻烦的旧日期时间类,例如java.util.Date,现在是遗留的,被java.time类取代。

LocalDateTime

  

2016-03-12 02:46:00价值......我不关心它提供的时区。它应具有该值,无论它是什么时区......

如果您确实想要在不考虑时区的情况下表示该日期和时间,请使用LocalDateTime课程。这堂课故意忽略了时区。

要解析,请调整输入字符串以符合java.time类用于解析/生成字符串的ISO 8601标准格式。

String input = "2016-03-12 02:46:00".replace( " " , "T" );
LocalDateTime ldt = LocalDateTime.parse( input );

但要注意:忽略时区会失去这个日期和时间的含义。如果没有时区的背景,我们不知道你是指新西兰奥克兰的凌晨2点,印度加尔各答的凌晨2点(几小时后),还是法国巴黎的凌晨2点(更多小时后),或者凌晨2点。蒙特利尔魁北克(还有几个小时后)。 LocalDateTime是关于可能时刻的粗略概念,但实际上并不是时间轴上的一个点。

ZonedDateTime

  

这是该程序Sun Mar 12 03:46:00 PDT 2017

的输出      

预期输出Sun Mar 12 02:46:00 PDT/PST 2017

现在你自相矛盾了。

通过将PDTPST与预期输出结合起来,您指的是通过特定区域wall-clock time的镜头感知的时间轴上的特定时刻。这与您不希望时区的“2016-03-12 02:46:00”的陈述相矛盾。 至关重要的是,您理解这种区别以正确处理日期时间工作。

如果确实字符串2016-03-12 02:46:00的意图是代表北美左岸海岸时间的一个时刻(我猜你的意思是PDT),那么我们必须首先将该字符串解析为LocalDateTime,因为它缺少任何时区指示符,但随后立即将其调整为时区以获取ZonedDateTime对象。

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

我在这里任意选择America/Los_Angeles作为时区,因为你的问题没有提到特定的时区,只有“PDT”。

String input = "2017-03-12 02:46:00".replace( " " , "T" );
LocalDateTime ldt = LocalDateTime.parse( input );
ZoneId z = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdt = ldt.atZone( z );

但事实恰恰相反,2017年3月12日有一个异常现象。那个被称为Daylight Saving Time (DST)的疯狂开始的那一天。北美大部分凌晨2点左右的时钟跳到凌晨3点。没有两点钟。这一天是23小时,而不是通常的24小时。所以你对2:46的请求是要求一个不存在的时刻,一个无效的值。解决这个难题的java.time中的设计选择是在DST的“Spring Forward”之后继续前进。结果是在凌晨3点,03:46

请参阅此code run live in IdeOne.com

  

输入:2017-03-12T02:46:00

     

ldt.toString():2017-03-12T02:46

     

zdt.toString():2017-03-12T03:46-07:00 [America / Los_Angeles]

请注意,上午2点小时将成为该输出中的凌晨3点。

一个合理的人可以在处理这种异常时为不同的设计选择提出论据,例如抛出异常。但这就是java.time的工作原理。研究课程文档,并确保您了解这一重要主题的行为。

如果要检测此类异常,请在toLocalDateTime对象上调用ZonedDateTime,然后与第一个LocalDateTime进行比较。没有异常,这对LocalDateTime对象将是平等的;异常他们不会平等。

关于java.time

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

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore