forked from KNEMC/KLALB
285 lines
11 KiB
Java
285 lines
11 KiB
Java
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 java.util.ArrayList;
|
||
import java.util.List;
|
||
import java.util.Objects;
|
||
|
||
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);
|
||
}
|
||
}
|
||
|
||
public static Long128 median(List<Long128> values) {
|
||
Objects.requireNonNull(values);
|
||
if ( values.isEmpty()) {
|
||
throw new IllegalArgumentException("列表不能为空");
|
||
}
|
||
|
||
// 1. 创建副本并排序
|
||
List<Long128> sorted = new ArrayList<>(values);
|
||
sorted.sort(Long128::compareTo);
|
||
|
||
// 2. 计算中位数
|
||
int size = sorted.size();
|
||
if (size % 2 == 1) {
|
||
// 奇数个:取中间值
|
||
return sorted.get(size / 2);
|
||
} else {
|
||
// 偶数个:取中间两个的平均值
|
||
Long128 left = sorted.get(size / 2 - 1);
|
||
Long128 right = sorted.get(size / 2);
|
||
return left.add(right).divide(Long128.valueOf(2));
|
||
}
|
||
}
|
||
} |