我们需要将Google Proto缓冲时间戳转换为正常日期。在这种情况下,是否可以将Google Proto缓冲区时间戳直接转换为Java LocalDate
?
答案 0 :(得分:5)
在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
一样,Instant
表示UTC中具有纳秒分辨率的时刻。
Instant instant = Instant.ofEpochSecond( ts.getSeconds() , ts.getNanos() ) ;
确定日期需要一个时区。在任何给定时刻,日期都会在全球范围内变化。
将ZoneId
应用于我们的Instant
以获得ZonedDateTime
。同一时刻,时间轴上的同一点,不同的时钟时间。
ZoneId z = ZoneId( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
将仅日期部分提取为LocalDate
。 LocalDate
没有时间,也没有时区。
LocalDate ld = zdt.toLocalDate() ;
警告:请勿为此目的使用LocalDateTime
类,不幸的是在另一个Answer中显示。该类故意缺少时区或从UTC偏移的任何概念。因此,它不能代表一个时刻,也不是时间轴上的一点。请参阅课程文档。
最好完全避免非常麻烦的旧式日期时间类,包括Date
,Calendar
,SimpleDateFormat
。但是,如果必须与尚未更新为 java.time 的旧代码进行互操作,则可以来回转换。调用添加到旧类中的新转换方法。
GregorianCalendar gc = GregorianCalendar.from( zdt ) ;
要将仅日期值表示为GregorianCalendar
,我们必须指定日期时间和时区。您可能希望将一天中的第一时间用作时间部分。永远不要假设第一刻是00:00:00。诸如夏令时之类的异常意味着第一时刻可能是另一个时间,例如01:00:00。让 java.time 确定第一时刻。
ZonedDateTime firstMomentOfDay = ld.atZone( z ) ;
GregorianCalendar gc = GregorianCalendar.from( firstMomentOfDay ) ;
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。
答案 1 :(得分:1)
最简单的方法是将日期从缓冲区Timestamp中提取到 String ,以便可以多次使用,然后:
Timestamp timestamp;
String sDate1 = timestamp.toString();
Date date1 = new SimpleDateFormat("dd/MM/yyyy").parse(sDate1);
如果要使其成为LocalDate,请执行以下操作:
Timestamp timestamp;
String sDate1 = timestamp.toString();
LocalDate localDate = LocalDate.parse(sDate1);
如果无法提取字符串时间戳并且有毫秒数,则还可以从中创建LocalDate和Date对象,因为它们都有承包商。
Timestamp timestamp;
long timeInMilliSeconds = Timestamp.toMillis(timestamp);
Date currentDate = new Date(timeInMilliSeconds);
LocalDate date = Instant.ofEpochMilli(timeInMilliSeconds).atZone(ZoneId.systemDefault()).toLocalDate();
答案 2 :(得分:1)
首先要注意:Protobuf的TimeStamp
比Java的LocalDate
(天)具有更高的分辨率(秒和几分之一秒),因此您将通过从TimeStamp
转换而丢失一些信息到LocalDate
请参见时间戳记JavaDoc的摘录:
时间戳表示与任何时区或 日历,以秒和秒的分数表示 毫秒的UTC纪元时间。
同一JavaDoc告诉我们,该值是基于大纪元时间的表示,这意味着我们可以使用Java的LocalDateTime#ofEpochSeconds进行转换而不会造成损失(因为LocalDateTime
也存储时间)并从此抽出时间来获得LocalDate
。
通过使用LocalDateTime
(em:Local),我们可以确保我们使用与TimeStamp
类相同的TimeZone偏移量,即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
后进行EDIT
看看Date
及其JavaDoc的可能构造函数,我们发现:
分配一个Date对象,并将其初始化为表示自标准基准时间(即“纪元”)以来的指定毫秒数,即格林尼治标准时间1970年1月1日。
并且因为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欧洲中部时间
秒:86400 = 1970年1月2日星期五欧洲中部时间
答案 3 :(得分:0)
PubsubMessage pubsubMessage = message.getPubsubMessage();
String data = pubsubMessage.getData().toStringUtf8();
//System.out.println(pubsubMessage.getMessageId());
Timestamp timestamp = pubsubMessage.getPublishTime();
//System.out.println(timestamp);
Instant instant = Instant.ofEpochSecond(timestamp.getSeconds() ,
timestamp.getNanos());
ZoneId z = ZoneId.of("America/Montreal");
ZonedDateTime zdt = instant.atZone(z);
LocalDateTime ldt = zdt.toLocalDateTime();
System.out.println("today's date==> "+ldt.getDayOfMonth());
上面的代码肯定会起作用。