简体   繁体   English

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

[英]Simple Java String to java.util.Date conversion adds unwanted daylight saving

This is my program snippet这是我的程序片段

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(); 
    }

  }
}

This is the output of that program这是该程序的输出

Sun Mar 12 03:46:00 PDT 2017

Expected Output预期产出

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

Apparently, it is adding daylight saving time which occurs on PST at 2017-03-12 02:00:00显然,它正在添加发生在太平洋标准时间 2017-03-12 02:00:00 的夏令时

Few things I am bounded.很少有我受到限制的事情。

  • I cannot change server default timezone or anything specific to JVM我无法更改服务器默认时区或任何特定于 JVM 的内容
  • I must return back java.util.Date as final value.我必须返回 java.util.Date 作为最终值。

Edit: To some comment pointing me out how java.util.Date only stores long timestamp.编辑:有些评论指出 java.util.Date 如何只存储长时间戳。 Can you please give me a way where this function works你能告诉我这个功能的工作方式吗

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

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

should give me 2017-03-12 02:46:00 value in Date class?应该给我 2017-03-12 02:46:00 Date 类中的值? I don't care about what timezone it provides.我不在乎它提供的时区。 It should have that value, whatever timezone it is while printing.无论打印时处于哪个时区,它都应该具有该值。 Again my JVM is in PST.我的 JVM 再次处于 PST 中。

Use java.time, not legacy date-time classes使用 java.time,而不是旧的日期时间类

You are using troublesome old date-time classes such as java.util.Date that are now legacy, supplanted by the java.time classes.您正在使用麻烦的旧日期时间类,例如java.util.Date现在是遗留的,由 java.time 类取代。

LocalDateTime

2016-03-12 02:46:00 value …I don't care about what timezone it provides. 2016-03-12 02:46:00 value ...我不在乎它提供什么时区。 It should have that value, whatever timezone it is…无论时区如何,它都应该具有该值……

If you truly want to represent that date and time-of-day without regard for time zone, use the LocalDateTime class.如果您真的想在不考虑时区的情况下表示该日期和时间,请使用LocalDateTime类。 This class purposely ignores time zone.这个类故意忽略时区。

To parse, adjust your input string to comply with the ISO 8601 standard formats used by the java.time classes for parsing/generating strings.要解析,请调整输入字符串以符合 java.time 类用于解析/生成字符串的ISO 8601标准格式。

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

But beware: By ignoring time zone you lose the meaning of this date+time.但要注意:通过忽略时区,您将失去此日期+时间的含义。 Without the context of a time zone, we do not know if you mean the 2 AM in Auckland NZ, or 2 AM in Kolkata India (some hours later), or 2 AM in Paris France (more hours later), or 2 AM in Montréal Québec (still more hours later).如果没有时区上下文,我们不知道您是指新西兰奥克兰的凌晨 2 点,还是印度加尔各答的凌晨 2 点(几个小时后),或法国巴黎的凌晨 2 点(几个小时后),还是美国的凌晨 2 点蒙特利尔魁北克(更多小时后)。 A LocalDateTime is a rough idea about possible moments, but is not actually a point on the timeline. LocalDateTime是关于可能时刻的粗略概念,但实际上并不是时间线上的一个点。

ZonedDateTime

This is the output of that program Sun Mar 12 03:46:00 PDT 2017这是该程序的输出Sun Mar 12 03:46:00 PDT 2017

Expected Output Sun Mar 12 02:46:00 PDT/PST 2017预期产出Sun Mar 12 02:46:00 PDT/PST 2017

Now you contradict yourself.现在你自相矛盾了。

By including the PDT or PST with your expected output, you mean a specific moment on the timeline perceived through the lens of a particular region's wall-clock time .通过将PDTPST包含在您的预期输出中,您的意思是通过特定区域挂钟时间的镜头感知的时间线上的特定时刻。 This contradicts your statement that you want "2016-03-12 02:46:00" regardless of time zone.这与您想要“2016-03-12 02:46:00”而不管时区的声明相矛盾。 It is crucial that you understand this distinction to properly handle date-time work.了解这种区别以正确处理日期时间工作至关重要

