如何获取Date.toString()以生成SimpleDateFormat可以针对1970年1月1日左右的Date正确解析的输出(我假设这也适用于1968年和1969年的冬天)
如果我运行以下命令,
System.out.println(TimeZone.getDefault());
Date date = new Date(0);
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
Date date2 = sdf.parse(date.toString());
System.out.println("date: " + date);
System.out.println("date2: " + date2);
Date date3 = sdf.parse(date2.toString());
System.out.println("date3: " + date3);
Run Code Online (Sandbox Code Playgroud)
此打印
sun.util.calendar.ZoneInfo[id="Europe/London",offset=0,dstSavings=3600000,useDaylight=true,transitions=242,lastRule=java.util.SimpleTimeZone[id=Europe/London,offset=0,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]
date: Thu Jan 01 01:00:00 GMT 1970
date2: Thu Jan 01 02:00:00 GMT 1970
date3: Thu Jan 01 03:00:00 GMT 1970
Run Code Online (Sandbox Code Playgroud)
问题在于伦敦于1970年1月1日在英国夏令时。所以正确的日期应该是
date: Thu Jan 01 01:00:00 BST 1970
Run Code Online (Sandbox Code Playgroud)
要么
date: Thu Jan 01 00:00:00 GMT 1970
Run Code Online (Sandbox Code Playgroud)
但似乎两者混淆。
虽然我不希望支持java.util.Date,但对我来说这不是一个选择。
您的输入无效,因为BST(英国夏季时间)在冬季无效。
BST 无法可靠地解析,因为它是非标准的非唯一伪区域。
无需弄乱SimpleDateFormat。让现代的 java.time类完成繁重的工作。
虽然我很乐意不支持
java.util.Date,但对我来说这不是一个选择。
在代码的边缘,将旧类和现代类相互转换。
// Convert from legacy to modern.
Instant instant = myJavaUtilDate.toInstant() ;
// Convert from modern to legacy.
java.util.Date myJavaUtilDate = Date.from( instant ) ;
Run Code Online (Sandbox Code Playgroud)
BST冬天不行显然,您中的“ B” BST是英国人。但是BST在这种情况下意味着英国夏令时。这意味着夏令时(DST)是在夏季而不是在冬季。因此,您输入的一月份日期的字符串与组合BST是毫无意义的。
您在1970年使用英国时区的时刻的例子进一步复杂化了。
DST在英国使用UTC(+01:00)的提前一小时偏移的做法:在冬天的标准时间是夏季,和零(00 +00)的偏置电流的做法。并非总是如此。
早在1970年,英国就试用了“双夏令时”。在1968-1971年的实验中,冬季时间比UTC提前1小时,而不是零,而夏季时间比UTC提前2小时,而不是现在的1小时。这使英国时间与欧洲大陆更加共有,并希望减少事故的发生。
因此,如果我们调整1970年1月的时间,那么我们可以预计在时区之前跳到一小时Europe/London。尽管在2019年1月这一刻,我们预计不会出现跳跃,但英国的一天中的时间将与UTC相同(相对于UTC的偏移量为零小时-分钟-秒)。
避免使用2-4个字符的伪区域,例如BST。它们不是标准化的。它们甚至都不是唯一的!因此,BST可以解释为是时区Pacific/Bougainville一样好British Summer Time。
指定适当的时区名称,格式Continent/Region,如America/Montreal,Africa/Casablanca或Pacific/Auckland。切勿使用2-4字母的缩写,例如BST或EST或,IST因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。
您可以轻松地在传统日期时间类和现代日期时间类之间进行转换。新的转换方法已添加到旧类中。寻找from,to和valueOf方法,每次的命名约定。
java.util.Date ? java.time.Instantjava.util.GregorianCalendar ? java.time.ZonedDateTimejava.sql.Date ? java.time.LocalDatejava.sql.Timestamp ? java.time.Instant您在1970年1月1日输入的00:00字符串恰好是旧日期和现代日期时间类都使用的纪元参考日期。我们对此值有一个常数。
Instant epoch = Instant.EPOCH ;
Run Code Online (Sandbox Code Playgroud)
Instant.toString():1970-01-01T00:00:00Z
在您所在的时区看到同一时刻Europe/London。
ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = epoch.atZone( z ) ;
Run Code Online (Sandbox Code Playgroud)
zdt.toString():1970-01-01T01:00 + 01:00 [欧洲/伦敦]
请注意,上述的Double-Summertime实验即已生效。如果我们在2019年尝试相同的代码,则得到的自UTC的偏移量为零。
ZonedDateTime zdt2019 =
Instant
.parse( "2019-01-01T00:00Z" )
.atZone( ZoneId.of( "Europe/London" ) )
;
Run Code Online (Sandbox Code Playgroud)
zdt2019.toString():2019-01-01T00:00Z [欧洲/伦敦]
要转换为java.util.Date,我们需要一个java.time.Instant对象。An Instant代表UTC的时刻。我们可以Instant从ZonedDateTime对象中提取一个,从而有效地将区域调整为UTC。相同的时刻,不同的时钟时间。
Instant instant = zdt.toInstant():
Run Code Online (Sandbox Code Playgroud)
现在应该回到1970-01-01T00:00:00Z的纪元开始日期。
Instant.toString():1970-01-01T00:00:00Z
要获取该java.util.Date对象,您可能需要与尚未更新为java.time类的旧代码进行互操作,请使用Date.from添加到该旧类中的新方法。
java.util.Date d = Date.from( instant ) ; // Same moment, but with possible data-loss as nanoseconds are truncated to milliseconds.
Run Code Online (Sandbox Code Playgroud)
d.toString():格林尼治标准时间1970年1月1日00:00:00
顺便说一句,从转换时,要注意可能的数据丢失的Instant到Date。现代类的分辨率为纳秒,而传统类的分辨率为毫秒。因此,您的小数秒的一部分可能会被截断。
查看上面的所有代码,可在IdeOne.com上实时运行。
若要转换另一个方向,请使用Date::toString方法。
Instant instant = d.toInstant() ;
Run Code Online (Sandbox Code Playgroud)
避免使用自定义格式的文本来交换日期时间值。将日期时间值序列化为可读文本时,请仅使用标准ISO 8601格式。默认情况下,java.time类使用这些格式。
您正在尝试分析的那些字符串是一种糟糕的格式,并且永远不要用于数据交换。
该java.time框架是建立在Java 8和更高版本。这些类取代麻烦的老传统日期时间类,如java.util.Date,Calendar,和SimpleDateFormat。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC驱动程序。不需要字符串,不需要类。java.sql.*
在哪里获取java.time类?
该ThreeTen-额外项目与其他类扩展java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。你可能在这里找到一些有用的类,比如Interval,YearWeek,YearQuarter,和更多。
| 归档时间: |
|
| 查看次数: |
164 次 |
| 最近记录: |