dsh-metaphysics 0.14.3 → 0.16.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/CHANGELOG.md +213 -166
- package/README.md +229 -221
- package/client.js +1551 -111
- package/engine/bazi.js +505 -515
- package/engine/calendar.js +325 -256
- package/engine/crosscheck.js +133 -0
- package/engine/daliuren.js +339 -342
- package/engine/diff.js +197 -0
- package/engine/fail.js +13 -0
- package/engine/followup.js +173 -0
- package/engine/geo.js +1 -1
- package/engine/hepan.js +147 -144
- package/engine/index.js +566 -513
- package/engine/interpret-knowledge.js +277 -0
- package/engine/interpret-plain.js +197 -0
- package/engine/interpret.js +1356 -1176
- package/engine/liuyao.js +237 -238
- package/engine/lru.js +69 -0
- package/engine/meihua.js +137 -136
- package/engine/nayin.js +24 -0
- package/engine/qimen.js +442 -438
- package/engine/sanhe.js +26 -0
- package/engine/validate.js +56 -0
- package/engine/ziwei-hepan.js +123 -120
- package/engine/ziwei.js +821 -828
- package/index.js +229 -212
- package/package.json +1 -1
package/engine/bazi.js
CHANGED
|
@@ -1,515 +1,505 @@
|
|
|
1
|
-
// 四柱八字引擎
|
|
2
|
-
import {
|
|
3
|
-
STEMS, BRANCHES, TERM_NAMES,
|
|
4
|
-
ganzhiName, dayGanzhiIndex, jdToParts, partsToJd, sexagenaryIndex,
|
|
5
|
-
termWindow, previousJie, nextJie, equationOfTime, formatJd,
|
|
6
|
-
} from './calendar.js';
|
|
7
|
-
import { resolveAddress } from './geo.js';
|
|
8
|
-
import { computeBaziShensha } from './shensha.js';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (hasPair(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (
|
|
154
|
-
if (
|
|
155
|
-
if (
|
|
156
|
-
return
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
*
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const
|
|
233
|
-
const
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
//
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
const
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
const
|
|
246
|
-
const
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const
|
|
252
|
-
const
|
|
253
|
-
const
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
let
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
for (const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
if (
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
const
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
startAge: { years: startAgeYears, months: startAgeMonths },
|
|
507
|
-
toNextJieDays: Math.round(spanDays * 100) / 100,
|
|
508
|
-
list: dayun,
|
|
509
|
-
},
|
|
510
|
-
strength,
|
|
511
|
-
frame,
|
|
512
|
-
liunian,
|
|
513
|
-
liunianFrom: thisYear,
|
|
514
|
-
};
|
|
515
|
-
}
|
|
1
|
+
// 四柱八字引擎
|
|
2
|
+
import {
|
|
3
|
+
STEMS, BRANCHES, TERM_NAMES,
|
|
4
|
+
ganzhiName, dayGanzhiIndex, jdToParts, partsToJd, sexagenaryIndex,
|
|
5
|
+
termWindow, previousJie, nextJie, equationOfTime, formatJd, xunKongOf,
|
|
6
|
+
} from './calendar.js';
|
|
7
|
+
import { resolveAddress } from './geo.js';
|
|
8
|
+
import { computeBaziShensha } from './shensha.js';
|
|
9
|
+
import { assertCivil } from './validate.js';
|
|
10
|
+
import { nayinOf } from './nayin.js';
|
|
11
|
+
import { SANHE } from './sanhe.js';
|
|
12
|
+
import { analyzeBaziFrame, scoreLuck } from './geju.js';
|
|
13
|
+
|
|
14
|
+
// 地支藏干(本气 / 中气 / 余气)
|
|
15
|
+
export const HIDDEN_STEMS = {
|
|
16
|
+
子: ['癸'],
|
|
17
|
+
丑: ['己', '癸', '辛'],
|
|
18
|
+
寅: ['甲', '丙', '戊'],
|
|
19
|
+
卯: ['乙'],
|
|
20
|
+
辰: ['戊', '乙', '癸'],
|
|
21
|
+
巳: ['丙', '戊', '庚'],
|
|
22
|
+
午: ['丁', '己'],
|
|
23
|
+
未: ['己', '丁', '乙'],
|
|
24
|
+
申: ['庚', '壬', '戊'],
|
|
25
|
+
酉: ['辛'],
|
|
26
|
+
戌: ['戊', '辛', '丁'],
|
|
27
|
+
亥: ['壬', '甲'],
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const STEM_ELEMENT = {
|
|
31
|
+
甲: '木', 乙: '木', 丙: '火', 丁: '火', 戊: '土',
|
|
32
|
+
己: '土', 庚: '金', 辛: '金', 壬: '水', 癸: '水',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export const BRANCH_ELEMENT = {
|
|
36
|
+
子: '水', 丑: '土', 寅: '木', 卯: '木', 辰: '土', 巳: '火',
|
|
37
|
+
午: '火', 未: '土', 申: '金', 酉: '金', 戌: '土', 亥: '水',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const GENERATES = { 木: '火', 火: '土', 土: '金', 金: '水', 水: '木' };
|
|
41
|
+
const OVERCOMES = { 木: '土', 土: '水', 水: '火', 火: '金', 金: '木' };
|
|
42
|
+
|
|
43
|
+
const isYangStem = (stem) => STEMS.indexOf(stem) % 2 === 0;
|
|
44
|
+
|
|
45
|
+
// 两套藏干权重是不同用途,不是"同一件事写了两次":
|
|
46
|
+
// · 五行占比——看这一行在盘里有多少,本气 1 / 中气 0.5 / 余气 0.3;
|
|
47
|
+
// · 日主通根——看这一支能不能让日主站住,本气权重更高(1.2 / 0.6 / 0.3)。
|
|
48
|
+
const WUXING_HIDDEN_WEIGHT = [1, 0.5, 0.3];
|
|
49
|
+
const ROOT_HIDDEN_WEIGHT = [1.2, 0.6, 0.3];
|
|
50
|
+
|
|
51
|
+
const STEM_HE = { 甲己: '土', 乙庚: '金', 丙辛: '水', 丁壬: '木', 戊癸: '火' };
|
|
52
|
+
const STEM_CHONG_PAIRS = ['甲庚', '乙辛', '丙壬', '丁癸'];
|
|
53
|
+
const BRANCH_HE = { 子丑: '土', 寅亥: '木', 卯戌: '火', 辰酉: '金', 巳申: '水', 午未: '土' };
|
|
54
|
+
const SANHUI = { 寅卯辰: '木', 巳午未: '火', 申酉戌: '金', 亥子丑: '水' };
|
|
55
|
+
const BRANCH_CHONG = ['子午', '丑未', '寅申', '卯酉', '辰戌', '巳亥'];
|
|
56
|
+
const BRANCH_HAI = ['子未', '丑午', '寅巳', '卯辰', '申亥', '酉戌'];
|
|
57
|
+
const BRANCH_PO = ['子酉', '丑辰', '寅亥', '卯午', '巳申', '未戌'];
|
|
58
|
+
// 三刑:寅巳申(无恩之刑)、丑戌未(恃势之刑)、子卯(无礼之刑)。
|
|
59
|
+
// 另有「自刑」:辰午酉亥四支见同支即自刑(辰辰、午午、酉酉、亥亥),此前漏判。
|
|
60
|
+
const XING_GROUPS = [['寅', '巳', '申'], ['丑', '戌', '未'], ['子', '卯']];
|
|
61
|
+
const XING_SELF = ['辰', '午', '酉', '亥'];
|
|
62
|
+
|
|
63
|
+
const hasPair = (list, a, b) => list.includes(a + b) || list.includes(b + a);
|
|
64
|
+
|
|
65
|
+
/** 干支关系:五合、相冲、相克;六合、三合半合、三会半会拱会、冲、害、破、刑 */
|
|
66
|
+
export function buildRelations(pillars) {
|
|
67
|
+
const stems = ['year', 'month', 'day', 'hour'].map((k) => pillars[k].stem);
|
|
68
|
+
const branches = ['year', 'month', 'day', 'hour'].map((k) => pillars[k].branch);
|
|
69
|
+
|
|
70
|
+
const stemOut = [];
|
|
71
|
+
for (let i = 0; i < 4; i++) {
|
|
72
|
+
for (let j = i + 1; j < 4; j++) {
|
|
73
|
+
const a = stems[i];
|
|
74
|
+
const b = stems[j];
|
|
75
|
+
if (a === b) continue;
|
|
76
|
+
const he = STEM_HE[a + b] || STEM_HE[b + a];
|
|
77
|
+
if (he) { stemOut.push({ text: `${a}${b}合化${he}`, rank: 0 }); continue; }
|
|
78
|
+
if (hasPair(STEM_CHONG_PAIRS, a, b)) { stemOut.push({ text: `${a}${b}相冲`, rank: 1 }); continue; }
|
|
79
|
+
const ea = STEM_ELEMENT[a];
|
|
80
|
+
const eb = STEM_ELEMENT[b];
|
|
81
|
+
if (OVERCOMES[ea] === eb) stemOut.push({ text: `${a}克${b}`, rank: 3 });
|
|
82
|
+
else if (OVERCOMES[eb] === ea) stemOut.push({ text: `${b}克${a}`, rank: 3 });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const branchOut = [];
|
|
87
|
+
const set = new Set(branches);
|
|
88
|
+
const fullSans = [];
|
|
89
|
+
for (const [k, v] of Object.entries(SANHE)) {
|
|
90
|
+
if ([...k].every((c) => set.has(c))) {
|
|
91
|
+
branchOut.push({ text: `${k}三合${v}`, rank: 0 });
|
|
92
|
+
fullSans.push(k);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const fullHuis = [];
|
|
96
|
+
for (const [k, v] of Object.entries(SANHUI)) {
|
|
97
|
+
if ([...k].every((c) => set.has(c))) {
|
|
98
|
+
branchOut.push({ text: `${k}三会${v}`, rank: 0 });
|
|
99
|
+
fullHuis.push(k);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
for (let i = 0; i < 4; i++) {
|
|
103
|
+
for (let j = i + 1; j < 4; j++) {
|
|
104
|
+
const a = branches[i];
|
|
105
|
+
const b = branches[j];
|
|
106
|
+
if (a === b) {
|
|
107
|
+
// 同支不是"没关系":辰午酉亥两柱同见为自刑
|
|
108
|
+
if (XING_SELF.includes(a)) branchOut.push({ text: `${a}${b}自刑`, rank: 2 });
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const he = BRANCH_HE[a + b] || BRANCH_HE[b + a];
|
|
112
|
+
const sh = Object.keys(SANHE).find((k) => k.includes(a) && k.includes(b));
|
|
113
|
+
const hui = Object.keys(SANHUI).find((k) => k.includes(a) && k.includes(b));
|
|
114
|
+
if (he) {
|
|
115
|
+
// 六合优先,不再重复标半合/半会
|
|
116
|
+
branchOut.push({ text: `${a}${b}合${he}`, rank: 0 });
|
|
117
|
+
} else {
|
|
118
|
+
if (sh && !fullSans.includes(sh)) {
|
|
119
|
+
const mid = sh[1];
|
|
120
|
+
const kind = a === mid || b === mid ? '半合' : '拱合';
|
|
121
|
+
branchOut.push({ text: `${a}${b}${kind}${SANHE[sh]}`, rank: 0 });
|
|
122
|
+
}
|
|
123
|
+
if (hui && !fullHuis.includes(hui)) {
|
|
124
|
+
const adj = Math.abs(hui.indexOf(a) - hui.indexOf(b)) === 1;
|
|
125
|
+
branchOut.push({ text: `${a}${b}${adj ? '半会' : '拱会'}${SANHUI[hui]}`, rank: 0 });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (hasPair(BRANCH_CHONG, a, b)) branchOut.push({ text: `${a}${b}相冲`, rank: 1 });
|
|
129
|
+
if (hasPair(BRANCH_HAI, a, b)) branchOut.push({ text: `${a}${b}相害`, rank: 2 });
|
|
130
|
+
if (hasPair(BRANCH_PO, a, b)) branchOut.push({ text: `${a}${b}相破`, rank: 2 });
|
|
131
|
+
for (const g of XING_GROUPS) {
|
|
132
|
+
if (g.includes(a) && g.includes(b)) branchOut.push({ text: `${a}${b}相刑`, rank: 2 });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const uniq = (arr) => {
|
|
138
|
+
const seen = new Set();
|
|
139
|
+
const out = [];
|
|
140
|
+
for (const x of [...arr].sort((p, q) => p.rank - q.rank)) {
|
|
141
|
+
if (!seen.has(x.text)) { seen.add(x.text); out.push(x.text); }
|
|
142
|
+
}
|
|
143
|
+
return out;
|
|
144
|
+
};
|
|
145
|
+
return { stems: uniq(stemOut), branches: uniq(branchOut) };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** 十神:以日干为我 */
|
|
149
|
+
export function tenGod(dayStem, otherStem) {
|
|
150
|
+
const me = STEM_ELEMENT[dayStem];
|
|
151
|
+
const it = STEM_ELEMENT[otherStem];
|
|
152
|
+
const samePolarity = isYangStem(dayStem) === isYangStem(otherStem);
|
|
153
|
+
if (me === it) return samePolarity ? '比肩' : '劫财';
|
|
154
|
+
if (GENERATES[me] === it) return samePolarity ? '食神' : '伤官';
|
|
155
|
+
if (OVERCOMES[me] === it) return samePolarity ? '偏财' : '正财';
|
|
156
|
+
if (OVERCOMES[it] === me) return samePolarity ? '七杀' : '正官';
|
|
157
|
+
if (GENERATES[it] === me) return samePolarity ? '偏印' : '正印';
|
|
158
|
+
return '?';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function nayin(ganzhiIdx) {
|
|
162
|
+
return nayinOf(ganzhiIdx).name;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const JIE_TO_MONTH_BRANCH = { 0: 1, 2: 2, 4: 3, 6: 4, 8: 5, 10: 6, 12: 7, 14: 8, 16: 9, 18: 10, 20: 11, 22: 0 };
|
|
166
|
+
|
|
167
|
+
function pillar(ganzhiIdx, dayStem) {
|
|
168
|
+
const g = ganzhiName(ganzhiIdx);
|
|
169
|
+
const hidden = HIDDEN_STEMS[g.branch];
|
|
170
|
+
return {
|
|
171
|
+
ganzhi: g.name,
|
|
172
|
+
stem: g.stem,
|
|
173
|
+
branch: g.branch,
|
|
174
|
+
stemElement: STEM_ELEMENT[g.stem],
|
|
175
|
+
branchElement: BRANCH_ELEMENT[g.branch],
|
|
176
|
+
stemTenGod: dayStem ? tenGod(dayStem, g.stem) : null,
|
|
177
|
+
hidden: hidden.map((s, i) => ({
|
|
178
|
+
stem: s,
|
|
179
|
+
element: STEM_ELEMENT[s],
|
|
180
|
+
tenGod: dayStem ? tenGod(dayStem, s) : null,
|
|
181
|
+
role: ['本气', '中气', '余气'][i] ?? '余气',
|
|
182
|
+
})),
|
|
183
|
+
nayin: nayin(ganzhiIdx),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* 真太阳时修正
|
|
189
|
+
* @returns {{offsetMinutes:number, jd:number, note:string}}
|
|
190
|
+
*/
|
|
191
|
+
export function applyTrueSolar(jd, longitude) {
|
|
192
|
+
const p = jdToParts(jd);
|
|
193
|
+
if (longitude == null || Number.isNaN(longitude)) {
|
|
194
|
+
return { offsetMinutes: 0, jd, note: '未提供经度,按东八区平太阳时' };
|
|
195
|
+
}
|
|
196
|
+
const longitudeMinutes = (longitude - 120) * 4;
|
|
197
|
+
const eot = equationOfTime(p.year, p.month, p.day);
|
|
198
|
+
const offset = longitudeMinutes + eot;
|
|
199
|
+
return {
|
|
200
|
+
offsetMinutes: Math.round(offset * 10) / 10,
|
|
201
|
+
jd: jd + offset / 1440,
|
|
202
|
+
note: `经度差 ${longitudeMinutes.toFixed(1)} 分 + 均时差 ${eot.toFixed(1)} 分`,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 排四柱八字
|
|
208
|
+
* @param {object} input { year,month,day,hour,minute, gender:'male'|'female', longitude?, lateZi?:boolean, trueSolar?:boolean }
|
|
209
|
+
*/
|
|
210
|
+
export function buildBazi(input) {
|
|
211
|
+
assertCivil(input);
|
|
212
|
+
const { year, month, day, hour = 0, minute = 0, gender = 'male' } = input;
|
|
213
|
+
const lateZi = input.lateZi !== false;
|
|
214
|
+
const useTrueSolar = input.trueSolar !== false;
|
|
215
|
+
|
|
216
|
+
const civilJd = partsToJd({ year, month, day, hour, minute });
|
|
217
|
+
// 地址 -> 经度:手填的 longitude 优先,其次按地址查表
|
|
218
|
+
const geo = input.geo || (input.address ? resolveAddress(input.address) : null);
|
|
219
|
+
const longitude = typeof input.longitude === 'number'
|
|
220
|
+
? input.longitude
|
|
221
|
+
: (geo && typeof geo.lon === 'number' ? geo.lon : undefined);
|
|
222
|
+
const solar = useTrueSolar ? applyTrueSolar(civilJd, longitude) : { offsetMinutes: 0, jd: civilJd, note: '未启用真太阳时' };
|
|
223
|
+
const jd = solar.jd;
|
|
224
|
+
|
|
225
|
+
// 八字只用「节」定月柱与起运(气不参与),传 jieOnly 省掉一半节气求值
|
|
226
|
+
const terms = termWindow(year, { jieOnly: true });
|
|
227
|
+
const prevJieTerm = previousJie(terms, jd);
|
|
228
|
+
const nextJieTerm = nextJie(terms, jd);
|
|
229
|
+
|
|
230
|
+
// 年柱:以立春为界
|
|
231
|
+
const lichun = terms.find((t) => t.index === 2 && t.year === year);
|
|
232
|
+
const solarYear = lichun && jd < lichun.jd ? year - 1 : year;
|
|
233
|
+
const yearIdx = (((solarYear - 4) % 60) + 60) % 60;
|
|
234
|
+
const yearStem = STEMS[yearIdx % 10];
|
|
235
|
+
|
|
236
|
+
// 月柱:以「节」为界
|
|
237
|
+
const monthBranchIdx = JIE_TO_MONTH_BRANCH[prevJieTerm.index];
|
|
238
|
+
const yinMonthStem = ((STEMS.indexOf(yearStem) % 5) * 2 + 2) % 10;
|
|
239
|
+
const monthOffset = ((monthBranchIdx - 2) % 12 + 12) % 12; // 0 = 寅月
|
|
240
|
+
const monthStemIdx = (yinMonthStem + monthOffset) % 10;
|
|
241
|
+
const monthIdx = sexagenaryIndex(monthStemIdx, monthBranchIdx);
|
|
242
|
+
|
|
243
|
+
// 日柱:23:00 后是否换日
|
|
244
|
+
const jdnBase = Math.floor(jd + 0.5);
|
|
245
|
+
const hourOfDay = jdToParts(jd).hour;
|
|
246
|
+
const jdn = lateZi && hourOfDay >= 23 ? jdnBase + 1 : jdnBase;
|
|
247
|
+
const dayIdx = dayGanzhiIndex(jdn);
|
|
248
|
+
const dayStem = STEMS[dayIdx % 10];
|
|
249
|
+
|
|
250
|
+
// 时柱:五鼠遁
|
|
251
|
+
const hourBranchIdx = Math.floor(((hourOfDay + 1) % 24) / 2);
|
|
252
|
+
const ziHourStem = ((STEMS.indexOf(dayStem) % 5) * 2) % 10;
|
|
253
|
+
const hourStemIdx = (ziHourStem + hourBranchIdx) % 10;
|
|
254
|
+
const hourIdx = sexagenaryIndex(hourStemIdx, hourBranchIdx);
|
|
255
|
+
|
|
256
|
+
const pillars = {
|
|
257
|
+
year: pillar(yearIdx, dayStem),
|
|
258
|
+
month: pillar(monthIdx, dayStem),
|
|
259
|
+
day: pillar(dayIdx, dayStem),
|
|
260
|
+
hour: pillar(hourIdx, dayStem),
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// 大运
|
|
264
|
+
const isYangYear = STEMS.indexOf(yearStem) % 2 === 0;
|
|
265
|
+
const forward = (isYangYear && gender === 'male') || (!isYangYear && gender === 'female');
|
|
266
|
+
const spanDays = forward ? nextJieTerm.jd - jd : jd - prevJieTerm.jd;
|
|
267
|
+
const totalMonths = spanDays * 4; // 3 天 = 1 年 = 12 个月
|
|
268
|
+
let startAgeYears = Math.floor(totalMonths / 12);
|
|
269
|
+
let startAgeMonths = Math.round(totalMonths % 12);
|
|
270
|
+
// 四舍五入到 12 个月时必须进位,否则显示「X 岁 12 个月起运」
|
|
271
|
+
if (startAgeMonths >= 12) { startAgeMonths -= 12; startAgeYears += 1; }
|
|
272
|
+
|
|
273
|
+
const dayun = [];
|
|
274
|
+
for (let i = 1; i <= 8; i++) {
|
|
275
|
+
const idx = (((monthIdx + (forward ? i : -i)) % 60) + 60) % 60;
|
|
276
|
+
const g = ganzhiName(idx);
|
|
277
|
+
dayun.push({
|
|
278
|
+
step: i,
|
|
279
|
+
startAge: startAgeYears + (i - 1) * 10,
|
|
280
|
+
ganzhi: g.name,
|
|
281
|
+
stem: g.stem,
|
|
282
|
+
branch: g.branch,
|
|
283
|
+
stemTenGod: tenGod(dayStem, g.stem),
|
|
284
|
+
nayin: nayin(idx),
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// 流年(默认从「今年」起排 10 年;传 input.nowYear 可钉死基准年,用于复现历史结论)
|
|
289
|
+
const thisYear = Number(input.nowYear) || new Date().getFullYear();
|
|
290
|
+
const liunian = [];
|
|
291
|
+
for (let y = thisYear; y < thisYear + 10; y++) {
|
|
292
|
+
const idx = (((y - 4) % 60) + 60) % 60;
|
|
293
|
+
liunian.push({
|
|
294
|
+
year: y,
|
|
295
|
+
age: y - solarYear + 1,
|
|
296
|
+
ganzhi: ganzhiName(idx).name,
|
|
297
|
+
stemTenGod: tenGod(dayStem, ganzhiName(idx).stem),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// 五行统计(天干 1.0;地支藏干按 WUXING_HIDDEN_WEIGHT)
|
|
302
|
+
const wuxing = { 木: 0, 火: 0, 土: 0, 金: 0, 水: 0 };
|
|
303
|
+
for (const p of Object.values(pillars)) {
|
|
304
|
+
wuxing[p.stemElement] += 1;
|
|
305
|
+
p.hidden.forEach((h, i) => {
|
|
306
|
+
wuxing[h.element] += WUXING_HIDDEN_WEIGHT[i] ?? 0.1;
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
for (const k of Object.keys(wuxing)) wuxing[k] = Math.round(wuxing[k] * 10) / 10;
|
|
310
|
+
|
|
311
|
+
// 旬空(以日柱所在旬)
|
|
312
|
+
const xunStart = Math.floor(dayIdx / 10) * 10;
|
|
313
|
+
const kongwang = [
|
|
314
|
+
BRANCHES[(xunStart + 10) % 12],
|
|
315
|
+
BRANCHES[(xunStart + 11) % 12],
|
|
316
|
+
];
|
|
317
|
+
|
|
318
|
+
// ── 十二长生、各柱空亡、神煞 ──────────────────────────────
|
|
319
|
+
const CHANGSHENG = ['长生', '沐浴', '冠带', '临官', '帝旺', '衰', '病', '死', '墓', '绝', '胎', '养'];
|
|
320
|
+
const CS_START = { 甲: 11, 乙: 6, 丙: 2, 丁: 9, 戊: 2, 己: 9, 庚: 5, 辛: 0, 壬: 8, 癸: 3 };
|
|
321
|
+
const isYang = (s) => STEMS.indexOf(s) % 2 === 0;
|
|
322
|
+
|
|
323
|
+
function changsheng(stem, branch) {
|
|
324
|
+
const start = CS_START[stem];
|
|
325
|
+
const bi = BRANCHES.indexOf(branch);
|
|
326
|
+
const step = isYang(stem) ? bi - start : start - bi;
|
|
327
|
+
return CHANGSHENG[((step % 12) + 12) % 12];
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// 旬空统一走 calendar.xunKongOf:此前 bazi / liuyao / daliuren 各写一份公式,
|
|
331
|
+
// 三份形式不同(一处用 (start+10)%12、一处用 (10-2k)%12、一处查表),改一处极易漏改另两处。
|
|
332
|
+
const monthBranch = pillars.month.branch;
|
|
333
|
+
|
|
334
|
+
// 神煞:表驱动、双查法(年干/日干、年支/日支、月支、日柱、时柱),详见 engine/shensha.js
|
|
335
|
+
const shensha = computeBaziShensha(pillars, kongwang);
|
|
336
|
+
|
|
337
|
+
for (const key of ['year', 'month', 'day', 'hour']) {
|
|
338
|
+
const pl = pillars[key];
|
|
339
|
+
pl.dishi = changsheng(dayStem, pl.branch);
|
|
340
|
+
pl.zizuo = changsheng(pl.stem, pl.branch);
|
|
341
|
+
pl.kongwang = xunKongOf(pl.ganzhi);
|
|
342
|
+
// shensha 保持字符串数组以兼容既有 UI / 测试;明细见 shenshaDetail
|
|
343
|
+
pl.shensha = shensha.detail[key].map((x) => x.name);
|
|
344
|
+
pl.shenshaDetail = shensha.detail[key];
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// ── 日主旺衰(月令 + 通根 + 天干帮扶,量化但规则透明)──
|
|
348
|
+
const SEASON_EL = { 寅: '木', 卯: '木', 巳: '火', 午: '火', 申: '金', 酉: '金', 亥: '水', 子: '水', 辰: '土', 戌: '土', 丑: '土', 未: '土' };
|
|
349
|
+
const me = STEM_ELEMENT[dayStem];
|
|
350
|
+
const seasonEl = SEASON_EL[monthBranch];
|
|
351
|
+
let monthW;
|
|
352
|
+
let monthWord;
|
|
353
|
+
if (me === seasonEl) { monthW = 3; monthWord = '旺'; }
|
|
354
|
+
else if (GENERATES[seasonEl] === me) { monthW = 2; monthWord = '相'; }
|
|
355
|
+
else if (GENERATES[me] === seasonEl) { monthW = 1; monthWord = '休'; }
|
|
356
|
+
else if (OVERCOMES[me] === seasonEl) { monthW = 0.5; monthWord = '囚'; }
|
|
357
|
+
else { monthW = 0; monthWord = '死'; }
|
|
358
|
+
|
|
359
|
+
let rootScore = 0;
|
|
360
|
+
const rootBranches = [];
|
|
361
|
+
for (const key of ['year', 'month', 'day', 'hour']) {
|
|
362
|
+
const pl = pillars[key];
|
|
363
|
+
let hit = false;
|
|
364
|
+
pl.hidden.forEach((h, i) => {
|
|
365
|
+
if (STEM_ELEMENT[h.stem] === me) { rootScore += ROOT_HIDDEN_WEIGHT[i] ?? 0.1; hit = true; }
|
|
366
|
+
else if (GENERATES[STEM_ELEMENT[h.stem]] === me) { rootScore += (ROOT_HIDDEN_WEIGHT[i] ?? 0.1) * 0.4; hit = true; }
|
|
367
|
+
});
|
|
368
|
+
if (hit) rootBranches.push(pl.branch);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
let helpScore = 0;
|
|
372
|
+
const helpers = [];
|
|
373
|
+
const drainers = [];
|
|
374
|
+
for (const key of ['year', 'month', 'hour']) {
|
|
375
|
+
const st = pillars[key].stem;
|
|
376
|
+
const el2 = STEM_ELEMENT[st];
|
|
377
|
+
if (el2 === me) { helpScore += 1; helpers.push(st); }
|
|
378
|
+
else if (GENERATES[el2] === me) { helpScore += 0.8; helpers.push(st); }
|
|
379
|
+
else if (OVERCOMES[el2] === me) { helpScore -= 1; drainers.push(st); }
|
|
380
|
+
else if (OVERCOMES[me] === el2) { helpScore -= 0.8; drainers.push(st); }
|
|
381
|
+
else { helpScore -= 0.5; drainers.push(st); }
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const total = Math.round((monthW + rootScore + helpScore) * 10) / 10;
|
|
385
|
+
const level = total >= 4 ? '身强' : total >= 2.5 ? '偏强' : total >= 1.5 ? '中和' : total >= 0.5 ? '偏弱' : '身弱';
|
|
386
|
+
const strength = {
|
|
387
|
+
level,
|
|
388
|
+
score: total,
|
|
389
|
+
detail: `月令${monthBranch}${seasonEl},日主${me}${monthWord}(${monthW});通根${rootBranches.join('') || '无'}(${rootScore.toFixed(1)});天干帮扶${helpers.join('') || '无'}/耗泄${drainers.join('') || '无'}(${helpScore.toFixed(1)})`,
|
|
390
|
+
method: '月令权重 3/2/1/0.5/0 + 地支藏干通根 + 天干帮扶,量化后分档;属简化算法,非唯一流派',
|
|
391
|
+
parts: {
|
|
392
|
+
season: { branch: monthBranch, element: seasonEl, word: monthWord, weight: monthW },
|
|
393
|
+
roots: rootBranches,
|
|
394
|
+
rootScore: Math.round(rootScore * 10) / 10,
|
|
395
|
+
helpers,
|
|
396
|
+
drainers,
|
|
397
|
+
helpScore: Math.round(helpScore * 10) / 10,
|
|
398
|
+
},
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
// ── 格局 / 用神 / 行运 ─────────────────────────────────────
|
|
402
|
+
const frame = analyzeBaziFrame({ pillars, dayStem, monthBranch, strength, wuxing });
|
|
403
|
+
|
|
404
|
+
// ── 大运/流年与原局的地支关系 ──
|
|
405
|
+
const pairRel = (a, b) => {
|
|
406
|
+
if (!a || !b) return [];
|
|
407
|
+
// 大运/流年支与原局同支:辰午酉亥为自刑,其余同支不算关系
|
|
408
|
+
if (a === b) return XING_SELF.includes(a) ? ['自刑'] : [];
|
|
409
|
+
const out = [];
|
|
410
|
+
if (BRANCH_HE[a + b] || BRANCH_HE[b + a]) out.push('合');
|
|
411
|
+
if (hasPair(BRANCH_CHONG, a, b)) out.push('冲');
|
|
412
|
+
if (hasPair(BRANCH_HAI, a, b)) out.push('害');
|
|
413
|
+
if (hasPair(BRANCH_PO, a, b)) out.push('破');
|
|
414
|
+
for (const g of XING_GROUPS) if (g.includes(a) && g.includes(b)) out.push('刑');
|
|
415
|
+
return out;
|
|
416
|
+
};
|
|
417
|
+
const natalBranches = ['year', 'month', 'day', 'hour'].map((k) => pillars[k].branch);
|
|
418
|
+
const relOf = (branch) => {
|
|
419
|
+
const seen = new Set();
|
|
420
|
+
const out = [];
|
|
421
|
+
for (const b of natalBranches) {
|
|
422
|
+
for (const r of pairRel(b, branch)) {
|
|
423
|
+
const t = r + b;
|
|
424
|
+
if (!seen.has(t)) { seen.add(t); out.push(t); }
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return out;
|
|
428
|
+
};
|
|
429
|
+
for (const d of dayun) {
|
|
430
|
+
d.relations = relOf(d.branch);
|
|
431
|
+
d.luck = scoreLuck(d.ganzhi, frame);
|
|
432
|
+
}
|
|
433
|
+
for (const l of liunian) {
|
|
434
|
+
l.relations = relOf(l.ganzhi[1]);
|
|
435
|
+
l.luck = scoreLuck(l.ganzhi, frame);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const p = jdToParts(jd);
|
|
439
|
+
|
|
440
|
+
// ── 胎元 / 命宫 / 身宫 ──
|
|
441
|
+
// 胎元:月柱天干进一位、地支进三位(受胎之月的干支)
|
|
442
|
+
const mStemIdx = STEMS.indexOf(pillars.month.stem);
|
|
443
|
+
const mBranchIdx = BRANCHES.indexOf(pillars.month.branch);
|
|
444
|
+
const taiyuan = ganzhiName(sexagenaryIndex((mStemIdx + 1) % 10, (mBranchIdx + 3) % 12));
|
|
445
|
+
// 命宫:以子月起正月顺数至生月,再自该宫起子时逆数至生时
|
|
446
|
+
const hourBrIdxForGong = BRANCHES.indexOf(pillars.hour.branch);
|
|
447
|
+
const soulIdx = (((mBranchIdx - hourBrIdxForGong) % 12) + 12) % 12;
|
|
448
|
+
// 命宫天干按五虎遁从年干起(寅为正月)
|
|
449
|
+
const yinStem = ((STEMS.indexOf(pillars.year.stem) % 5) * 2 + 2) % 10;
|
|
450
|
+
const soulStemIdx = (yinStem + ((soulIdx - 2 + 12) % 12)) % 10;
|
|
451
|
+
const minggong = ganzhiName(sexagenaryIndex(soulStemIdx, soulIdx));
|
|
452
|
+
// 身宫:命宫对宫(相隔六位)
|
|
453
|
+
const bodyIdx = (soulIdx + 6) % 12;
|
|
454
|
+
const bodyStemIdx = (yinStem + ((bodyIdx - 2 + 12) % 12)) % 10;
|
|
455
|
+
const shengong = ganzhiName(sexagenaryIndex(bodyStemIdx, bodyIdx));
|
|
456
|
+
|
|
457
|
+
return {
|
|
458
|
+
system: 'bazi',
|
|
459
|
+
relations: buildRelations(pillars),
|
|
460
|
+
palaces: {
|
|
461
|
+
taiyuan: { ganzhi: taiyuan.name, note: '月干进一、月支进三' },
|
|
462
|
+
minggong: { ganzhi: minggong.name, branch: minggong.branch, note: '子月起正月顺数至生月,再逆数至生时;干按五虎遁' },
|
|
463
|
+
shengong: { ganzhi: shengong.name, branch: shengong.branch, note: '命宫对宫' },
|
|
464
|
+
},
|
|
465
|
+
input: {
|
|
466
|
+
civil: { year, month, day, hour, minute },
|
|
467
|
+
gender,
|
|
468
|
+
longitude: longitude ?? null,
|
|
469
|
+
address: input.address || null,
|
|
470
|
+
geo,
|
|
471
|
+
lateZi,
|
|
472
|
+
trueSolar: useTrueSolar,
|
|
473
|
+
},
|
|
474
|
+
solarTime: {
|
|
475
|
+
civilText: `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')} ${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}`,
|
|
476
|
+
trueSolarText: formatJd(jd),
|
|
477
|
+
offsetMinutes: solar.offsetMinutes,
|
|
478
|
+
note: solar.note,
|
|
479
|
+
lunarYearForPillar: solarYear,
|
|
480
|
+
},
|
|
481
|
+
jieqi: {
|
|
482
|
+
previous: { name: prevJieTerm.name, time: formatJd(prevJieTerm.jd) },
|
|
483
|
+
next: { name: nextJieTerm.name, time: formatJd(nextJieTerm.jd) },
|
|
484
|
+
// 距「节」的分钟数(取两侧较小值)。是否提示复核由摘要层决定,阈值 20 分钟:
|
|
485
|
+
// 与 NAOJ 历要项对拍实测节气最多偏 13.5 分钟,20 分钟留出余量。
|
|
486
|
+
nearBoundaryMinutes: Math.round(Math.min(jd - prevJieTerm.jd, nextJieTerm.jd - jd) * 1440),
|
|
487
|
+
},
|
|
488
|
+
pillars,
|
|
489
|
+
dayMaster: { stem: dayStem, element: STEM_ELEMENT[dayStem], yinYang: isYangStem(dayStem) ? '阳' : '阴' },
|
|
490
|
+
wuxing,
|
|
491
|
+
kongwang,
|
|
492
|
+
shensha,
|
|
493
|
+
dayun: {
|
|
494
|
+
direction: forward ? '顺行' : '逆行',
|
|
495
|
+
rule: `${isYangYear ? '阳' : '阴'}年${gender === 'male' ? '男' : '女'}${forward ? '顺排' : '逆排'}`,
|
|
496
|
+
startAge: { years: startAgeYears, months: startAgeMonths },
|
|
497
|
+
toNextJieDays: Math.round(spanDays * 100) / 100,
|
|
498
|
+
list: dayun,
|
|
499
|
+
},
|
|
500
|
+
strength,
|
|
501
|
+
frame,
|
|
502
|
+
liunian,
|
|
503
|
+
liunianFrom: thisYear,
|
|
504
|
+
};
|
|
505
|
+
}
|