Joda-Time奇怪的时刻

时间:2014-02-03 10:16:51

标签: java date jodatime

我正在尝试初始化一个Joda-Time DateTime对象,时间为12:00,这就是我这样做的方式:

public static final long MINUTE         = 60 * 1000;
public static final long HOUR           = 60 * MINUTE; 

DateTime defaultDate = new DateTime(HOUR * 12);
System.out.print("the hour is: " + defaultDate.getHourOfDay()) // getting 14

为什么我得到14而不是12?也许妈妈没有教我如何正确阅读时钟?!

2 个答案:

答案 0 :(得分:6)

你指定自Unix时代以来的数毫秒,即午夜 UTC

但是,您隐式使用DateTime中的系统默认时区,我怀疑在Unix时代,您的系统时区是UTC + 2。

如果要使用特定时区,可以在构造函数中传递:

DateTime defaultDate = new DateTime(HOUR * 12, DateTimeZone.UTC);

此外,您可以使用DateTimeConstants.MILLIS_PER_HOUR或使用java.util.concurrent.TimeUnit进行转换,而不是使用自己的常量。

答案 1 :(得分:1)

java.time

下面引用的是来自 home page of Joda-Time 的通知:

<块引用>

请注意,从 Java SE 8 开始,要求用户迁移到 java.time (JSR-310) - 替代该项目的 JDK 核心部分。

使用 java.time(现代日期时间 API)的解决方案:

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        ZonedDateTime zdt = ZonedDateTime.of(LocalDateTime.of(LocalDate.EPOCH, LocalTime.of(12, 0)), ZoneOffset.UTC);
        System.out.println(zdt);
    }
}

输出:

1970-01-01T12:00Z

ONLINE DEMO

几个重要的注意事项:

  1. ZonedDateTime#toString 删除秒和秒的分数(如果它们为零)。如果要显示它们,可以使用 DateTimeFormatter 例如
String formatted = zdt.format(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH));
  1. 输出中的 Z 是零时区偏移的 timezone designator。它代表祖鲁语并指定 Etc/UTC 时区(时区偏移为 +00:00 小时)。

Trail: Date Time 了解有关现代 Date-Time API 的更多信息。

您的代码出了什么问题?

下面引用了 DateTime(long) 的说明,重点是:

使用 ISOChronology 在默认时区构造一个设置为 1970-01-01T00:00:00Z 毫秒的实例。

您的位置 Israel was at an offset of +02:00 hours in 1970 以及 DateTime 实例已实例化,偏移量为 +02:00 小时。

演示:

import java.util.concurrent.TimeUnit;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;

public class Main {
    public static void main(String[] args) {
        DateTime defaultDate = new DateTime(TimeUnit.HOURS.toMillis(12), DateTimeZone.UTC);
        System.out.println(defaultDate);
    }
}

输出:

1970-01-01T12:00:00.000Z

您可能已经从代码中注意到的另一件事是,如果已经有可用的标准 API(例如 TimeUnit#toMillis),请不要自己执行计算。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project