使用 Protocol Buffers 序列化日期

Serializing Dates with Protocol Buffers

所以经过一番搜索,建议使用int64纪元。

一切都很好,但是在与我的模型交互时,我想与实际的 LocalDate 对象交互,那么处理这个问题的策略是什么?

我能想到的两种策略是:

这里的常见做法是什么?

永远不要编辑生成的代码。这不是一个好主意的原因有很多,您编辑的代码可能不适用于未来版本的 Protobuf 库。

通常,从 int64 转换为某种 Date 对象的成本很低。我建议将数据保留为 int64 格式,只在需要时按需构建 LocalDate 对象。

也就是说,维护一个单独的手写模型并且只在解析/序列化时使用 Protobuf 类 也是常见的做法。

我开始为所有 dates/times:

创建通用解决方案
message Timestamp {
    int64 seconds = 1;
    int32 nanos = 2;
}

使用以下转换器:

public static Timestamp fromLocalDate(LocalDate localDate) {
    Instant instant = localDate.atStartOfDay().toInstant(ZoneOffset.UTC);
    return Timestamp.newBuilder()
        .setSeconds(instant.getEpochSecond())
        .setNanos(instant.getNano())
        .build();
}

public static LocalDate toLocalDate(Timestamp timestamp) {
    return LocalDateTime.ofInstant(Instant.ofEpochSecond(timestamp.getSeconds(), timestamp.getNanos()), ZoneId.of("UTC"))
        .toLocalDate();
}

无需创建您自己的时间戳版本。

您可以简单地使用 google.protobuf.Timestamp (source):

import "google/protobuf/timestamp.proto";
message Application {
    google.protobuf.Timestamp date = 1;
}

这是创建 Date 对象的标准(原型)方式。

使用新的 Java8 时间 API

可以轻松地将 Instant 转换为 google.Timestamp
LocalDate date = ...;
final Instant instant = java.sql.Timestamp.valueOf(date.atStartOfDay()).toInstant();        
Timestamp t = Timestamp.newBuilder().setSeconds(instant.getEpochSecond()).build();

请注意 Google protobuf lib 包含 Timestamp 的帮助程序:

https://github.com/google/protobuf/blob/master/java/util/src/main/java/com/google/protobuf/util/Timestamps.java

C# class 中生成的属性不是 .NET 日期和时间类型。这些属性使用 Google.Protobuf.WellKnownTypes 命名空间中的 TimestampDuration classes。这些 classes 提供了与 DateTimeOffsetDateTimeTimeSpan.

相互转换的方法
   syntax = "proto3"
  
   import "google/protobuf/timestamp.proto";

message Meeting {
    string subject = 1;
    google.protobuf.Timestamp time = 2;
}