当前的 Apache Avro (1.8.2) 文档提到了“duration”逻辑类型:
A duration logical type annotates Avro fixed type of size 12, which stores three little-endian unsigned integers that represent durations at different granularities of time. The first stores a number in months, the second stores a number in days, and the third stores a number in milliseconds.
虽然这一切都说得通,但我无法在 .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 帮助的情况下实现。
最佳答案
乔达时间
Joda-Time项目现在在maintenance mode ,团队建议迁移到 java.time类。概念相似,因为这两个项目都是由同一个人 Stephen Colebourne 领导的。
java.time
java.time 框架提供了两个独立的类来表示独立于时间轴的时间跨度:
Period
若干年、月和日。持续时间
天数(与日历无关的通用 24 小时时间 block )、小时、分钟、秒和小数秒(纳秒)。
您可以将前两个数字用作 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”表示时长为“三年六个月四天十二小时三十分五秒”。
要生成这样的字符串,只需在Period
或Duration
上调用toString
。要解析,请调用 parse
。
Avro 中的奇怪概念
Avro 的持续时间概念(月 + 天 + 毫秒)对我来说似乎很奇怪。最大的问题是将年-月-日与时-分-秒混合使用几乎没有任何实际意义(想想看)。跟踪几个月而不是几年是令人惊讶的。
org.threeten.extra.PeriodDuration
如果您坚持要将年-月-日与时-分-秒合并,请考虑添加 ThreeTen-Extra库到您的项目。它提供了一个 PeriodDuration
类。
PeriodDuration pd = PeriodDuration.of( p , d ) ; // Pass `Period` and `Duration` objects as covered above.
同样,您可能希望调用 normalizedStandardDays
和 normalizedYears
.
关于java.time
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 类?
- Java SE 8 , Java SE 9 , Java SE 10 , 然后
- 内置。
- 带有捆绑实现的标准 Java API 的一部分。
- Java 9 添加了一些次要功能和修复。
- Java SE 6和 Java SE 7
- 许多 java.time 功能在 ThreeTen-Backport 中被反向移植到 Java 6 和 7 .
- Android
- 更高版本的 Android 捆绑了 java.time 类的实现。
- 对于早期的 Android (<26),ThreeTenABP项目适应 ThreeTen-Backport(如上所述)。参见 How to use ThreeTenABP… .
ThreeTen-Extra项目用附加类扩展 java.time。该项目是 future 可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如 Interval
, YearWeek
, YearQuarter
, 和 more .
关于java - 是否有 Avro 的 "duration"逻辑类型的 API 实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49992244/