If indeed the intent of the string 2016-03-12 02:46:00 is to represent a moment in the wall-clock time of the left coast of north America (as I guess you meant by PDT ), then we must parse that string firstly as a LocalDateTime as it lacks any indicator of time zone, but then immediately adjust it into a time zone to get a ZonedDateTime object.如果字符串2016-03-12 02:46:00的意图确实是代表北美左海岸挂钟时间的一个时刻(我猜你的意思是PDT ),那么我们必须解析字符串首先作为LocalDateTime因为它缺少任何时区指示符,然后立即将其调整为时区以获取ZonedDateTime对象。

Specify a proper time zone name in the format of continent/region , such as America/Montreal , Africa/Casablanca , or Pacific/Auckland .continent/region的格式指定正确的时区名称,例如America/MontrealAfrica/CasablancaPacific/Auckland Never use the 3-4 letter abbreviation such as EST or IST or PDT or PST as they are not true time zones, not standardized, and not even unique(!).切勿使用 3-4 个字母的缩写,例如ESTISTPDTPST因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

Here I arbitrarily chose America/Los_Angeles as the time zone, as your Question does not mention a specific time zone, only “PDT”.这里我随意选择了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 );

But it just so happens that March 12 of 2017 has an anomaly.但碰巧的是,2017 年 3 月 12 日有一个异常。 That is the day when the craziness known as Daylight Saving Time (DST) kicks in. The clocks in much of the left coast of north America at 2 AM jump to 3 AM.那是被称为夏令时 (DST)的疯狂开始的那一天。北美左海岸大部分地区的时钟从凌晨 2 点跳到凌晨 3 点。 There is no two o'clock hour.没有两点钟。 The day is 23 hours long rather than the usual 24 hours.一天有 23 小时,而不是通常的 24 小时。 So your request for 2:46 is asking for a nonexistent moment, an invalid value.所以你对 2:46 的请求是要求一个不存在的时刻,一个无效的值。 The design choice in java.time to resolve this conundrum is to jump forward, following the "Spring Forward" of DST. java.time 中解决这个难题的设计选择是向前跳,跟随 DST 的“Spring Forward”。 The result is in the 3 AM hour, 03:46 .结果是在凌晨 3 点, 03:46

See this code run live in IdeOne.com .查看此代码在 IdeOne.com 中实时运行

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

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

zdt.toString(): 2017-03-12T03:46-07:00[America/Los_Angeles] zdt.toString(): 2017-03-12T03:46-07:00[美国/洛杉矶]

Note the 2 AM hour becomes the 3 AM hour in that output.请注意,该输出中的凌晨 2 点将变为凌晨 3 点。

A reasonable person could make arguments for a different design choice in handling this anomaly, such as throwing an Exception.一个理性的人可以在处理这种异常时为不同的设计选择提出论据,例如抛出异常。 But this is how java.time works.但这就是 java.time 的工作方式。 Study the class doc and be sure you understand the behavior on this important topic.研究课程文档并确保您了解有关此重要主题的行为。

If you want to detect such an anomaly, call toLocalDateTime on the ZonedDateTime object, and compare to the first LocalDateTime .如果要检测此类异常,请在ZonedDateTime对象上调用toLocalDateTime ,并与第一个LocalDateTime进行比较。 With no anomaly, the pair of LocalDateTime objects will be equal;如果没有异常, LocalDateTime对象对将相等; with an anomaly they will not be equal.对于异常,它们将不相等。


About java.time关于 java.time

The java.time framework is built into Java 8 and later. java.time框架内置于 Java 8 及更高版本中。 These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat .这些类取代麻烦的老传统日期时间类,如java.util.DateCalendar ,和SimpleDateFormat

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes.现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial .要了解更多信息,请参阅Oracle 教程 And search Stack Overflow for many examples and explanations.并在 Stack Overflow 上搜索许多示例和解释。 Specification is JSR 310 .规范是JSR 310

Where to obtain the java.time classes?从哪里获得 java.time 类?

The ThreeTen-Extra project extends java.time with additional classes. ThreeTen-Extra项目用额外的类扩展了 java.time。 This project is a proving ground for possible future additions to java.time.该项目是未来可能添加到 java.time 的试验场。 You may find some useful classes here such as Interval , YearWeek , YearQuarter , and more .您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM