从镶木地板到golang转换int96时间戳

时间:2018-11-01 14:53:55

标签: go parquet

具有此12字节数组(int96)进行时间戳记。

[128 76 69 116 64 7 0 0 48 131 37 0]

如何将其转换为时间戳?

我知道前8个字节应强制转换为代表某个时期的日期时间的int64毫秒。

2 个答案:

答案 0 :(得分:3)

前8个字节的时间以纳秒为单位,而不是毫秒。它们也不是从时代开始测量的,而是从午夜开始测量的。日期部分以Julian day number的形式存储在最后4个字节中。

这是我之前做过的实验的结果,可能会有所帮助。我将'2000-01-01 12:34:56'存储为int96并与镶木地板工具一起丢弃:

$ parquet-tools dump hdfs://path/to/parquet/file | tail -n 1
value 1: R:0 D:1 V:117253024523396126668760320

由于117253024523396126668760320 = 0x60FD4B3229000059682500,所以12个字节为00 60 FD 4B 32 29 00 00 | 59 68 25 00,其中|显示时间部分和日期部分之间的边界。

00 60 FD 4B 32 29 00 00是时间部分。我们需要反转字节,因为int96时间戳使用反转字节顺序,因此我们得到0x000029324BFD6000 = 45296 * 10 ^ 9纳秒= 45296秒= 12小时+ 34分钟+ 56秒。

59 68 25 00是日期部分,如果我们反转字节,我们将得到0x00256859 = 2451545作为儒略日数,即corresponds to 2000-01-01。

答案 1 :(得分:1)

@Zoltan,尽管您没有提供Golang提款,但您绝对值得投票。

感谢您和https://github.com/carlosjhr64/jd

我写了一个函数func int96ToJulian(parquetDate []byte) time.Time

playground

func int96ToJulian(parquetDate []byte) time.Time {
    nano := binary.LittleEndian.Uint64(parquetDate[:8])
    dt := binary.LittleEndian.Uint32(parquetDate[8:])

    l := dt + 68569
    n := 4 * l / 146097
    l = l - (146097*n+3)/4
    i := 4000 * (l + 1) / 1461001
    l = l - 1461*i/4 + 31
    j := 80 * l / 2447
    k := l - 2447*j/80
    l = j / 11
    j = j + 2 - 12*l
    i = 100*(n-49) + i + l

    tm := time.Date(int(i), time.Month(j), int(k), 0, 0, 0, 0, time.UTC)
    return tm.Add(time.Duration(nano))
}