Java GregorianCalendar



我试图理解GregorianCalendar作为一名经验丰富的Delphi(pascal)开发人员学习java。根据文件,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()

根据定义,这应该等于零。然而我得到了1800000毫秒。这是5个小时。我想这和时区有关?有什么建议吗?我在东区。

如果是,我该如何解释?我真的在努力理解,这样我就可以用秒来计算两次之间的差异。如果不了解这一点,我就无法继续!谢谢Doug

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)

我知道这不能直接回答您的问题,但GregorianCalendar可能不是最好的方法。我建议你使用Joda Time这样的库,因为你专门寻找Duration和Period等概念。还可以看看ThreeTen JSR310的RI,它是为Java8计划的。

这是一个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();

我打赌它是东部时区。最大的问题是:你必须对此负责吗?你打算在同一时区计算/记录时间吗?这个类有很多功能,以至于它变得非常臃肿,但非常方便。

GregorianCalendar类确实包含时区功能,还可以执行诸如提供DST偏移之类的操作。

北美东海岸与UTC

您的GregorianCalendar带有时区。但你的时代的定义是UTC。1970年北美东海岸的第一个时刻比1970年UTC的第一个瞬间晚了五个小时。所以你把苹果比作桔子。

让我们再看一看,但使用现代的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.

millisInchEpoch.toString():0

相反,猜测您的时区是America/New_York,该区域1970年的第一个时刻比UTC 1970年的第一时刻晚5小时(1800000毫秒)。

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[美国/纽约]

instantFromNewYork.toString():1970-01-01T05:00:00Z

划时代百万纽约:1800000

5*60*60*1000=1800000=5小时*60分钟/小时*60秒/分钟*1000毫秒/秒

java.time

GregorianCalendar类是一个有缺陷、设计糟糕、麻烦的类。避开它。它现在被java.time.ZonedDateTime取代。

Instant

Instant类表示以UTC为单位的时间线上的一个时刻,分辨率为纳秒(最多九(9)位小数)。

Instant instant = Instant.now() ;

instant.toString():2018-02-06T02:59:56.156787Z

ZonedDateTime

您可以从UTC调整到特定时区。你最终会得到同一时刻,时间线上的同一点,但不同的挂钟时间。

continent/region的格式指定适当的时区名称,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用3-4个字母的伪时区,如ESTIST,因为它们是真实时区,不是标准化的,甚至不是唯一的(!)。没有"东部时间"这样的东西,使用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【非洲/突尼斯】

从epoch开始计数

将日期时间值作为历元参考日期的计数处理是不明智的。人眼不可能将这样的整数读取为日期时间,因此调试和发现无效值是困难的或不可能的。

但如果你坚持的话,你可以从1970年第一个时刻的历元(UTC,1970-01-01T00:00Z)中提取毫秒数。

小心数据丢失。在生成以毫秒为单位的计数时,Instant中的任何微秒或纳秒都将被忽略。

long millisSinceEpoch = instant.toEpochMilli() ;

1517885996156


关于java.time

java.time框架构建在Java8及更高版本中。这些类取代了诸如java.util.DateCalendar、&SimpleDateFormat

现在处于维护模式的JodaTime项目建议迁移到java.Time类。

要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR310。

从哪里获得java.time类?

  • Java SE 8Java SE 9及更高版本
    • 内置
    • 标准Java API的一部分,带有捆绑实现
    • Java 9添加了一些小功能和修复程序
  • Java SE 6Java SE 7
    • 大部分java.time功能都是向后移植到Java6&7英寸ThreeTen背包
  • 安卓
    • java.time类的Android捆绑包实现的后续版本
    • 对于早期的Android,ThreeTenABP项目适用于ThreeTen Backport(如上所述)。请参阅如何使用ThreeTenABP…

ThreeTen Extra项目通过附加类扩展java.time。这个项目是将来可能添加到java.time的试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。

相关内容

  • 没有找到相关文章

最新更新