Avro模式中的ISO 8601日期

4

在Avro中是否可以使用诸如“2019-08-24T14:15:22.000Z”之类的日期时间字段?

文档指出,需要使用逻辑类型的int/long类型来处理日期/时间戳。但是,在这种情况下,您需要将日期作为时期时间戳。

我正在寻找类似于以下内容:

{
    "name": "myDateField",
    "type": "string",
    "logicalType": "timestamp-micros"
}

但是在这种情况下似乎忽略了logicalType,因此可以在该字段中设置任何随机字符串。

你想做什么?你使用的是哪种编程语言?当然,你可以在字符串中放置任何值,唯一的选择是在(反)序列化期间检查并拒绝无效值。如果你不需要时区,为什么不使用纪元时间戳呢? - eik
@eik 我认为这与实际情况不太相关,但我需要 a) 从 Java/Spring 应用程序向主题发送消息,并且 b) 能够手动向代理发送消息(例如通过 Conduktor)。在这两种情况下,都应该进行验证。当然,我的消费者应用程序也会验证不正确的数据,但最好在发送到主题时更早地拒绝它。我一直在想 Avro 是否支持检查这些类型的日期字符串(ISO 8601 格式显然是目前最流行的)。当然,我还需要保留时区(在示例中只有 Z)。 - amseager
2个回答

1

逻辑类型的概念是你正在使用的库将会为你进行转换。

假设你有一个像这样的模式:

{
    "type": "record",
    "name": "root",
    "fields": [
        {
            "name": "mydate",
            "type": {
                "type": "int",
                "logicalType": "date",
            },
        },
    ]
}

如果您想在Python中使用此模式(例如),则可以按以下方式创建记录:
from datetime import date
record = {"mydate": date(2021, 11, 19)}

您正在使用的Avro库负责将date对象进行转换,以确定如何正确地表示为底层的int类型,然后将其序列化为int。同样,在读取记录时,该库负责首先将底层的int转换回date对象。从用户角度来看,您不必担心转换问题,只需使用更高级别的类型即可。

如果我在请求中收到一个ISO日期或从数据库中获取它,该怎么办?我认为这些情况在企业中非常普遍。 - amseager
抱歉,我不确定这些情况是如何处理的,因为我没有做过。 - Scott

0
假设您有一个简单的Pojo:
public class AvroEvent {
  public ZonedDateTime time;
}

您可以使用Avro逻辑类型转换:
public class ZonedDateTimeConversion extends Conversion<ZonedDateTime> {
  public Class<ZonedDateTime> getConvertedType() {
    return ZonedDateTime.class;
  }

  public String getLogicalTypeName() {
    return "zoneddatetime-string";
  }

  public Schema getRecommendedSchema() {
    return new ZonedDateTimeString().addToSchema(Schema.create(Schema.Type.STRING));
  }

  public ZonedDateTime fromCharSequence(CharSequence value, Schema schema, LogicalType type) {
    return ZonedDateTime.parse(value, DateTimeFormatter.ISO_ZONED_DATE_TIME);
  }

  public CharSequence toCharSequence(ZonedDateTime value, Schema schema, LogicalType type) {
    return value.format(DateTimeFormatter.ISO_ZONED_DATE_TIME);
  }

  public static class ZonedDateTimeString extends LogicalType {
    private ZonedDateTimeString() {
      super("zoneddatetime-string");
    }

    public void validate(Schema schema) {
      super.validate(schema);
      if (schema.getType() != Schema.Type.STRING) {
        throw new IllegalArgumentException(
            "ZonedDateTime (string) can only be used with an underlying string type");
      }
    }
  }
}

将其添加到 Avro 模型中,以便用于序列化和反序列化您的 Pojo:

    var model = new ReflectData();
    model.addLogicalTypeConversion(new ZonedDateTimeConversion());

    var schema = model.getSchema(AvroEvent.class);

    var encoder = new BinaryMessageEncoder<AvroEvent>(model, schema);
    
    var data = encoder.encode(...);

因此,您只能将有效的数据写入序列化,并在反序列化无效时间时抛出异常。

请参见https://github.com/fillmore-labs/avro-logical-type-conversion以获取一个运行示例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接