是否存在Avro的“持续时间”逻辑类型的API实现?

时间:2018-04-24 01:42:58

标签: java avro duration

当前的Apache Avro(1.8.2)文档提到了“duration”逻辑类型:

  

持续时间逻辑类型注释大小为12的Avro固定类型,它存储三个小端无符号整数,表示不同粒度时间的持续时间。第一个以月为单位存储数字,第二个以天为单位存储数字,第三个以毫秒为单位存储数字。

虽然这一切都有意义,但我无法在.Net或Java库中找到实际的实现。 documentation for logical types清楚地列出了除持续时间(日期,时间 - 毫秒,时间 - 微观,时间戳 - 毫秒和时间戳 - 微观)之外的所有逻辑类型。

“持续时间”相应地在我的Avro架构中定义:

{
    "type": "record",
    "name": "DataBlock",
    "fields": [
    {
        "name": "duration",
        "type": {
            "type": "fixed",
            "name": "DataBlockDuration",
            "size": 12
        }
    }]
}

在.Net(请原谅VB)中,我必须手动序列化持续时间:

Dim ret(11) As Byte
Dim months = BitConverter.GetBytes(duration.Months)
Dim days = BitConverter.GetBytes(duration.Days)
Dim milliseconds = BitConverter.GetBytes(duration.Milliseconds)

Array.Copy(months, 0, ret, 0, 4)
Array.Copy(days, 0, ret, 4, 4)
Array.Copy(milliseconds, 0, ret, 8, 4)

在Java中进行反序列化时,我必须通过这样做转换为org.joda.time.Period:

IntBuffer buf = ByteBuffer
                  .wrap(dataBlock.getDuration().bytes())
                  .order(ByteOrder.LITTLE_ENDIAN)
                  .asIntBuffer();

Period period = Period
                  .months(buf.get(0))
                  .withDays(buf.get(1))
                  .withMillis(buf.get(2));

我是否遗漏了某些内容,或者Avro团队是否编写了规范而忘记实施该规范?似乎这种数据类型必须在没有任何Avro API帮助的情况下实现。

2 个答案:

答案 0 :(得分:2)

约达时间

Joda-Time项目现在位于maintenance mode,团队建议迁移到java.time课程。概念是相似的,因为这两个项目都由同一个人Stephen Colebourne领导。

java.time

java.time 框架提供了两个独立的类来表示未附加到时间轴的时间跨度:

  • Period若数年,数月和数日。
  • Duration若数天(与日历无关的通用24小时时间段),小时,分钟,秒和小数秒(纳秒)。

您可以将前两个数字用作Period,将第三个数字用作Duration

Period p = Period.ofMonths( months ).plusDays( days ) ;
Duration d = Duration.ofMillis( millis ) ;

您可能想要normalize the years & months of the Period对象。例如,“15个月”的期间将标准化为“1年3个月”。

Period p = Period.ofMonths( months ).plusDays( days ).normalized() ;

ISO 8601

java.time 类在解析/生成字符串时使用标准的ISO 8601标准格式。

在一段时间或一段时间内,这意味着使用PnYnMnDTnHnMnS格式。 P标志着开头,T将任何年 - 月 - 天与任何小时 - 分钟 - 秒分开。例如,“P3Y6M4DT12H30M5S”表示持续时间为“三年,六年,四天,十二小时,三十分钟和五秒”。

要生成此类字符串,只需在toStringPeriod上调用Duration即可。要解析,请致电parse

Avro中的奇怪概念

Avro对持续时间(月+天+毫秒)的概念对我来说似乎很奇怪。最大的问题是,将数月 - 月 - 天与小时 - 分钟 - 秒混合很少有任何实际意义(考虑一下)。跟踪数月而非数年是令人惊讶的。

org.threeten.extra.PeriodDuration

如果您坚持要将年 - 月 - 天与小时 - 分 - 秒合并,请考虑将ThreeTen-Extra库添加到您的项目中。它提供PeriodDuration类。

PeriodDuration pd = PeriodDuration.of( p , d ) ;  // Pass `Period` and `Duration` objects as covered above.

同样,您可能想要致电normalizedStandardDaysnormalizedYears

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance 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的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 1 :(得分:2)

根据Apache问题跟踪器AVRO-2123,已指定逻辑持续时间类型但尚未实现。

所以,是的,Apache团队编写了规范,但忘了在这个细节中实现它。

我还在Avro-version 1.8.2中搜索了解压缩的jar文件以获取joda-library的任何导入,并且只找到了类org.apache.avro.data.TimeConversions,它获得了其他逻辑类型的转换,例如"日期" (映射到org.joda.time.LocalDate)等但不适用于Joda-class Period

通过使用Period - 类的Joda来解决问题似乎很好,因为:

  • Avro仍然使用Joda-Time(虽然后者处于维护模式),
  • Period - 类可以在几个月,几天和几毫秒内完全映射Avro-spec的持续时间(并且使用Avro规范要求的无符号整数以保持始终为正的持续时间对于避免奇数时段也是一件好事混合标志)。

我知道的Joda-Time的可能替代方案:

  • Threeten-Extra-class PeriodDuration(参见Basil Bourque的答案)
  • Time4J-class net.time4j.Duration(我的lib)

Threeten-Extra-class比Joda级别具有更少的功能(完全没有本地化,减少了ISO-8601合规性等),但在Time4J级别的特殊Avro相关场景中可能仍然足够具有比Joda更多的功能(在ISO兼容性,格式化,解析,规范化等方面)。

相关问题