我正在尝试在我的数据库中设置与服务器无关的日期时间,我相信这样做的最佳做法是设置 UTC DateTime。我的数据库服务器是 Cassandra,Java 的数据库驱动程序只理解 Date 类型。
因此,假设在我的代码中,我现在使用新的 Java 8 ZonedDateTime 来获取 UTC(ZonedDateTime.now(ZoneOffset.UTC)
),我该如何将此 ZonedDateTime 实例转换为“旧版” Date 类?
我正在尝试在我的数据库中设置与服务器无关的日期时间,我相信这样做的最佳做法是设置 UTC DateTime。我的数据库服务器是 Cassandra,Java 的数据库驱动程序只理解 Date 类型。
因此,假设在我的代码中,我现在使用新的 Java 8 ZonedDateTime 来获取 UTC(ZonedDateTime.now(ZoneOffset.UTC)
),我该如何将此 ZonedDateTime 实例转换为“旧版” Date 类?
您可以将 ZonedDateTime 转换为可以直接与 Date 一起使用的瞬间。
Date.from(java.time.ZonedDateTime.now().toInstant());
如果您正在使用适用于 Android 的ThreeTen backport并且不能使用较新的版本Date.from(Instant instant)
(至少需要 API 26),您可以使用:
ZonedDateTime zdt = ZonedDateTime.now();
Date date = new Date(zdt.toInstant().toEpochMilli());
或者:
Date date = DateTimeUtils.toDate(zdt.toInstant());
这是一个将当前系统时间转换为 UTC 的示例。它涉及将 ZonedDateTime 格式化为字符串,然后使用 java.text DateFormat 将字符串对象解析为日期对象。
ZonedDateTime zdt = ZonedDateTime.now(ZoneOffset.UTC);
final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd HH:mm:ss");
final DateFormat FORMATTER_YYYYMMDD_HH_MM_SS = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
String dateStr = zdt.format(DATETIME_FORMATTER);
Date utcDate = null;
try {
utcDate = FORMATTER_YYYYMMDD_HH_MM_SS.parse(dateStr);
}catch (ParseException ex){
ex.printStackTrace();
}
接受的答案对我不起作用。返回的日期始终是本地日期,而不是原始时区的日期。我住在UTC+2。
//This did not work for me
Date.from(java.time.ZonedDateTime.now().toInstant());
我想出了两种从 ZonedDateTime 获取正确日期的替代方法。
假设您有夏威夷的 ZonedDateTime
LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(ZoneId.of("US/Hawaii"); // UTC-10
或最初要求的UTC
Instant zulu = Instant.now(); // GMT, UTC+0
ZonedDateTime zdt = zulu.atZone(ZoneId.of("UTC"));
备选方案 1
我们可以使用 java.sql.Timestamp。这很简单,但它可能也会影响您的编程完整性
Date date1 = Timestamp.valueOf(zdt.toLocalDateTime());
备选方案 2
我们从毫秒创建日期(之前已在此处回答)。请注意,本地 ZoneOffset 是必须的。
ZoneOffset localOffset = ZoneOffset.systemDefault().getRules().getOffset(LocalDateTime.now());
long zonedMillis = 1000L * zdt.toLocalDateTime().toEpochSecond(localOffset) + zdt.toLocalDateTime().getNano() / 1000000L;
Date date2 = new Date(zonedMillis);
对于像 beehuang 评论的 docker 应用程序,您应该设置您的时区。
或者,您可以使用withZoneSameLocal。例如:
2014-07-01T00:00+02:00 [GMT+02:00] 转换为
Date.from(zonedDateTime.withZoneSameLocal(ZoneId.systemDefault()).toInstant())
至2014 年 7 月 1 日星期二 00:00:00 CEST及至
Date.from(zonedDateTime.toInstant())
至2014 年 6 月 30 日星期一 22:00:00 UTC
我用这个。
public class TimeTools {
public static Date getTaipeiNowDate() {
Instant now = Instant.now();
ZoneId zoneId = ZoneId.of("Asia/Taipei");
ZonedDateTime dateAndTimeInTai = ZonedDateTime.ofInstant(now, zoneId);
try {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateAndTimeInTai.toString().substring(0, 19).replace("T", " "));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
因为
Date.from(java.time.ZonedDateTime.ofInstant(now, zoneId).toInstant());
没用!!!如果你在你的电脑上运行你的应用程序,那没问题。但是如果你在 AWS 或 Docker 或 GCP 的任何区域运行,就会产生问题。因为计算机不是您在云上的时区。您应该在代码中设置正确的时区。例如,亚洲/台北。然后它将在 AWS 或 Docker 或 GCP 中更正。
public class App {
public static void main(String[] args) {
Instant now = Instant.now();
ZoneId zoneId = ZoneId.of("Australia/Sydney");
ZonedDateTime dateAndTimeInLA = ZonedDateTime.ofInstant(now, zoneId);
try {
Date ans = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateAndTimeInLA.toString().substring(0, 19).replace("T", " "));
System.out.println("ans="+ans);
} catch (ParseException e) {
}
Date wrongAns = Date.from(java.time.ZonedDateTime.ofInstant(now, zoneId).toInstant());
System.out.println("wrongAns="+wrongAns);
}
}
您可以使用Java 8 及更高版本中内置的java.time类来执行此操作。
ZonedDateTime temporal = ...
long epochSecond = temporal.getLong(INSTANT_SECONDS);
int nanoOfSecond = temporal.get(NANO_OF_SECOND);
Date date = new Date(epochSecond * 1000 + nanoOfSecond / 1000000);
如果您只对现在感兴趣,那么只需使用:
Date d = new Date();