Java处理Parquet的TIMESTAMP_MICROS_STRINGIFIER日期转换错误求助
解决Parquet TIMESTAMP_MICROS_STRINGIFIER转Java日期格式错误问题
问题根源
你的代码核心错误在于:Parquet的TIMESTAMP(MICROS)存储的是微秒级时间戳(测试值1640997340000000 = 1640997340秒 × 1000000微秒),但你直接用Instant.ofEpochMilli()把它当成毫秒处理,相当于把时间戳放大了1000倍,自然得到错误的远未来日期。
修复方案
需要将微秒时间戳转换为Java时间API能识别的单位,两种常用处理方式:
方式1:微秒转毫秒后生成Instant
将获取到的long值除以1000(整数除法舍去最后三位微秒):
Instant instant = Instant.ofEpochMilli(g.getLong(j, 0) / 1000);
方式2:精确保留微秒级精度
拆分秒和纳秒(1微秒=1000纳秒),适合需要高精度时间的场景:
long micros = g.getLong(j, 0); Instant instant = Instant.ofEpochSecond(micros / 1000000, (micros % 1000000) * 1000);
额外优化:替换过时的日期格式化类
SimpleDateFormat存在线程不安全问题,建议用Java 8+的DateTimeFormatter替代,同时指定时区避免默认时区偏差:
DateTimeFormatter dt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()); // 格式化时直接传入Instant valueToString = dt.format(instant);
修改后的完整代码
private static void writeGroup(BufferedWriter w, Group g, MessageType schema, String csvDelimiter) throws IOException { DateTimeFormatter dt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()); for (int j = 0; j < schema.getFieldCount(); j++) { if (j > 0) { w.write(csvDelimiter); } String valueToString; try { if ("TIMESTAMP_MICROS_STRINGIFIER".equals(g.getType().getType(schema.getFieldName(j)).asPrimitiveType().stringifier().toString())) { long micros = g.getLong(j, 0); // 方式1:转毫秒(满足当前需求) Instant instant = Instant.ofEpochMilli(micros / 1000); // 方式2:精确到微秒(按需启用) // Instant instant = Instant.ofEpochSecond(micros / 1000000, (micros % 1000000) * 1000); valueToString = dt.format(instant); } else { valueToString = g.getValueToString(j, 0); } } catch (RuntimeException e) { valueToString = ""; } w.write(valueToString); } w.write('\n'); }
验证结果
用测试时间戳1640997340000000计算:
- 转毫秒后得到
1640997340000,对应日期为2022-01-01 00:35:40,与期望结果完全匹配。
内容的提问来源于stack exchange,提问作者user3582583
相关产品推荐
相关产品推荐

