3 回答
TA贡献1801条经验 获得超8个赞
作为 UTC 中的一个时刻,转换为java.time.Instant. 然后应用时区以获取ZonedDateTime. 将仅日期部分提取为LocalDate.
单线:
Instant
.ofEpochSecond( ts.getSeconds() , ts.getNanos() )
.atZone( ZoneId.of( "America/Montreal" ) )
.toLocalDate()
转变
第一步是将Timestamp对象的秒数和小数秒(纳秒)转换为java.time类。具体来说,java.time.Instant。就像Timestamp, anInstant代表 UTC 中的一个时刻,分辨率为纳秒。
Instant instant = Instant.ofEpochSecond( ts.getSeconds() , ts.getNanos() ) ;
确定日期需要时区。对于任何给定时刻,日期因地区而异。
将 a 应用ZoneId到 ourInstant以获得ZonedDateTime. 同一时刻,时间线上的同一点,不同的挂钟时间。
ZoneId z = ZoneId( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
将仅日期部分提取为LocalDate. ALocalDate没有时间和时区。
LocalDate ld = zdt.toLocalDate() ;
注意:不要不使用LocalDateTime类用于此目的,在另一个答案不幸所示。该类故意缺少时区或UTC偏移量的任何概念。因此,它不能代表一个时刻,也不是时间线上的一个点。请参阅类文档。
转变
最好完全避免非常麻烦的遗留日期时间类,包括Date, Calendar, SimpleDateFormat。但是,如果您必须与尚未更新为java.time 的旧代码进行互操作,则可以来回转换。调用添加到旧类的新转换方法。
GregorianCalendar gc = GregorianCalendar.from( zdt ) ;
要将仅日期值表示为 a,GregorianCalendar我们必须指定时间和时区。您可能希望使用一天中的第一时刻作为时间组件。永远不要假设第一个时刻是 00:00:00。夏令时等异常意味着第一个时刻可能是另一个时间,例如 01:00:00。让java.time确定第一时刻。
ZonedDateTime firstMomentOfDay = ld.atZone( z ) ;
GregorianCalendar gc = GregorianCalendar.from( firstMomentOfDay ) ;
TA贡献1810条经验 获得超4个赞
首先请注意:Protobuf 的TimeStamp分辨率(秒和几分之一秒)比 Java 的LocalDate(天)更高,因此您将通过从 转换TimeStamp为LocalDate
请参阅 TimeStamp 的JavaDoc 的摘录:
时间戳表示独立于任何时区或日历的时间点,以 UTC 纪元时间的纳秒分辨率表示为秒和秒的分数。
这个 JavaDoc 告诉我们,该值是基于纪元时间的表示,这意味着我们可以使用 Java 的LocalDateTime#ofEpochSeconds进行无损转换(因为LocalDateTime也存储时间),然后从那里剥离时间以获得LocalDate.
通过使用LocalDateTime(em: Local),我们可以确保我们使用与类相同的时区偏移量TimeStamp,即 UTC(再次来自 JavaDoc):
final Timestamp ts1 = Timestamp.newBuilder().setSeconds((60 * 60 * 24) - 1).build();
final Timestamp ts2 = Timestamp.newBuilder().setSeconds((60 * 60 * 24)).build();
final LocalDate ld1 = LocalDateTime.ofEpochSecond(ts1.getSeconds(), ts1.getNanos(), ZoneOffset.UTC).toLocalDate();
final LocalDate ld2 = LocalDateTime.ofEpochSecond(ts2.getSeconds(), ts2.getNanos(), ZoneOffset.UTC).toLocalDate();
System.out.println(ts1 + " = " + ld1);
System.out.println(ts2 + " = " + ld2);
输出
秒:86399 = 1970-01-01
秒:86400 = 1970-01-02
要求转换为后编辑java.util.Date
查看可能的构造函数Date及其JavaDoc,我们发现:
分配一个 Date 对象并将其初始化为表示自称为“纪元”的标准基准时间(即格林威治标准时间 1970 年 1 月 1 日 00:00:00)以来的指定毫秒数。
并且因为 GMT 是用于分区时间表示的旧标准并且它基本上是 UTC +/- 0,所以这个构造函数符合我们的需要:
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// making sure the Date objects use UTC as timezone
final Timestamp ts1 = Timestamp.newBuilder().setSeconds((60 * 60 * 24) - 1).build();
final Timestamp ts2 = Timestamp.newBuilder().setSeconds((60 * 60 * 24)).build();
final Date d1 = new Date(ts1.getSeconds() * 1000);
final Date d2 = new Date(ts2.getSeconds() * 1000);
System.out.println(ts1 + " = " + d1);
System.out.println(ts2 + " = " + d2);
输出:
秒:86399 = 1970 年 1 月 1 日星期四 23:59:59 CET
秒:86400 = 1970 年 1 月 2 日星期五 00:00:00 CET
添加回答
举报