Skip to content

🌌 Cesium 中的 JulianDate(儒略日期)和 Clock(时钟)

什么是儒略日期?

JulianDate 是 Cesium 时间系统的基石,采用天文学儒略日概念,具有以下优势:

  • 连续无间断:不存在历法不连续问题(如闰年、闰秒)
  • 高精度存储:分离日和秒数存储,避免浮点精度损失
  • 时区无关性:以 UTC 时间为基准,避免时区混乱
  • 科学标准:符合国际天文学联合会标准

时间表示结构

js
{
  day: 2460830,      // 整数部分 - 从儒略日起始日算起的天数
  secondsOfDay: 43200 // 小数部分 - 当天已过去的秒数(0-86400)
}

JulianDate 与常规日期的转换

js
new Cesium.JulianDate(julianDayNumber, secondsOfDay, timeStandard);
名称描述
julianDayNumber儒略日数,表示整天数
secondsOfDay当前儒略日数的秒数
timeStandard定义前两个参数的时间标准,默认Cesium.TimeStandard.UTC

JulianDate 与北京时间

JulianDate 本身不涉及时区概念,它存储的是 UTC 时间,转换为北京时间需通过addHours添加 8 小时偏移。

js
// 创建当前时间对应的 JulianDate
const julianDate = Cesium.JulianDate.fromDate(new Date());
// 将 JulianDate 转换为北京时间
const beijingDate = Cesium.JulianDate.addHours(
  julianDate,
  8,
  new Cesium.JulianDate()
);

常规日期 → JulianDate

从当前时间创建

js
// 创建当前时间的JulianDate(推荐)
const nowJulian = Cesium.JulianDate.now();

// 从JavaScript Date创建
const jsDate = new Date();
const fromJsDate = Cesium.JulianDate.fromDate(jsDate);

从 ISO 8601 字符串创建

js
// 从ISO 8601字符串创建(UTC时间)
const isoString = "2025-06-04T12:00:00Z"; // Z表示UTC时间
const fromIso = Cesium.JulianDate.fromIso8601(isoString);

// 带时区的ISO字符串(会自动转换为UTC)
const localIsoString = "2025-06-04T20:00:00+08:00"; // 北京时间
const fromLocalIso = Cesium.JulianDate.fromIso8601(localIsoString);

JulianDate → 常规日期

转换为 JavaScript Date

js
const julianDate = Cesium.JulianDate.now();

// 转换为JavaScript Date(会丢失纳秒精度)
const jsDate = Cesium.JulianDate.toDate(julianDate);

格式化为 ISO 8601 字符串

js
const julianDate = Cesium.JulianDate.now();

// 格式化为ISO 8601字符串(UTC)
const isoString = Cesium.JulianDate.toIso8601(julianDate);
// 输出: "2025-06-04T12:00:00.000Z"

// 带毫秒精度
const isoWithMs = Cesium.JulianDate.toIso8601(julianDate, 3);
// 输出: "2025-06-04T12:00:00.500Z"(假设500ms)

时间操作实用函数

方法名描述
addDays增加天数
addHours增加小时数
addMinutes增加分钟数
addSeconds增加秒数

增加时间

js
const baseDate = Cesium.JulianDate.fromIso8601("2025-06-04T12:00:00Z");
const result = new Cesium.JulianDate();

// 增加1天3小时30分钟
const newDate = Cesium.JulianDate.addDays(baseDate, 1, result);
Cesium.JulianDate.addHours(newDate, 3, result);
Cesium.JulianDate.addMinutes(result, 30, result);

console.log(Cesium.JulianDate.toIso8601(result));
// 输出: "2025-06-05T15:30:00Z"

减少时间(使用负数)

js
const baseDate = Cesium.JulianDate.fromIso8601("2025-06-04T12:00:00Z");
const result = new Cesium.JulianDate();

// 减少2小时
Cesium.JulianDate.addHours(baseDate, -2, result);
console.log(Cesium.JulianDate.toIso8601(result));
// 输出: "2025-06-04T10:00:00Z"

Cesium 中的时钟 Clock

Clock 作为时间推进引擎,其工作流程如下:

  1. 初始化:设置 startTime、stopTime 和初始 currentTime
  2. 推进:根据 clockStep 和 multiplier 计算新时间
  3. 边界检查:根据 clockRange 处理边界行为
  4. 事件触发:调用 onTick 监听器
js
new Cesium.Clock(options);
属性类型说明
currentTimeJulianDate当前场景时间(可读写)
startTimeJulianDate时间轴起始时间
stopTimeJulianDate时间轴结束时间
multiplierNumber时间流逝倍率(正=正向播放,负=倒放)
clockStepClockStep判断对每一帧的调用是否依赖于帧或系统时钟。
clockRangeClockRange到达时间边界的行为:UNBOUNDED:不停止,CLAMPED:停止在边界,LOOP_STOP:循环播放
shouldAnimateBoolean是否自动播放(true=播放,false=暂停)

ClockStep 属性

ClockStep 决定时间如何前进:

ClockStep 值说明适用场景
SYSTEM_CLOCK与系统时间同步实时模拟
SYSTEM_CLOCK_MULTIPLIER系统时间 × 倍率加速/减速模拟
TICK_DEPENDENT每帧前进固定时间精确控制动画

ClockRange 属性

ClockRange 控制到达边界时的行为:

ClockRange 值说明适用场景
UNBOUNDED不受限制继续前进无边界时间
CLAMPED停在边界固定区间动画
LOOP_STOP循环播放重复动画

基础配置

js
const clock = new Cesium.Clock({
  startTime: Cesium.JulianDate.fromIso8601("2023-01-01T00:00:00Z"),
  currentTime: Cesium.JulianDate.fromIso8601("2023-01-01T12:00:00Z"),
  stopTime: Cesium.JulianDate.fromIso8601("2023-01-02T00:00:00Z"),
  clockRange: Cesium.ClockRange.LOOP_STOP, // 循环播放
  multiplier: 2.0, // 2倍速播放
  clockStep: Cesium.ClockStep.SYSTEM_CLOCK,
});

// 在 Viewer 中使用
const viewer = new Cesium.Viewer("cesiumContainer", {
  clock: clock,
  shouldAnimate: true, // 播放
});

动态控制

js
// 播放/暂停
viewer.clock.shouldAnimate = !viewer.clock.shouldAnimate;

// 调整播放速度
viewer.clock.multiplier = 4.0; // 4倍速

// 倒放
viewer.clock.multiplier = -1.0; // 倒放

// 跳转到特定时间
const targetTime = Cesium.JulianDate.fromIso8601("2025-06-04T18:00:00Z");
Cesium.JulianDate.clone(targetTime, viewer.clock.currentTime);

// 重置时钟
viewer.clock.currentTime = Cesium.JulianDate.clone(viewer.clock.startTime);