【发布时间】:2017-03-20 13:12:54
【问题描述】:
我有一个将日期和日期时间(分别作为整数和双精度数)存储为修改儒略日数 (MJD) 的数据库。修改后的儒略日数是从 1858 年 11 月 17 日午夜 UTC 开始的连续天数。根据定义,它们始终以 UTC 计算,与 GMT 有 +0:00 的偏移量,并且不针对夏令时进行调整。这些属性简化了 DateTimes 的某些操作,例如优先级和日期算术。
缺点是 MJD 必须在使用前后从 UTC 重新定位并重新定位回 UTC,特别是对于日期边界至关重要的应用程序(例如,Medicare 将计费日期边界识别为 -local- 中的午夜)时间)。
考虑以下静态工厂方法,其目的是将“区域天数”(基本上,已添加适当偏移量以表示本地日期时间的 MJD)转移到 MJD(UTC)中:
public static MJD ofDayNumberInZone(double regDN, ZoneId zone) {
:
:
}
如果您有一个本地日期和时间,并且您知道本地时区,那么您应该拥有将 regDN 偏移回 UTC 所需的所有信息(根据 MJD 的要求),这似乎很直观)。
事实上,使用以前的 Java 日历 API 编写此函数相当简单。 regDN 很容易转换为用于设置 GregorianCalendar 实例的 Date。知道“本地时区”后,日历会报告 ZONE_OFFSET 和 DST_OFFSET 值,然后可以使用这些值将天数调整为 MJD。
这是我在 Java 8 DateTime API 中编写类似算法的尝试:
public static MJD ofDayNumberInZone(double zonedMJD, ZoneId zone) {
double epochSec = ((zonedMJD - MJD.POSIX_EPOCH_AS_MJD) * 86400.0);
LocalDateTime dt = LocalDateTime
.ofEpochSecond(
(long) epochSec,
(int) (epochSec - Math.floor(epochSec) * 1000000000.0),
---> zone.getRules().getOffset( <Instant> )
);
}
问题如箭头所示。使用 ofEpochSecond 方法构造 LocalDateTime 实例似乎需要您提前知道偏移量,这似乎违反直觉(我已经有了本地时间和时区,这是我想要的偏移量)。
我没有成功找到一种简单的方法来使用 Java 8 API 获取从本地时间到 UTC 的偏移量。虽然我可以继续使用旧的 Calendar API,但新的 DateTime 库提供了引人注目的优势......所以我想尝试解决这个问题。我错过了什么?
编辑:这是一个使用旧 Java 日历 API 的示例,说明如何将任意时区中的天数和小数天数“非区域化”为 UTC。此方法采用双精度,即“区域化日期数”和时区对象。它使用 GregorianCalendar 将参数转换为从 Epoch 开始的毫秒 UTC 计数:
private static final Object lockCal = new Object();
private static final SimpleDateFormat SDF = new SimpleDateFormat();
private static final GregorianCalendar CAL = new
GregorianCalendar(TimeZone.getTimeZone(HECTOR_ZONE));
:
:
public static MJD ofDayNumberInZone(double rdn, TimeZone tz) {
Date dat = new Date((long) ((rdn - MJD.POSIX_EPOCH_AS_MJD) *
(86400.0 * 1000.0)));
return MJD.ofDateInZone(dat, tz);
}
public static MJD ofDateInZone(Date dat, TimeZone tz) {
long utcMillisFromEpoch;
synchronized(lockCal) {
CAL.setTimeZone(tz);
CAL.setTime(dat);
utcMillisFromEpoch = CAL.getTimeInMillis();
}
return MJD.ofEpochMillisInUTC(utcMillisFromEpoch);
}
public static MJD ofEpochMillisInUTC(long millis)
{ return new MJD((millis / (86400.0 * 1000.0)) + POSIX_EPOCH_AS_MJD); }
【问题讨论】:
-
那么从
Zoned MJD转换为UTC MJD的方法的目的是什么? -
我不使用 Java,但让我们想象你成功了。我希望您能够在程序运行时获得有效的偏移量,或者可能考虑日期并更改当年夏令时的偏移量。当 DST 的开始/结束日期不同时,我不希望 Java 能够提供历史偏移量,当然,预测国会未来的行动是不可能的。那么您是否对历史或未来的日期/时间进行了适当的考虑?
-
@GerardAshton:这与我的问题无关,但 Java DateTime API 完全支持 IANA 时区数据库,并为特定于区域的时间偏移计算提供历史上准确的偏移。
-
我注意到 getOffset 方法需要一个瞬间,它是从纪元以来的秒数和纳秒数创建的。但是,如果您不知道偏移量并且不知道格林威治/UTC 时间,那么您就无法计算自纪元以来的秒数,因此您无法创建瞬间。
-
@GerardAshton:这是我遇到的悖论......如果 - 你 - 知道当地时间和当地时区,那么 - 你 - 有足够的信息来正确到达 UTC。然而,Java 8 DateTime API 似乎无法构造任何 Instant,除非它知道如何在内部以 UTC 表示它(显然,事先知道与 UTC 的偏移量作为先决条件)。我被困在如何获取当地时间和时区并从中制作即时信息。这在旧 API 中很简单,但我发现新 API 很难使用。
标签: java date datetime julian-date