为了账号安全,请及时绑定邮箱和手机立即绑定

如何将 Google proto 时间戳转换为 Java LocalDate?

如何将 Google proto 时间戳转换为 Java LocalDate?

翻阅古今 2021-10-27 19:16:48
我们需要将 Google Proto 缓冲区时间戳转换为正常日期。在这种情况下,有没有办法将 Google Proto 缓冲区时间戳LocalDate直接转换为 Java ?
查看完整描述

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 ) ;

//img1.sycdn.imooc.com//617935400001620b09130524.jpg

查看完整回答
反对 回复 2021-10-27
?
蝴蝶不菲

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


查看完整回答
反对 回复 2021-10-27
  • 3 回答
  • 0 关注
  • 286 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信