forked from KNEMC/KLALB
KLALB V3.4
This commit is contained in:
@@ -0,0 +1,367 @@
|
||||
package org.kne.cloud.clock;
|
||||
|
||||
import java.math.BigInteger;
|
||||
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 BigInteger NANOS_PER_SECOND = BigInteger.valueOf(1_000_000_000L);
|
||||
public static final BigInteger NANOS_PER_MILLIS = BigInteger.valueOf(1_000_000L);
|
||||
|
||||
// NTP 纪元 (1900) 和 Unix 纪元 (1970) 之间的纳秒差
|
||||
public static final BigInteger NTP_EPOCH_OFFSET_NS = BigInteger.valueOf(2208988800L)
|
||||
.multiply(NANOS_PER_SECOND);
|
||||
|
||||
// 2^64 值,用于单位转换
|
||||
public static final BigInteger TWO_POW_64 = BigInteger.ONE.shiftLeft(64);
|
||||
|
||||
// 2^32 值,用于 64 位时间戳处理
|
||||
public static final BigInteger TWO_POW_32 = BigInteger.ONE.shiftLeft(32);
|
||||
|
||||
// 掩码常量
|
||||
public static final BigInteger MASK_32_BIT = new BigInteger("FFFFFFFF", 16);
|
||||
public static final BigInteger MASK_64_BIT = new BigInteger("FFFFFFFFFFFFFFFF", 16);
|
||||
|
||||
// ================== 核心转换方法 ==================
|
||||
// 2^32 秒,约 136.192 年,一个 NTP 纪元的长度
|
||||
public static final BigInteger SECONDS_PER_ERA = BigInteger.valueOf(0x100000000L);
|
||||
|
||||
public static BigInteger inferNtp64To128(long remote64Bit,BigInteger local128Bit ) {
|
||||
return inferNtp64To128(toUnsignedBigInteger(remote64Bit),local128Bit);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据本地 128 位时间戳和网络 64 位时间戳,推断并补全纪元信息
|
||||
*
|
||||
* @param remote64Bit 从网络接收的 64 位 NTP 时间戳
|
||||
* @param local128Bit 本地已知的 128 位 NTP 时间戳
|
||||
* @return 推断出的完整 128 位 NTP 时间戳
|
||||
*/
|
||||
public static BigInteger inferNtp64To128(BigInteger remote64Bit,BigInteger local128Bit ) {
|
||||
// 1. 从本地 128 位时间戳中提取纪元号和 64 位时间戳部分
|
||||
BigInteger localEra = NTPTimestamps.getEraNumber(local128Bit);
|
||||
BigInteger local64Bit = NTPTimestamps.getNtp64Timestamp(local128Bit);
|
||||
|
||||
// 3. 计算本地和远程 64 位时间戳的差异
|
||||
BigInteger difference = remote64Bit.subtract(local64Bit);
|
||||
|
||||
// 4. 判断纪元关系并推断远程时间戳的纪元
|
||||
BigInteger remoteEra;
|
||||
|
||||
// 如果差异很大(超过半个纪元),可能需要调整纪元
|
||||
BigInteger halfEra = BigInteger.valueOf(Long.MAX_VALUE);
|
||||
|
||||
if (difference.compareTo(halfEra) > 0) {
|
||||
// 远程时间戳比本地小很多,可能属于上一个纪元
|
||||
remoteEra = localEra.subtract(BigInteger.ONE);
|
||||
} else if (difference.compareTo(halfEra.negate()) < 0) {
|
||||
// 远程时间戳比本地大很多,可能属于下一个纪元
|
||||
remoteEra = localEra.add(BigInteger.ONE);
|
||||
} else {
|
||||
// 差异不大,属于同一个纪元
|
||||
remoteEra = localEra;
|
||||
}
|
||||
|
||||
// 5. 组合纪元号和 64 位时间戳,得到完整的 128 位时间戳
|
||||
return NTPTimestamps.ntp64To128(remote64Bit, remoteEra);
|
||||
}
|
||||
/**
|
||||
* 将从1970年开始的纳秒数转换为 NTPv4 128 位时间戳
|
||||
* 128位时间戳表示从1900年1月1日起经过的 2⁻⁶⁴ 秒的数量
|
||||
*/
|
||||
public static BigInteger nanosToNtp128BitTimestamp(Long128 nanosSince1970) {
|
||||
// 1. 计算从 1900 年开始的总纳秒数
|
||||
BigInteger totalNanosFrom1900 = nanosSince1970.toBigInteger().add(NTP_EPOCH_OFFSET_NS);
|
||||
|
||||
// 2. 将纳秒转换为 2⁻⁶⁴ 秒单位
|
||||
return totalNanosFrom1900.multiply(TWO_POW_64).divide(NANOS_PER_SECOND);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 NTPv4 128 位时间戳转换回从1970年开始的纳秒数
|
||||
*/
|
||||
public static Long128 ntp128BitToNanosTimestamp(BigInteger ntp128Timestamp) {
|
||||
// 1. 将 2⁻⁶⁴ 秒单位转换回纳秒
|
||||
BigInteger totalNanosFrom1900 = ntp128Timestamp.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
|
||||
|
||||
// 2. 计算从 1970 年开始的总纳秒数
|
||||
return Long128.valueOf( totalNanosFrom1900.subtract(NTP_EPOCH_OFFSET_NS));
|
||||
}
|
||||
|
||||
|
||||
public static BigInteger nanosToNtp128BitTimeInterval(BigInteger nanos) {
|
||||
// 2. 将纳秒转换为 2⁻⁶⁴ 秒单位
|
||||
return nanos.multiply(TWO_POW_64).divide(NANOS_PER_SECOND);
|
||||
}
|
||||
|
||||
|
||||
public static BigInteger ntp128BitToNanosInterval(BigInteger ntp128Timestamp) {
|
||||
// 1. 将 2⁻⁶⁴ 秒单位转换回纳秒
|
||||
BigInteger totalNanosFrom1900 = ntp128Timestamp.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
|
||||
|
||||
return totalNanosFrom1900;
|
||||
}
|
||||
|
||||
|
||||
// ================== 128位 ↔ 64位 转换 ==================
|
||||
|
||||
/**
|
||||
* 将 NTP 128 位时间戳转换为 NTP 64 位时间戳
|
||||
* 64位时间戳就是128位时间戳的中间64位
|
||||
*/
|
||||
public static BigInteger ntp128To64(BigInteger ntp128Timestamp) {
|
||||
return ntp128Timestamp.shiftRight(32).and(MASK_64_BIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 NTP 64 位时间戳转换为 NTP 128 位时间戳
|
||||
* 64位时间戳放在128位时间戳的中间64位,高32位Era和低32位分数为0
|
||||
*/
|
||||
public static BigInteger ntp64To128(BigInteger ntp64Timestamp) {
|
||||
return ntp64Timestamp.and(MASK_64_BIT).shiftLeft(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 NTP 64 位时间戳转换为 NTP 128 位时间戳(指定Era Number)
|
||||
*/
|
||||
public static BigInteger ntp64To128(BigInteger ntp64Timestamp, BigInteger eraNumber) {
|
||||
return eraNumber.and(MASK_32_BIT).shiftLeft(96)
|
||||
.or(ntp64Timestamp.and(MASK_64_BIT).shiftLeft(32));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 NTP 128 位时间戳中提取 Era Number(高32位)
|
||||
*/
|
||||
public static BigInteger getEraNumber(BigInteger ntp128Timestamp) {
|
||||
return ntp128Timestamp.shiftRight(96).and(MASK_32_BIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 NTP 128 位时间戳中提取 64 位时间戳(中间64位)
|
||||
*/
|
||||
public static BigInteger getNtp64Timestamp(BigInteger ntp128Timestamp) {
|
||||
return ntp128Timestamp.shiftRight(32).and(MASK_64_BIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 NTP 128 位时间戳中提取分数部分(低32位)
|
||||
*/
|
||||
public static BigInteger getFraction(BigInteger ntp128Timestamp) {
|
||||
return ntp128Timestamp.and(MASK_32_BIT);
|
||||
}
|
||||
|
||||
// ================== 工具方法 ==================
|
||||
|
||||
/**
|
||||
* 从毫秒和纳秒偏移构造 BigInteger 纳秒
|
||||
*/
|
||||
public static Long128 toNanosSince1970(long unixTimeMillis, long nanosOffset) {
|
||||
return Long128.valueOf(unixTimeMillis)
|
||||
.multiply(Long128.valueOf( NANOS_PER_MILLIS))
|
||||
.add(Long128.valueOf(nanosOffset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 BigInteger 纳秒提取毫秒和纳秒偏移
|
||||
*/
|
||||
public static long[] toMillisAndNanos(Long128 nanosSince1970) {
|
||||
Long128[] millisAndNanos = nanosSince1970.divideAndRemainder(Long128.valueOf( NANOS_PER_MILLIS));
|
||||
return new long[]{millisAndNanos[0].longValue(), millisAndNanos[1].longValue()};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个 128 位时间戳之间的时间差(纳秒)
|
||||
*/
|
||||
public static BigInteger calculateTimeDifference(BigInteger timestamp1, BigInteger timestamp2) {
|
||||
BigInteger diff = timestamp2.subtract(timestamp1);
|
||||
return diff.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 将 64 位 NTP 时间戳分解为秒数和分数
|
||||
*/
|
||||
public static BigInteger[] parseNtp64Timestamp(BigInteger ntp64Timestamp) {
|
||||
BigInteger seconds = ntp64Timestamp.shiftRight(32).and(MASK_32_BIT);
|
||||
BigInteger fraction = ntp64Timestamp.and(MASK_32_BIT);
|
||||
return new BigInteger[]{seconds, fraction};
|
||||
}
|
||||
|
||||
/**
|
||||
* 从秒数和分数构建 64 位 NTP 时间戳
|
||||
*/
|
||||
public static BigInteger buildNtp64Timestamp(BigInteger seconds, BigInteger fraction) {
|
||||
return seconds.and(MASK_32_BIT).shiftLeft(32).or(fraction.and(MASK_32_BIT));
|
||||
}
|
||||
|
||||
// ================== 测试代码 ==================
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("=== NTPv4 128位/64位时间戳转换测试 ===");
|
||||
|
||||
// 测试当前时间
|
||||
testCurrentTime();
|
||||
|
||||
// 测试 128位 ↔ 64位 转换
|
||||
test128To64Conversion();
|
||||
|
||||
// 测试 Era Number 处理
|
||||
testEraNumberHandling();
|
||||
|
||||
// 测试边界值
|
||||
testBoundaryValues();
|
||||
}
|
||||
|
||||
private static void testCurrentTime() {
|
||||
System.out.println("\n=== 当前时间测试 ===");
|
||||
|
||||
Long128 nanosSince1970 = toNanosSince1970(System.currentTimeMillis(), 123456);
|
||||
BigInteger ntp128 = nanosToNtp128BitTimestamp(nanosSince1970);
|
||||
BigInteger ntp64 = ntp128To64(ntp128);
|
||||
|
||||
System.out.println("从1970年开始的纳秒数: " + nanosSince1970);
|
||||
System.out.println("NTP 128-bit: 0x" + ntp128.toString(16).toUpperCase());
|
||||
System.out.println("NTP 64-bit: 0x" + ntp64.toString(16).toUpperCase());
|
||||
|
||||
// 反向转换验证
|
||||
BigInteger recovered128 = ntp64To128(ntp64);
|
||||
Long128 recoveredNanos = ntp128BitToNanosTimestamp(recovered128);
|
||||
|
||||
System.out.println("恢复的纳秒数: " + recoveredNanos);
|
||||
System.out.println("转换正确: " + (nanosSince1970.equals(recoveredNanos) ? "✅" : "❌"));
|
||||
}
|
||||
|
||||
private static void test128To64Conversion() {
|
||||
System.out.println("\n=== 128位 ↔ 64位 转换测试 ===");
|
||||
|
||||
// 创建一个测试用的 128 位时间戳
|
||||
BigInteger test128 = new BigInteger("EC652B7E912F00B81234567890ABCDEF", 16);
|
||||
|
||||
BigInteger ntp64 = ntp128To64(test128);
|
||||
BigInteger recovered128 = ntp64To128(ntp64);
|
||||
|
||||
System.out.println("原始128位: 0x" + test128.toString(16).toUpperCase());
|
||||
System.out.println("转换64位: 0x" + ntp64.toString(16).toUpperCase());
|
||||
System.out.println("恢复128位: 0x" + recovered128.toString(16).toUpperCase());
|
||||
|
||||
// 验证中间64位相同
|
||||
BigInteger original64Part = getNtp64Timestamp(test128);
|
||||
System.out.println("转换正确: " + (original64Part.equals(ntp64) ? "✅" : "❌"));
|
||||
}
|
||||
|
||||
private static void testEraNumberHandling() {
|
||||
System.out.println("\n=== Era Number 处理测试 ===");
|
||||
|
||||
BigInteger ntp64 = new BigInteger("EC652B7E912F00B8", 16);
|
||||
BigInteger eraNumber = new BigInteger("1", 16); // Era 1
|
||||
|
||||
BigInteger ntp128WithEra = ntp64To128(ntp64, eraNumber);
|
||||
BigInteger extractedEra = getEraNumber(ntp128WithEra);
|
||||
BigInteger extracted64 = getNtp64Timestamp(ntp128WithEra);
|
||||
|
||||
System.out.println("设置 Era: 0x" + eraNumber.toString(16).toUpperCase());
|
||||
System.out.println("提取 Era: 0x" + extractedEra.toString(16).toUpperCase());
|
||||
System.out.println("提取 64位: 0x" + extracted64.toString(16).toUpperCase());
|
||||
System.out.println("128位值: 0x" + ntp128WithEra.toString(16).toUpperCase());
|
||||
System.out.println("Era 正确: " + (eraNumber.equals(extractedEra) ? "✅" : "❌"));
|
||||
System.out.println("64位正确: " + (ntp64.equals(extracted64) ? "✅" : "❌"));
|
||||
}
|
||||
|
||||
private static void testBoundaryValues() {
|
||||
System.out.println("\n=== 边界值测试 ===");
|
||||
|
||||
// 测试最大值
|
||||
BigInteger max64 = MASK_64_BIT; // 0xFFFFFFFFFFFFFFFF
|
||||
BigInteger max128 = ntp64To128(max64);
|
||||
BigInteger recovered64 = ntp128To64(max128);
|
||||
|
||||
System.out.println("最大64位: 0x" + max64.toString(16).toUpperCase());
|
||||
System.out.println("转换128位: 0x" + max128.toString(16).toUpperCase());
|
||||
System.out.println("恢复64位: 0x" + recovered64.toString(16).toUpperCase());
|
||||
System.out.println("最大值转换正确: " + (max64.equals(recovered64) ? "✅" : "❌"));
|
||||
|
||||
// 测试 Era Number 边界
|
||||
BigInteger maxEra = MASK_32_BIT; // 0xFFFFFFFF
|
||||
BigInteger test64 = new BigInteger("1234567890ABCDEF", 16);
|
||||
BigInteger ntp128MaxEra = ntp64To128(test64, maxEra);
|
||||
BigInteger extractedMaxEra = getEraNumber(ntp128MaxEra);
|
||||
|
||||
System.out.println("最大Era转换正确: " + (maxEra.equals(extractedMaxEra) ? "✅" : "❌"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成时间序列测试
|
||||
*/
|
||||
public static void testTimeSeries() {
|
||||
System.out.println("\n=== 时间序列测试 ===");
|
||||
|
||||
Long128 startNanos = toNanosSince1970(System.currentTimeMillis(), 0);
|
||||
BigInteger start128 = nanosToNtp128BitTimestamp(startNanos);
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Long128 offsetNanos = Long128.valueOf(i).multiply(Long128.valueOf( NANOS_PER_SECOND).divide(Long128.valueOf(10)));
|
||||
Long128 currentNanos = startNanos.add(offsetNanos);
|
||||
BigInteger current128 = nanosToNtp128BitTimestamp(currentNanos);
|
||||
BigInteger current64 = ntp128To64(current128);
|
||||
|
||||
long[] time = toMillisAndNanos(currentNanos);
|
||||
System.out.printf("时间: %d ms + %d ns -> 64位: %s -> 128位: %s%n",
|
||||
time[0], time[1],
|
||||
current64.toString(16).toUpperCase(),
|
||||
current128.toString(16).toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 日期时间格式化器
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 128 位时间戳转换为可读字符串
|
||||
*/
|
||||
public static String ntp128ToString(BigInteger ntp128Timestamp) {
|
||||
Long128 nanosSince1970 = ntp128BitToNanosTimestamp(ntp128Timestamp);
|
||||
return nanosSince1970ToString(nanosSince1970);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 64 位时间戳转换为可读字符串
|
||||
*/
|
||||
public static String ntp64ToString(BigInteger ntp64Timestamp) {
|
||||
Long128 nanosSince1970 = ntp128BitToNanosTimestamp(ntp64To128( ntp64Timestamp));
|
||||
return nanosSince1970ToString(nanosSince1970);
|
||||
}
|
||||
|
||||
public static BigInteger toUnsignedBigInteger(long unsignedLong) {
|
||||
if (unsignedLong >= 0) {
|
||||
return BigInteger.valueOf(unsignedLong);
|
||||
} else {
|
||||
// 对于负数,通过添加 2^64 来转换为无符号表示
|
||||
return BigInteger.valueOf(unsignedLong & 0x7FFFFFFFFFFFFFFFL)
|
||||
.setBit(63);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user