在Java Thread中重新计算datetime

时间:2015-02-17 00:34:31

标签: java android multithreading time

确定Java线程中的日期时间(在Android中)的最佳方法是什么?

我有以下代码段:

public void repeatedlyPrintTheTime() {
    final Handler handler = new Handler();

    mR = new Runnable() {
        public void run() {
            System.out.println("Time 1 is " + mCalendar.getTime().toString());
            System.out.println("Time 2 is " + GregorianCalendar.getInstance().getTime().toString());
            handler.postDelayed(this, 1000);
        }
    };

    handler.postDelayed(mR, 1000);
}

时间1重复打印相同的时间,但每次迭代时间2都会更新。

每次我想检查时间是什么时,我是否真的需要获得GregorianCalendar的新实例?

2 个答案:

答案 0 :(得分:2)

TL;博士

是的,每次要捕获当前时刻时,都必须获得一个新的日期时间对象实例。没有自动更新现有实例。

Instant.now()

单一时刻,未自动更新

GregorianCalendar只有一个时刻,并且会自动更新。如果它是自动更新的,那么你将永远无法做任何业务逻辑,因为随着代码的运行,值会不断变化!

使用java.time

此外,GregorianCalendar及其兄弟类非常混乱,应该避免。它们现在已经遗留下来,取而代之的是java.time类。

以UTC为当前时刻使用InstantInstant类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。

Instant instant = Instant.now();
  

instant.toString():2017-02-27T14:48:58.664Z

要稍后再次捕获当前时间,请获取另一个Instant实例。

Instant instantLater = Instant.now();
  

instantLater.toString():2017-02-27T14:49:02.164Z

您甚至可以捕获它们之间的增量,作为Duration对象。

Duration duration = Duration.between( instant, instantLater );
  

duration.toString():PT3.5S

要通过特定区域wall-clock time的镜头看到同一时刻,请调整为时区。应用ZoneId获取ZonedDateTime对象。

continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用诸如ESTIST之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
  

zdt.toString():2017-02-27T09:48:58.664-05:00 [美国/蒙特利尔]

请参阅此code run live at IdeOne.com

要表示未来或过去的时刻,请指定输入以获取OffsetDateTimeZonedDateTime

  

...的JavaDoc

     

ZonedDateTime.of(int year,int month,int dayOfMonth,int hour,int minute,int second,int nanoOfSecond,ZoneId zone)

ZonedDateTime zdt = ZonedDateTime.of( 2017 , 1 , 23 , 12 , 34 , 56 , 123456789 , ZoneId.of( "America/Montreal" );

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 1 :(得分:0)

某些日历类不是线程安全的。您可以使用锁定在synchronized块中插入该代码:

private Object calendarLock; --Class attribute

public void repeatedlyPrintTheTime() {
    final Handler handler = new Handler();

    mR = new Runnable() {
        public void run() {
            synchronized(calendarLock) {
                System.out.println("Time 1 is " + mCalendar.getTime().toString());
                System.out.println("Time 2 is " + GregorianCalendar.getInstance().getTime().toString());
                handler.postDelayed(this, 1000);
            }
        }
    };

    handler.postDelayed(mR, 1000);
}