Files
KLALB/src/org/kne/cloud/clock/NTPTimestamps.java
T

259 lines
10 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package org.kne.cloud.clock;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import org.kne.math.Long128;
public class NTPTimestamps {
// 常量定义
public static final Long128 NANOS_PER_SECOND = Long128.valueOf(1_000_000_000L);
public static final Long128 NANOS_PER_MILLIS = Long128.valueOf(1_000_000L);
// NTP 纪元 (1900) 和 Unix 纪元 (1970) 之间的纳秒差
public static final Long128 NTP_EPOCH_OFFSET_NS = Long128.valueOf(2208988800L)
.multiply(NANOS_PER_SECOND);
// 2^64 值,用于单位转换
public static final Long128 TWO_POW_64 = Long128.ONE.shiftLeft(64);
// 2^32 值,用于 64 位时间戳处理
public static final Long128 TWO_POW_32 = Long128.ONE.shiftLeft(32);
// 掩码常量
public static final Long128 MASK_32_BIT = new Long128(0xFFFFFFFF);
public static final Long128 MASK_64_BIT = new Long128(0xFFFFFFFFFFFFFFFFL);
// ================== 核心转换方法 ==================
// 2^32 秒,约 136.192 年,一个 NTP 纪元的长度
public static final Long128 SECONDS_PER_ERA = Long128.valueOf(0x100000000L);
private static final Long128 TWO_POW_N64_PER_NANOS = Long128.valueOf("1208925819614629");
public static Long128 inferNtp64To128(long remote64Bit,Long128 local128Bit ) {
return inferNtp64To128(toUnsignedLong128(remote64Bit),local128Bit);
}
/**
* 根据本地 128 位时间戳和网络 64 位时间戳,推断并补全纪元信息
*
* @param remote64Bit 从网络接收的 64 位 NTP 时间戳
* @param local128Bit 本地已知的 128 位 NTP 时间戳
* @return 推断出的完整 128 位 NTP 时间戳
*/
public static Long128 inferNtp64To128(Long128 remote64Bit,Long128 local128Bit ) {
// 1. 从本地 128 位时间戳中提取纪元号和 64 位时间戳部分
Long128 localEra = NTPTimestamps.getEraNumber(local128Bit);
Long128 local64Bit = NTPTimestamps.getNtp64Timestamp(local128Bit);
// 3. 计算本地和远程 64 位时间戳的差异
Long128 difference = remote64Bit.subtract(local64Bit);
// 4. 判断纪元关系并推断远程时间戳的纪元
Long128 remoteEra;
// 如果差异很大(超过半个纪元),可能需要调整纪元
Long128 halfEra = Long128.valueOf(Long.MAX_VALUE);
if (difference.compareTo(halfEra) > 0) {
// 远程时间戳比本地小很多,可能属于上一个纪元
remoteEra = localEra.subtract(Long128.ONE);
} else if (difference.compareTo(halfEra.negate()) < 0) {
// 远程时间戳比本地大很多,可能属于下一个纪元
remoteEra = localEra.add(Long128.ONE);
} else {
// 差异不大,属于同一个纪元
remoteEra = localEra;
}
// 5. 组合纪元号和 64 位时间戳,得到完整的 128 位时间戳
return NTPTimestamps.ntp64To128(remote64Bit, remoteEra);
}
/**
* 将从1970年开始的纳秒数转换为 NTPv4 128 位时间戳
* 128位时间戳表示从1900年1月1日起经过的 2⁻⁶⁴ 秒的数量
*/
public static Long128 nanosToNtp128BitTimestamp(Long128 nanosSince1970) {
// 1. 计算从 1900 年开始的总纳秒数
Long128 totalNanosFrom1900 = nanosSince1970.add(NTP_EPOCH_OFFSET_NS);
// 2. 将纳秒转换为 2⁻⁶⁴ 秒单位
// return totalNanosFrom1900.multiply(TWO_POW_64).divide(NANOS_PER_SECOND);
return totalNanosFrom1900.multiply(TWO_POW_N64_PER_NANOS).shiftRight(16);
}
/**
* 从 NTPv4 128 位时间戳转换回从1970年开始的纳秒数
*/
public static Long128 ntp128BitToNanosTimestamp(Long128 ntp128Timestamp) {
// 1. 将 2⁻⁶⁴ 秒单位转换回纳秒
Long128 totalNanosFrom1900 = ntp128Timestamp.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
// 2. 计算从 1970 年开始的总纳秒数
return totalNanosFrom1900.subtract(NTP_EPOCH_OFFSET_NS);
}
public static Long128 nanosToNtp128BitTimeInterval(Long128 nanos) {
// 2. 将纳秒转换为 2⁻⁶⁴ 秒单位
return nanos.multiply(TWO_POW_64).divide(NANOS_PER_SECOND);
}
public static Long128 ntp128BitToNanosInterval(Long128 ntp128Timestamp) {
// 1. 将 2⁻⁶⁴ 秒单位转换回纳秒
Long128 totalNanosFrom1900 = ntp128Timestamp.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
return totalNanosFrom1900;
}
// ================== 128位 ↔ 64位 转换 ==================
/**
* 将 NTP 128 位时间戳转换为 NTP 64 位时间戳
* 64位时间戳就是128位时间戳的中间64位
*/
public static Long128 ntp128To64(Long128 ntp128Timestamp) {
return ntp128Timestamp.shiftRight(32).and(MASK_64_BIT);
}
/**
* 将 NTP 64 位时间戳转换为 NTP 128 位时间戳
* 64位时间戳放在128位时间戳的中间64位,高32位Era和低32位分数为0
*/
public static Long128 ntp64To128(Long128 ntp64Timestamp) {
return ntp64Timestamp.and(MASK_64_BIT).shiftLeft(32);
}
/**
* 将 NTP 64 位时间戳转换为 NTP 128 位时间戳(指定Era Number
*/
public static Long128 ntp64To128(Long128 ntp64Timestamp, Long128 eraNumber) {
return eraNumber.and(MASK_32_BIT).shiftLeft(96)
.or(ntp64Timestamp.and(MASK_64_BIT).shiftLeft(32));
}
/**
* 从 NTP 128 位时间戳中提取 Era Number(高32位)
*/
public static Long128 getEraNumber(Long128 ntp128Timestamp) {
return ntp128Timestamp.shiftRight(96).and(MASK_32_BIT);
}
/**
* 从 NTP 128 位时间戳中提取 64 位时间戳(中间64位)
*/
public static Long128 getNtp64Timestamp(Long128 ntp128Timestamp) {
return ntp128Timestamp.shiftRight(32).and(MASK_64_BIT);
}
/**
* 从 NTP 128 位时间戳中提取分数部分(低32位)
*/
public static Long128 getFraction(Long128 ntp128Timestamp) {
return ntp128Timestamp.and(MASK_32_BIT);
}
// ================== 工具方法 ==================
/**
* 从毫秒和纳秒偏移构造 Long128 纳秒
*/
public static Long128 toNanosSince1970(long unixTimeMillis, long nanosOffset) {
return Long128.valueOf(unixTimeMillis)
.multiply( NANOS_PER_MILLIS)
.add(Long128.valueOf(nanosOffset));
}
/**
* 从 Long128 纳秒提取毫秒和纳秒偏移
*/
public static long[] toMillisAndNanos(Long128 nanosSince1970) {
Long128[] millisAndNanos = nanosSince1970.divideAndRemainder( NANOS_PER_MILLIS);
return new long[]{millisAndNanos[0].longValue(), millisAndNanos[1].longValue()};
}
/**
* 计算两个 128 位时间戳之间的时间差(纳秒)
*/
public static Long128 calculateTimeDifference(Long128 timestamp1, Long128 timestamp2) {
Long128 diff = timestamp2.subtract(timestamp1);
return diff.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
}
/**
* 将 64 位 NTP 时间戳分解为秒数和分数
*/
public static Long128[] parseNtp64Timestamp(Long128 ntp64Timestamp) {
Long128 seconds = ntp64Timestamp.shiftRight(32).and(MASK_32_BIT);
Long128 fraction = ntp64Timestamp.and(MASK_32_BIT);
return new Long128[]{seconds, fraction};
}
/**
* 从秒数和分数构建 64 位 NTP 时间戳
*/
public static Long128 buildNtp64Timestamp(Long128 seconds, Long128 fraction) {
return seconds.and(MASK_32_BIT).shiftLeft(32).or(fraction.and(MASK_32_BIT));
}
// 日期时间格式化器
private static final DateTimeFormatter DEFAULT_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
private static final DateTimeFormatter DETAILED_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.n");
public static String nanosSince1970ToString(Long128 nanos) {
Long128 millis = nanos.divide(Long128.valueOf(1_000_000));
Long128 nanosPart = nanos.mod(Long128.valueOf(1_000_000));
Instant instant = Instant.ofEpochMilli(millis.longValue());
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
return String.format("%s.%06d",
DEFAULT_FORMATTER.format(dateTime),
nanosPart.longValue());
}
public static String nanosSince1970ToString2(Long128 nanos) {
Long128 millis = nanos.divide(Long128.valueOf(1_000_000));
Instant instant = Instant.ofEpochMilli(millis.longValue());
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
return DEFAULT_FORMATTER.format(dateTime);
}
/**
* 将 128 位时间戳转换为可读字符串
*/
public static String ntp128ToString(Long128 ntp128Timestamp) {
Long128 nanosSince1970 = ntp128BitToNanosTimestamp(ntp128Timestamp);
return nanosSince1970ToString(nanosSince1970);
}
/**
* 将 64 位时间戳转换为可读字符串
*/
public static String ntp64ToString(Long128 ntp64Timestamp) {
Long128 nanosSince1970 = ntp128BitToNanosTimestamp(ntp64To128( ntp64Timestamp));
return nanosSince1970ToString(nanosSince1970);
}
public static Long128 toUnsignedLong128(long unsignedLong) {
if (unsignedLong >= 0) {
return Long128.valueOf(unsignedLong);
} else {
// 对于负数,通过添加 2^64 来转换为无符号表示
return Long128.valueOf(unsignedLong & 0x7FFFFFFFFFFFFFFFL)
.setBit(63);
}
}
}