nv-time-now 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/TEST/check-diff.js +133 -0
- package/TEST/check.js +98 -0
- package/TEST/estimate.js +21 -0
- package/TEST/tst-tmid.js +34 -0
- package/index.js +26 -0
- package/package.json +11 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// compare_time.js
|
|
2
|
+
const { performance } = require('perf_hooks');
|
|
3
|
+
const timeFunc = require('../index');
|
|
4
|
+
|
|
5
|
+
// 测试配置
|
|
6
|
+
const ITERATIONS = 100_000_000; // 1亿次
|
|
7
|
+
const REPORT_INTERVAL = 10_000_000; // 每1000万次报告一次进度
|
|
8
|
+
|
|
9
|
+
// 统计变量
|
|
10
|
+
let countEqual = 0;
|
|
11
|
+
let countGreater = 0;
|
|
12
|
+
let countLess = 0;
|
|
13
|
+
let totalDiff = 0; // timeFunc - Date.now()
|
|
14
|
+
let totalAbsDiff = 0; // |timeFunc - Date.now()|
|
|
15
|
+
let minDiff = Infinity;
|
|
16
|
+
let maxDiff = -Infinity;
|
|
17
|
+
let lastReportTime = performance.now();
|
|
18
|
+
|
|
19
|
+
// 主测试函数
|
|
20
|
+
function runComparisonTest() {
|
|
21
|
+
console.log(`开始比较测试,共 ${ITERATIONS.toLocaleString()} 次调用...`);
|
|
22
|
+
console.log('='.repeat(60));
|
|
23
|
+
|
|
24
|
+
for (let i = 0; i < ITERATIONS; i++) {
|
|
25
|
+
const t1 = timeFunc();
|
|
26
|
+
const t2 = Date.now();
|
|
27
|
+
const diff = t1 - t2;
|
|
28
|
+
|
|
29
|
+
// 更新统计
|
|
30
|
+
if (diff === 0) {
|
|
31
|
+
countEqual++;
|
|
32
|
+
} else if (diff > 0) {
|
|
33
|
+
countGreater++;
|
|
34
|
+
} else {
|
|
35
|
+
countLess++;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
totalDiff += diff;
|
|
39
|
+
totalAbsDiff += Math.abs(diff);
|
|
40
|
+
|
|
41
|
+
if (diff < minDiff) minDiff = diff;
|
|
42
|
+
if (diff > maxDiff) maxDiff = diff;
|
|
43
|
+
|
|
44
|
+
// 定期报告进度
|
|
45
|
+
if ((i + 1) % REPORT_INTERVAL === 0) {
|
|
46
|
+
const currentTime = performance.now();
|
|
47
|
+
const elapsed = (currentTime - lastReportTime) / 1000;
|
|
48
|
+
const progress = ((i + 1) / ITERATIONS * 100).toFixed(1);
|
|
49
|
+
console.log(`进度: ${progress}% | 已用时间: ${elapsed.toFixed(1)}秒 | 当前差值: ${diff}`);
|
|
50
|
+
lastReportTime = currentTime;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 计算结果
|
|
55
|
+
const avgDiff = totalDiff / ITERATIONS;
|
|
56
|
+
const avgAbsDiff = totalAbsDiff / ITERATIONS;
|
|
57
|
+
const totalCount = countEqual + countGreater + countLess;
|
|
58
|
+
|
|
59
|
+
// 输出结果
|
|
60
|
+
console.log('='.repeat(60));
|
|
61
|
+
console.log('测试结果汇总:');
|
|
62
|
+
console.log(`总调用次数: ${ITERATIONS.toLocaleString()}`);
|
|
63
|
+
console.log(`相等次数 (==): ${countEqual.toLocaleString()} (${(countEqual/totalCount*100).toFixed(4)}%)`);
|
|
64
|
+
console.log(`大于次数 (>): ${countGreater.toLocaleString()} (${(countGreater/totalCount*100).toFixed(4)}%)`);
|
|
65
|
+
console.log(`小于次数 (<): ${countLess.toLocaleString()} (${(countLess/totalCount*100).toFixed(4)}%)`);
|
|
66
|
+
console.log('-'.repeat(40));
|
|
67
|
+
console.log(`平均差值 (timeFunc - Date.now): ${avgDiff.toFixed(6)} ms`);
|
|
68
|
+
console.log(`平均绝对差值: ${avgAbsDiff.toFixed(6)} ms`);
|
|
69
|
+
console.log(`最小差值: ${minDiff.toFixed(6)} ms`);
|
|
70
|
+
console.log(`最大差值: ${maxDiff.toFixed(6)} ms`);
|
|
71
|
+
console.log('='.repeat(60));
|
|
72
|
+
|
|
73
|
+
// 分析结论
|
|
74
|
+
analyzeResults(countEqual, countGreater, countLess, avgDiff, avgAbsDiff);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 结果分析函数
|
|
78
|
+
function analyzeResults(equal, greater, less, avgDiff, avgAbsDiff) {
|
|
79
|
+
console.log('\n分析结论:');
|
|
80
|
+
|
|
81
|
+
// 1. 比较关系分析
|
|
82
|
+
if (equal > 0) {
|
|
83
|
+
console.log(`- 发现 ${equal} 次相等情况,表明两个函数在相同时间点可能返回相同值`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (greater > less) {
|
|
87
|
+
console.log(`- timeFunc 大于 Date.now() 的情况更多 (${greater} > ${less})`);
|
|
88
|
+
} else if (less > greater) {
|
|
89
|
+
console.log(`- timeFunc 小于 Date.now() 的情况更多 (${less} > ${greater})`);
|
|
90
|
+
} else {
|
|
91
|
+
console.log(`- timeFunc 和 Date.now() 大小关系均衡 (${greater} = ${less})`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 2. 差值分析
|
|
95
|
+
if (Math.abs(avgDiff) < 1) {
|
|
96
|
+
console.log(`- 平均差值接近零 (${avgDiff.toFixed(6)} ms),表明两个函数高度同步`);
|
|
97
|
+
} else if (avgDiff > 0) {
|
|
98
|
+
console.log(`- 平均而言,timeFunc 比 Date.now() 大 ${avgDiff.toFixed(3)} ms`);
|
|
99
|
+
} else {
|
|
100
|
+
console.log(`- 平均而言,timeFunc 比 Date.now() 小 ${(-avgDiff).toFixed(3)} ms`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 3. 精度分析
|
|
104
|
+
if (avgAbsDiff < 0.1) {
|
|
105
|
+
console.log(`- 平均绝对差值很小 (${avgAbsDiff.toFixed(3)} ms),表明两个函数非常接近`);
|
|
106
|
+
} else if (avgAbsDiff < 1) {
|
|
107
|
+
console.log(`- 平均绝对差值较小 (${avgAbsDiff.toFixed(3)} ms),表明两个函数基本一致`);
|
|
108
|
+
} else {
|
|
109
|
+
console.log(`- 平均绝对差值较大 (${avgAbsDiff.toFixed(3)} ms),表明两个函数存在显著差异`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 4. 误差来源解释
|
|
113
|
+
console.log('\n误差来源分析:');
|
|
114
|
+
console.log('- timeFunc 基于进程启动时的时间戳,而 Date.now() 基于系统时间');
|
|
115
|
+
console.log('- 系统时间调整(NTP同步、用户修改)会导致 Date.now() 突变');
|
|
116
|
+
console.log('- 高精度计时器(performance.now)与系统时钟可能存在微小漂移');
|
|
117
|
+
console.log('- JavaScript事件循环和CPU调度可能导致测量微小偏差');
|
|
118
|
+
|
|
119
|
+
// 5. 使用建议
|
|
120
|
+
console.log('\n使用建议:');
|
|
121
|
+
if (avgAbsDiff < 0.5) {
|
|
122
|
+
console.log('✅ 对于大多数应用,timeFunc 可以替代 Date.now(),提供更高精度');
|
|
123
|
+
} else {
|
|
124
|
+
console.log('⚠️ 当需要精确时间时,建议直接使用 Date.now() 或 performance.now()');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (Math.abs(avgDiff) > 5) {
|
|
128
|
+
console.log('⚠️ 注意:两个函数存在系统性偏差,不适合需要精确同步的场景');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 执行测试
|
|
133
|
+
runComparisonTest();
|
package/TEST/check.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// check.js (修改后的版本)
|
|
2
|
+
const timeFunc = require('../index');
|
|
3
|
+
const { performance } = require('perf_hooks');
|
|
4
|
+
|
|
5
|
+
function testMonotonicity(iterations = 10_000_000) {
|
|
6
|
+
console.log(`开始测试 ${iterations.toLocaleString()} 次调用...`);
|
|
7
|
+
|
|
8
|
+
let last = -Infinity;
|
|
9
|
+
let violations = 0; // 后值 < 前值
|
|
10
|
+
let equalCount = 0; // 后值 == 前值
|
|
11
|
+
let greaterCount = 0; // 后值 > 前值
|
|
12
|
+
let minIncrement = Infinity;
|
|
13
|
+
let maxIncrement = 0;
|
|
14
|
+
let lastPrint = 0;
|
|
15
|
+
|
|
16
|
+
const startTime = performance.now();
|
|
17
|
+
|
|
18
|
+
for (let i = 0; i < iterations; i++) {
|
|
19
|
+
const current = timeFunc();
|
|
20
|
+
|
|
21
|
+
// 跳过第一次比较(没有前值)
|
|
22
|
+
if (i > 0) {
|
|
23
|
+
// 检查单调性
|
|
24
|
+
if (current < last) {
|
|
25
|
+
violations++;
|
|
26
|
+
// console.error(`❌ 违反单调性 @ ${i}: ${last} → ${current} (Δ${(current-last).toFixed(6)})`);
|
|
27
|
+
} else if (current === last) {
|
|
28
|
+
equalCount++;
|
|
29
|
+
} else {
|
|
30
|
+
greaterCount++;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 记录增量
|
|
34
|
+
const increment = current - last;
|
|
35
|
+
if (increment > 0 && increment < minIncrement) minIncrement = increment;
|
|
36
|
+
if (increment > maxIncrement) maxIncrement = increment;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
last = current;
|
|
40
|
+
|
|
41
|
+
// 进度报告
|
|
42
|
+
if (i > 0 && i % 1_000_000 === 0) {
|
|
43
|
+
process.stdout.write('.');
|
|
44
|
+
lastPrint = i;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const duration = performance.now() - startTime;
|
|
49
|
+
|
|
50
|
+
// 计算比率
|
|
51
|
+
const totalComparisons = iterations - 1;
|
|
52
|
+
const violationRatio = (violations / totalComparisons * 100).toFixed(4);
|
|
53
|
+
const equalRatio = (equalCount / totalComparisons * 100).toFixed(4);
|
|
54
|
+
const greaterRatio = (greaterCount / totalComparisons * 100).toFixed(4);
|
|
55
|
+
|
|
56
|
+
console.log('\n\n测试结果:');
|
|
57
|
+
console.log(`调用次数: ${iterations.toLocaleString()}`);
|
|
58
|
+
console.log(`比较次数: ${totalComparisons.toLocaleString()}`);
|
|
59
|
+
console.log(`后值 < 前值: ${violations.toLocaleString()} (${violationRatio}%)`);
|
|
60
|
+
console.log(`后值 == 前值: ${equalCount.toLocaleString()} (${equalRatio}%)`);
|
|
61
|
+
console.log(`后值 > 前值: ${greaterCount.toLocaleString()} (${greaterRatio}%)`);
|
|
62
|
+
console.log('-'.repeat(40));
|
|
63
|
+
console.log(`最小正增量: ${minIncrement === Infinity ? 'N/A' : minIncrement.toFixed(6)} ms`);
|
|
64
|
+
console.log(`最大增量: ${maxIncrement.toFixed(3)} ms`);
|
|
65
|
+
console.log(`总耗时: ${duration.toFixed(3)} ms`);
|
|
66
|
+
console.log(`平均耗时: ${(duration / iterations * 1000).toFixed(6)} μs/次`);
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
violations,
|
|
70
|
+
equalCount,
|
|
71
|
+
greaterCount,
|
|
72
|
+
minIncrement,
|
|
73
|
+
maxIncrement,
|
|
74
|
+
duration,
|
|
75
|
+
ratios: {
|
|
76
|
+
violationRatio,
|
|
77
|
+
equalRatio,
|
|
78
|
+
greaterRatio
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 执行测试
|
|
84
|
+
const iterations = Number(process.argv[2] ?? 100000000);
|
|
85
|
+
const result = testMonotonicity(iterations);
|
|
86
|
+
const passed = result.violations === 0;
|
|
87
|
+
|
|
88
|
+
console.log(`\n最终结果: ${passed ? '✅ 通过非递减测试' : '❌ 未通过测试'}`);
|
|
89
|
+
console.log(`单调性: ${result.equalCount > 0 ? '非严格单调 (有相等值)' : '严格单调'}`);
|
|
90
|
+
|
|
91
|
+
// 打印比率摘要
|
|
92
|
+
console.log('\n比率摘要:');
|
|
93
|
+
console.log(`后值 < 前值: ${result.ratios.violationRatio}%`);
|
|
94
|
+
console.log(`后值 == 前值: ${result.ratios.equalRatio}%`);
|
|
95
|
+
console.log(`后值 > 前值: ${result.ratios.greaterRatio}%`);
|
|
96
|
+
console.log(`总和: ${(parseFloat(result.ratios.violationRatio) + parseFloat(result.ratios.equalRatio) + parseFloat(result.ratios.greaterRatio)).toFixed(4)}%`);
|
|
97
|
+
|
|
98
|
+
|
package/TEST/estimate.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const _debug_estimate_limit = ()=>{
|
|
2
|
+
var old = Date.now();
|
|
3
|
+
var c = 0;
|
|
4
|
+
while(true) {
|
|
5
|
+
var now = Date.now();
|
|
6
|
+
if(now === old) {
|
|
7
|
+
++c;
|
|
8
|
+
} else {
|
|
9
|
+
break;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return c;
|
|
13
|
+
}
|
|
14
|
+
const debug_estimate_limit = (ROUNDS=1000000)=>{
|
|
15
|
+
var mx =0 ;
|
|
16
|
+
for(var i=0;i<ROUNDS;++i) {
|
|
17
|
+
var r = _debug_estimate_limit();
|
|
18
|
+
if(r>mx) {mx=r}
|
|
19
|
+
}
|
|
20
|
+
return mx
|
|
21
|
+
}
|
package/TEST/tst-tmid.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const {mts_seq_pair} = require("../index")
|
|
2
|
+
|
|
3
|
+
// 生成UUID
|
|
4
|
+
const tmid = (salt_len=3) => {
|
|
5
|
+
var [mts, seq] = mts_seq_pair();
|
|
6
|
+
// mts 变成 hex XXXXXXXXXXXX 最多6个不足前面补0 12个字符
|
|
7
|
+
// seq 变成 hex XXXX , 最多4个不足前面补0 4个字符
|
|
8
|
+
var mts_str = mts.toString(16);
|
|
9
|
+
mts_str = mts_str.slice(0,12);
|
|
10
|
+
mts_str = mts_str.padStart(12, '0');
|
|
11
|
+
|
|
12
|
+
var seq_str = seq.toString(16);
|
|
13
|
+
seq_str = seq_str.slice(0,4);
|
|
14
|
+
seq_str = seq_str.padStart(4, '0');
|
|
15
|
+
|
|
16
|
+
var salt = Math.random()*(2**53);
|
|
17
|
+
var salt_str = salt.toString(16);
|
|
18
|
+
salt_str = salt_str.slice(0,salt_len);
|
|
19
|
+
salt_str = salt_str.padStart(salt_len, '0');
|
|
20
|
+
|
|
21
|
+
// 组合成UUID格式:mts-seq-salt
|
|
22
|
+
return mts_str + "-" + seq_str + "-" + salt_str;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const extract_tmid = (tmseq)=>{
|
|
26
|
+
var mts = parseInt(tmseq.substr(0, 12),16); // 0-11: 12字符时间戳
|
|
27
|
+
var seq = parseInt(tmseq.substr(13, 4),16); // 13-16: 4字符序列ID
|
|
28
|
+
var salt = parseInt(tmseq.substr(18), 16); // 18到结束: 盐值
|
|
29
|
+
return [new Date(mts),seq,salt]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
id = tmid();
|
|
33
|
+
console.log(id)
|
|
34
|
+
console.log(extract_tmid(id))
|
package/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const ORIG0 = Date.now();
|
|
2
|
+
const ORIG1 = performance.now();
|
|
3
|
+
|
|
4
|
+
let OLD = Date.now();
|
|
5
|
+
let ID = 0;
|
|
6
|
+
const mts_seq_pair = ()=>{
|
|
7
|
+
var now = Date.now();
|
|
8
|
+
if(now === OLD) {
|
|
9
|
+
++ID;
|
|
10
|
+
return [now,ID];
|
|
11
|
+
} else {
|
|
12
|
+
var pair = [now,0];
|
|
13
|
+
OLD = now;
|
|
14
|
+
ID = 0;
|
|
15
|
+
return pair;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const PRECISION = 0.0009765625;
|
|
20
|
+
module.exports = ()=>ORIG0 + (performance.now()-ORIG1);
|
|
21
|
+
module.exports.PRECISION = PRECISION;
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
module.exports.mts_seq_pair = mts_seq_pair;
|
|
25
|
+
|
|
26
|
+
|