[英]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.很少有我受到限制的事情。
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 中。
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 .通过将PDT
或PST
包含在您的预期输出中,您的意思是通过特定区域挂钟时间的镜头感知的时间线上的特定时刻。 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/Montreal
、 Africa/Casablanca
或Pacific/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 个字母的缩写,例如EST
或IST
或PDT
或PST
因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
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.对于异常,它们将不相等。
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.Date
, Calendar
,和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 .您可以在这里找到一些有用的类,比如Interval
, YearWeek
, YearQuarter
,和更多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.