【问题标题】:How to serialize a Date using AVRO in Java如何在 Java 中使用 AVRO 序列化日期
【发布时间】:2012-10-26 16:11:52
【问题描述】:

我实际上是在尝试使用 Avro 序列化包含日期的对象,而反序列化的日期与预期值不匹配(使用 avro 1.7.2 和 1.7.1 测试)。这是我要序列化的类:

import java.text.SimpleDateFormat;
import java.util.Date;

public class Dummy {
    private Date date;
    private SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss.SSS");

    public Dummy() {
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public Date getDate() {
        return date;
    }

    @Override
    public String toString() {
        return df.format(date);
    }
}

用于序列化/反序列化的代码:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Date;

import org.apache.avro.Schema;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;
import org.apache.avro.io.Decoder;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.Encoder;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.reflect.ReflectData;
import org.apache.avro.reflect.ReflectDatumReader;
import org.apache.avro.reflect.ReflectDatumWriter;

public class AvroSerialization {

    public static void main(String[] args) {
        Dummy expected = new Dummy();
        expected.setDate(new Date());
        System.out.println("EXPECTED: " + expected);
        Schema schema = ReflectData.get().getSchema(Dummy.class);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Encoder encoder = EncoderFactory.get().binaryEncoder(baos, null);
        DatumWriter<Dummy> writer = new ReflectDatumWriter<Dummy>(schema);
        try {
            writer.write(expected, encoder);
            encoder.flush();
            Decoder decoder = DecoderFactory.get().binaryDecoder(baos.toByteArray(), null);
            DatumReader<Dummy> reader = new ReflectDatumReader<Dummy>(schema);
            Dummy actual = reader.read(null, decoder);
            System.out.println("ACTUAL: " + actual);
        } catch (IOException e) {
            System.err.println("IOException: " + e.getMessage());
        }
    }
}

还有输出:

EXPECTED: 06/11/2012 05:43:29.188
ACTUAL: 06/11/2012 05:43:29.387

它与已知错误有关,还是与我序列化对象的方式有关?

【问题讨论】:

  • 我知道我没有回答您的问题,但我不会使用静态 SimpleDateFormat。它不是线程安全的类,因此在线程环境中会给你不可靠的结果
  • 感谢您的评论,这实际上不是生产代码,而只是我为了暴露我的问题而开发的一个测试类。无论如何你是对的,所以我删除了静态修饰符;)

标签: java datetime serialization avro


【解决方案1】:

我认为 AVRO 此时不会序列化日期。 我要做的是将它包装在另一个类中并在 avro 的人中存储为很长的 (date.gettime()) 添加this feature。 您看到不同 Date 值的原因是每次您(和 avro)创建 一个 Date 对象,它用当前系统时间初始化 Date。

【讨论】:

  • 谢谢您,您的回答中似乎不支持日期,并且日期实际上是用当前系统时间初始化的。
【解决方案2】:

Avro 1.8 现在有一个日期“logicalType”,它注释 int。例如:

{"name": "date", "type": "int", "logicalType": "date"}

引用规范:“日期逻辑类型注释 Avro int,其中 int 存储从 unix 纪元 1970 年 1 月 1 日(ISO 日历)开始的天数。”

【讨论】:

  • 为什么是 int 而不是 long?
  • @AlessandroDionisi 规范要求日期,因为这种特定类型是自纪元以来的天数。还有另一种逻辑类型“timestamp-millis”,表示更常见的毫秒数,它是很长的。
  • 这是 AVRO 的一个缺点,因为在反序列化之后,如果您在 JSON 中有日期,它将显示为- { date: 2020-08-10 } 而在 JSON 中存储日期是非法的带连字符,不带引号。预期值是 - {date: "2020-08-10"} 这意味着类型应该是字符串,而不是 int。
  • 谁使用 unix 纪元后的天数?为什么不将毫秒作为默认值?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-01
  • 1970-01-01
相关资源
最近更新 更多