我正在尝试理解GregorianCalendar学习java作为经验丰富的Delphi(pascal)开发人员。根据文档,1970年1月1日0:00:00是计算从这一点开始经过的时间的参考。所以,在实验中,我设置了一个新变量
GregorianCalendar cal2 = new GregorianCalendar(1970, 0, 1, 0, 0, 0); //January=0, Day=1, Hour=0, Min=0, Sec=0
然后我读了时间
cal2.getTimeInMillis()
根据定义,这应该等于零。但我得到了18,000,000毫秒。这是5个小时。我在想这与时区有关?有任何建议,我在东区。
如果是这样,我该如何解释?我真的想了解所以我可以计算两次之间的秒数差异。不理解这一点,我无法继续! 谢谢! 道格
答案 0 :(得分:2)
package so;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class BeginningOfTime {
public static void main (final String[] args) {
final Calendar localTZ = new GregorianCalendar (1970, 0, 1, 0, 0, 0);
dump (localTZ);
final Calendar utcTZ = new GregorianCalendar ();
utcTZ.clear ();
utcTZ.setTimeZone (TimeZone.getTimeZone ("UTC"));
dump (utcTZ);
}
private static final void dump (final Calendar c) {
System.out.printf ("%s: %d (offset %d)%n",
c.getTimeZone ().getDisplayName (),
c.getTimeInMillis (),
c.get (Calendar.ZONE_OFFSET));
}
}
产生这个:
Eastern Standard Time: 18000000 (offset -18000000)
Coordinated Universal Time: 0 (offset 0)
答案 1 :(得分:1)
我知道这不会直接回答您的问题,但GregorianCalendar
可能不是最好的方法。我建议您使用像Joda Time这样的库,因为您专门寻找Duration和Period等概念。另请查看ThreeTen JSR 310的RI Java 8,计划用于{{3}}。
这是一个 JodaTime 解决方案,用于计算经过的时间(以秒为单位)。
DateTime start = new DateTime(2012, 3, 25, 0, 0, 0, 0);
DateTime end = new DateTime(2012, 3, 26, 0, 0, 0, 0);
int seconds = Seconds.secondsBetween(start, end).getSeconds();
答案 2 :(得分:0)
我打赌这是东部时区。最大的问题是:你必须考虑到它吗?你打算在同一时区计算/记录时间吗?这个类中有很多功能,它们非常臃肿,但非常方便。
GregorianCalendar类确实包含时区功能,也可以为您提供DST偏移。
答案 3 :(得分:0)
您的GregorianCalendar
带有时区。但是epoch的定义是UTC。 1970年的第一个时刻,在北美东海岸的比起1970年的第一个世界时间晚了五个小时。所以你要比较苹果和橘子。
让我们再看看,但使用现代的 java.time 类。
Instant instantEpochConstant = Instant.EPOCH ; // Expect 1970-01-01T00:00:00Z.
instantEpochConstant.toString():1970-01-01T00:00:00Z
Instant instantZeroMillis = Instant.ofEpochMilli( 0L ) ; // Expect 1970-01-01T00:00:00Z.
instantZeroMillis.toString():1970-01-01T00:00:00Z
long millisSinceEpoch = Instant.parse( "1970-01-01T00:00:00Z" ).toEpochMilli() ; // Expect zero.
millisSinceEpoch.toString():0
相比之下,猜测你的时区是America/New_York
,1970年的第一个时刻在该地区比晚上 5小时(18,000,000毫秒)比第一时刻 1970年的UTC 。
ZonedDateTime zdt = ZonedDateTime.of(
LocalDate.of( 1970 , Month.JANUARY , 1 ) ,
LocalTime.MIN ,
ZoneId.of( "America/New_York" )
);
Instant instantFromNewYork = zdt.toInstant() ;
long epochMillisNewYork = instantFromNewYork.toEpochMilli() ;
zdt.toString():1970-01-01T00:00-05:00 [America / New_York]
instantFromNewYork.toString():1970-01-01T05:00:00Z
epochMillisNewYork:18000000
5 * 60 * 60 * 1000 = 18,000,000 = 5小时* 60分钟/小时* 60秒/分钟* 1,000毫秒/秒
GregorianCalendar
课程是一个有缺陷,设计糟糕,麻烦的课程。躲开它。它现在由java.time.ZonedDateTime
取代。
Instant
Instant
类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。
Instant instant = Instant.now() ;
instant.toString():2018-02-06T02:59:56.156787Z
ZonedDateTime
您可以从UTC调整到特定时区。你最终会得到同一时刻,即时间轴上的相同点,但是不同的挂钟时间。
以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用诸如EST
或IST
之类的3-4个字母伪区域,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。没有“东部时间”之类的东西,请使用America/New_York
等时区。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
申请Instant
以获得ZonedDateTime
。
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString():2018-02-06T03:59:56.156787 + 01:00 [非洲/突尼斯]
将日期时间值作为纪元参考日期的计数处理是不明智的。这样的整数对于人眼来说不可能作为日期时间读取,因此难以或不可能调试和发现无效值。
但是如果你坚持,你可以从1970年的第一个时刻,1970-01-01T00:00Z中提取毫秒数。
小心数据丢失。在以毫秒为单位生成此计数时,Instant
中的任何微秒或纳秒都将被忽略。
long millisSinceEpoch = instant.toEpochMilli() ;
1517885996156
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。