重新计算 Java 线程中的日期时间

Recalculation of datetime in Java Thread

在 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 实例吗?

有些日历 类 不是线程安全的。您可以将该代码插入带锁的 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);
}

tl;博士

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

Instant.now()

单次,不自动更新

一个 GregorianCalendar 只保留一个时刻,不会 自动更新。如果它自动更新,您将永远无法执行任何业务逻辑,因为值会随着您的代码不断变化 运行!

使用java.time

另外,GregorianCalendar 和它的兄弟 类 是一团糟,应该避免。它们现在是遗留的,被 java.time 类 取代。

使用 Instant 表示 UTC 中的当前时刻。 Instant class represents a moment on the timeline in UTC with a resolution of 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 对象。

指定 proper time zone name in the format of continent/region, such as America/Montreal, Africa/CasablancaPacific/Auckland。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们 不是 真正的时区,不是标准化的,甚至不是唯一的(!)。

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

zdt.toString(): 2017-02-27T09:48:58.664-05:00[America/Montreal]

看到这个 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 framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time 类.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

在哪里获取java.time类?

  • Java SE 8 and SE 9 及更高版本
    • 内置。
    • 标准 Java API 的一部分,带有捆绑实施。
    • Java 9 添加了一些小功能和修复。
  • Java SE 6 and SE 7
  • Android
    • ThreeTenABP 项目专门针对 Android 改编 ThreeTen-Backport(如上所述)。
    • 参见

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.