根据我的理解,java.util.Date将日期存储为从1970年1月1日00:00开始的毫秒......
所以,我已经尝试过以下代码:
public void testDateFormatBehavior()
{
DateFormat dfNoDay = new SimpleDateFormat(
"MMM d H:m:s zzz yyyy"
);
// This one should be correct as IST = GMT+5.30
String expStrDateBegIST1 = "Jan 01 05:30:01 IST 1970";
// Instead, this one seems to do the conversion to
// Jan 01 00:00:00 GMT 1970
String expStrDateBegIST2 = "Jan 01 02:00:01 IST 1970";
String expStrDateBegUTC = "Jan 01 00:00:01 GMT 1970";
String expStrDateBegCET = "Jan 01 01:00:00 CET 1970";
// Should convert to Jan 01 06:00:00 GMT 1970 as CST = GMT-6
String expStrDateBegCST = "Jan 01 00:00:00 CST 1970";
// This is EST, which is GMT+6...
String expStrDateBegEST = "Jan 01 10:00:00 EST 1970";
try {
Date dBegIST1 = dfNoDay.parse(expStrDateBegIST1);
Date dBegIST2 = dfNoDay.parse(expStrDateBegIST2);
Date dBegUTC = dfNoDay.parse(expStrDateBegUTC);
Date dBegCET = dfNoDay.parse(expStrDateBegCET);
Date dBegCST = dfNoDay.parse(expStrDateBegCST);
Date dBegEST = dfNoDay.parse(expStrDateBegEST);
System.out.println("IST1 milliseconds: " + dBegIST1.getTime());
System.out.println("IST2 milliseconds: " + dBegIST2.getTime());
System.out.println("UTC milliseconds: " + dBegUTC.getTime());
System.out.println("CET milliseconds: " + dBegCET.getTime());
System.out.println("CST milliseconds: " + dBegCST.getTime());
System.out.println("EST milliseconds: " + dBegEST.getTime());
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
输出:
IST1 milliseconds: 12601000
IST2 milliseconds: 1000
UTC milliseconds: 1000
CET milliseconds: 0
CST milliseconds: 21600000
EST milliseconds: 0
UTC毫秒线是正确的,因为我们从1970年1月1日开始指定00:00:01秒。 CET是正确的。 CST是正确的,因为毫秒是在1970年1月1日之后的6小时。
然而,IST转换很奇怪。
http://wwp.greenwichmeantime.com/to/ist/to-gmt/index.htm
IST似乎是GMT + 5:30。在我的Java代码中,它认为它是GMT + 2:00而不是。
此外,EST不正确。它认为EST是GMT + 10:00,而不是GMT + 6:00。 GMT + 10:00是AEST,而不是EST。 http://wwp.greenwichmeantime.com/time-zone/australia/time-zones/eastern-standard-time/
我有什么问题吗?
答案 0 :(得分:5)
Timezone
javadoc解释说:
三个字母的时区ID
为了与JDK 1.1.x兼容,还支持其他一些三字母时区ID(例如“PST”,“CTT”,“AST”)。但是,他们的使用已被弃用,因为相同的缩写通常用于多个时区(例如,“CST”可能是美国“中央标准时间”和“中国标准时间”),以及Java然后平台只能识别其中一个。
问题在于您假设时区缩写始终指定特定时区。
“IST”含糊不清:印度标准时间/爱尔兰标准时间/以色列标准时间。同样,“EST”可以表示美国东部标准时间或东澳大利亚标准时间。
Joda-time's timezone list显示明确的Olson名称和当前时区偏移量。你最好使用Joda-time代替java.util
类,并使用Olson名称来识别时区。
Should I use Java date and time classes or go with a 3rd party library like Joda Time?讨论了许多人选择使用Joda-time的原因。
答案 1 :(得分:0)
ZonedDateTime.parse( // Parse string as `ZonedDateTime` object.
"1969-12-31T19:00-05:00[America/New_York]" // This zone on that date is five hours behind UTC.
) // So last day of 1969 at 7 PM there is simultaneously first moment of January 1, 1970 in UTC (00:00:00).
.toInstant() // .toString() --> 1970-01-01T00:00:00Z
.toEpochMilli() // --> zero seconds since epoch, as we are *at* the epoch.
0
接受的Answer by Samuel是正确的。
现代方法使用 java.time 类来取代麻烦的旧遗留日期时间类,例如Date
。
以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用诸如EST
或IST
之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
将日期时间值序列化为文本时,请使用标准ISO 8601格式。
java.time 类在解析/生成字符串时默认使用ISO 8601格式。因此无需指定格式化模式。
ZonedDateTime
类通过在方括号中附加时区名称来明智地扩展标准格式。
String input = "1970-01-01T05:30:01+05:30[Asia/Kolkata]" ; // "Jan 01 05:30:01 IST 1970"
ZonedDateTime zdt = ZonedDateTime.parse( input ) ;
String output = zdt.toString() ; // Generate string in standard ISO 8601 format.
1970-01-01T05:30:01 + 05:30 [亚/加尔各答]
要通过UTC的挂钟时间镜头查看同一时刻,请提取Instant
。 我们预计UTC时间会有一秒,因为那个日期的印度时间比UTC早了五个半小时。
Instant instant = zdt.toInstant() ;
instant.toString():1970-01-01T00:00:01Z
我建议避免将时间跟踪作为一个从历史算起的时间,因为它很模糊且容易出错。但是,如果你坚持,你可以获得自UTC 1970年第一时刻(1970-01-01T00:00:00Z)以来的毫秒数。
在这种情况下,我们期望得到一千毫秒(1秒)的结果。
long millisSinceEpoch = instant.toEpochMilli() ;
1000
要了解北美东海岸时区的一刻:
String input = "1970-01-01T10:00:00-05:00[America/New_York]"; // "Jan 01 10:00:00 EST 1970"
ZoneId z = ZoneId.of( "America/New_York" );
ZonedDateTime zdt = ZonedDateTime.parse( input );
Instant instant = zdt.toInstant();
long millisSinceEpoch = instant.toEpochMilli();
zdt.toString():1970-01-01T10:00-05:00 [America / New_York]
instant.toString():1970-01-01T15:00:00Z
millisSinceEpoch:54000000
或在同一区域的另一个时刻。在这里,我们在纪元参考前一天晚上7点尝试。该日期的America/New_York
区域比UTC晚了五个小时。因此,当调整为UTC时,我们正好在午夜的行程,即纪元参考日期的第一个时刻,1970-01-01T00:00:00Z。这意味着1969-12-31T19:00-05:00[America/New_York]
距离纪元零秒。
String input = "1969-12-31T19:00-05:00[America/New_York]" ;
ZoneId z = ZoneId.of( "America/New_York" );
ZonedDateTime zdt = ZonedDateTime.parse( input );
Instant instant = zdt.toInstant();
long millisSinceEpoch = instant.toEpochMilli();
zdt.toString():1969-12-31T19:00-05:00 [America / New_York]
instant.toString():1970-01-01T00:00:00Z
millisSinceEpoch:0
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
如果JDBC driver符合JDBC 4.2或更高版本,您可以直接与数据库交换 java.time 对象。不需要字符串或java.sql。* classes。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。