3. 时间基础概念

在多源金融数据对齐中,时间从来不是一个简单的字段,而是一组语义不同、来源不同、精度不同的坐标系统。同一笔成交,交易所记录的是撮合时刻,行情网关记录的是发出时刻,采集程序记录的是接收时刻,落库时又可能补上写入时刻。若不加区分地把它们都当作“时间”使用,后续对齐必然出现错位、重复或漏配。本节先把这些时间语义拆开,建立统一的时间坐标系。

一、四种时间语义:谁在什么时候说了什么

流式与批处理系统通常区分四类时间,它们在金融数据链路中各有明确位置:

  • 事件时间(Event Time):业务事件真实发生的时刻,例如交易所撮合引擎生成成交回报的时间。它是语义上最准确的时间,也是事件时间对齐的首选基准。
  • 摄入时间(Ingestion Time):数据进入采集或消息中间件的时刻,例如行情网关收到交易所报文的瞬间。它介于事件时间与处理时间之间,常用于无法获取可靠事件时间时的近似。
  • 处理时间(Processing Time):计算引擎实际处理该条数据的机器时间,例如 Flink 算子调用 System.currentTimeMillis() 的时刻。它最易获取,但受延迟、重放、背压影响最大,不适合作为金融对齐基准。
  • 时间戳(Timestamp):附着在数据记录上的具体时间值,可能表示上述任意一种语义。关键不是“有没有时间戳”,而是“这个时间戳代表哪种语义”。
常见错误:把 Kafka 消息的 timestamp 直接当作事件时间。Kafka 消息时间戳默认可能是 CreateTime(生产者创建时间)或 LogAppendTime(Broker 写入时间),二者都不等于交易所撮合时间。

二、时间戳的精度、时区与夏令时

金融数据的时间戳精度差异极大:交易所逐笔委托可能精确到微秒甚至纳秒,而日频基本面数据只有日期。对齐前必须统一到同一精度,并明确舍入规则——是截断、四舍五入还是向下取整到秒。精度不统一会造成“同一事件被分到不同时间桶”。

时区问题更隐蔽。交易所时间通常以本地时区发布:上交所、深交所使用 Asia/Shanghai,纽交所使用 America/New_York,伦交所使用 Europe/London。若采集端用 UTC 存储、分析端按本地时区解读,就会出现数小时偏移。正确做法是:存储统一用 UTC 或带偏移量的 ISO 8601 时间,展示和交易日判断时再转换到交易所本地时区。

夏令时(DST)是时区问题的放大器。美国、欧洲部分市场在夏季会将时钟拨快一小时,导致同一交易所的开盘时刻在 UTC 下发生偏移。例如纽交所常规交易时段在冬令时为 14:30–21:00 UTC,夏令时则变为 13:30–20:00 UTC。若系统硬编码 UTC 开盘时间,夏令时切换当天必然错位。

# 错误:硬编码 UTC 开盘时间
market_open_utc = "14:30"

# 正确:按交易所时区动态计算
from zoneinfo import ZoneInfo
from datetime import datetime, time
ny = ZoneInfo("America/New_York")
open_local = datetime.combine(date, time(9, 30), tzinfo=ny)
open_utc = open_local.astimezone(ZoneInfo("UTC"))

三、金融交易日历:不是所有“天”都是交易日

金融数据对齐不能只用自然日。交易日历定义了哪些日期开市、哪些休市、是否有半日交易、以及盘前盘后时段。不同市场的日历不同:A 股有春节、国庆长假,有感恩节、独立日,港股还受台风等临时休市影响。跨市场对齐时,必须使用各自市场的交易日历,再映射到统一时间轴。

概念含义对齐中的用途
事件时间业务事件真实发生时刻首选对齐基准
摄入时间数据进入采集链路时刻事件时间缺失时的近似
处理时间计算引擎处理时刻仅用于监控与延迟度量
时间戳记录上的时间值需先判定其语义
时区时间表示的偏移规则统一存储为 UTC
夏令时季节性时钟调整动态计算开盘时刻
交易日历开市/休市日期集合过滤非交易日、定义交易时段

四、案例:跨市场开盘对齐的完整判断链

假设需要把 A 股与的逐笔成交按“开盘后第 N 分钟”对齐。处理流程如下:

  1. 读取每条成交的事件时间,确认其精度与时区;
  2. 将事件时间统一转换为 UTC 存储;
  3. 根据交易所交易日历判断该日是否开市,剔除休市日数据;
  4. 按交易所本地时区计算当日开盘时刻,注意夏令时;
  5. 计算 offset = event_time_utc - open_time_utc;
  6. 按 offset 分桶,完成跨市场对齐。
若某条数据只有摄入时间而无事件时间,可先用摄入时间近似,但必须在数据质量报告中标记该字段来源,避免与真实事件时间混用。

五、误区复盘

  • 误区一:所有时间戳都是事件时间。 实际可能是摄入或处理时间,需逐字段确认。
  • 误区二:用自然日代替交易日。 周末与节假日会产生大量空桶或错配。
  • 误区三:忽略夏令时。 切换日开盘偏移一小时,跨市场对齐整体错位。
  • 误区四:时区混用不报错。 带时区与不带时区的时间直接相减,结果可能静默错误。
金融数据时间语义与对齐坐标系统 时间 事件时间 交易所撮合时刻 摄入时间 网关接收时刻 处理时间 引擎计算时刻 时间戳 记录上的时间值 时区 Asia/Shanghai America/New_York Europe/London 统一存储为 UTC 夏令时 冬令:14:30 UTC 开盘 夏令:13:30 UTC 开盘 动态计算,禁止硬编码 切换日整体偏移一小时 金融交易日历 开市 / 休市 / 半日交易 盘前 / 盘中 / 盘后时段 跨市场需分别映射 过滤非交易日数据

建立统一时间坐标系后,后续的多源对齐才有共同基准。核心原则可以概括为:以事件时间为准,以 UTC 存储,以交易所时区解释,以交易日历过滤,以统一精度分桶。任何一条数据进入对齐流程前,都应先回答“它的时间戳是什么语义、什么时区、什么精度”,否则对齐结果只是看似正确的数字。