From 19ac8dd54a9940fb7a9d5477a69eec393286dae6 Mon Sep 17 00:00:00 2001 From: 6tail <6tail@6tail.cn> Date: Sun, 19 Apr 2020 22:55:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B9=B2=E6=94=AF=E7=BA=AA?= =?UTF-8?q?=E5=B9=B4=E5=92=8C=E7=BA=AA=E6=9C=88=E7=9A=84=E4=B8=A5=E9=87=8D?= =?UTF-8?q?=E9=94=99=E8=AF=AF=EF=BC=9B=E8=8A=82=E6=B0=94=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=88=B0=E7=A7=92=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +- README_EN.md | 2 +- src/main/java/com/nlf/calendar/Lunar.java | 662 ++++++++++++++---- src/main/java/com/nlf/calendar/Solar.java | 181 +++-- .../java/com/nlf/calendar/util/LunarUtil.java | 12 +- src/test/java/sample/BaZiTest.java | 61 ++ src/test/java/test/GanZhiTest.java | 199 ++++++ src/test/java/test/LunarTest.java | 4 +- src/test/java/test/SolarTest.java | 2 +- src/test/java/test/TimeTest.java | 4 +- 10 files changed, 943 insertions(+), 190 deletions(-) create mode 100644 src/test/java/sample/BaZiTest.java create mode 100644 src/test/java/test/GanZhiTest.java diff --git a/README.md b/README.md index b0ebac2..aebf0b8 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # lunar [![License](https://img.shields.io/badge/license-MIT-4EB1BA.svg?style=flat-square)](https://github.com/6tail/lunar-java/blob/master/LICENSE) -lunar是一款无第三方依赖的公历(阳历)和农历(阴历、老黄历)工具,支持星座、干支、生肖、节气、节日、彭祖百忌、吉神(喜神/福神/财神/阳贵神/阴贵神)方位、胎神方位、冲煞、纳音、星宿、八字、五行、十神、建除十二值星、青龙名堂等十二神、黄道黑道日及吉凶等。 +lunar是一款无第三方依赖的公历(阳历)和农历(阴历、老黄历)工具,支持星座、儒略日、干支、生肖、节气、节日、彭祖百忌、吉神(喜神/福神/财神/阳贵神/阴贵神)方位、胎神方位、冲煞、纳音、星宿、八字、五行、十神、建除十二值星、青龙名堂等十二神、黄道黑道日及吉凶等。 > 支持java 1.5及以上版本。 +> 干支纪年:支持以正月初一计,支持以立春当日计,支持以立春交接时刻计。 +> 干支纪月:支持以节当日计,支持以节交接时刻计。 [English](https://github.com/6tail/lunar-java/blob/master/README_EN.md) @@ -59,7 +61,7 @@ lunar是一款无第三方依赖的公历(阳历)和农历(阴历、老黄历) 输出结果: 壹玖捌陆年肆月廿一 丙寅(虎)年 癸巳(蛇)月 癸酉(鸡)日 子(鼠)时 纳音[炉中火 长流水 剑锋金 海中金] 星期四 北方玄武 星宿[斗木獬](吉) 彭祖百忌[癸不词讼理弱敌强 酉不会客醉坐颠狂] 喜神方位[巽](东南) 阳贵神方位[巽](东南) 阴贵神方位[震](正东) 福神方位[兑](正西) 财神方位[离](正南) 冲[(丁卯)兔] 煞[东] - 1986-05-29 00:00 星期四 双子座 + 1986-05-29 00:00:00 星期四 双子座 ## 文档 diff --git a/README_EN.md b/README_EN.md index 0e7ae04..011f23b 100644 --- a/README_EN.md +++ b/README_EN.md @@ -58,7 +58,7 @@ If you will use jars in your projects, I suggest you to download latest snapshot Output: 壹玖捌陆年肆月廿一 丙寅(虎)年 癸巳(蛇)月 癸酉(鸡)日 子(鼠)时 纳音[炉中火 长流水 剑锋金 海中金] 星期四 北方玄武 星宿[斗木獬](吉) 彭祖百忌[癸不词讼理弱敌强 酉不会客醉坐颠狂] 喜神方位[巽](东南) 阳贵神方位[巽](东南) 阴贵神方位[震](正东) 福神方位[兑](正西) 财神方位[离](正南) 冲[(丁卯)兔] 煞[东] - 1986-05-29 00:00 星期四 双子座 + 1986-05-29 00:00:00 星期四 双子座 ## Documentation diff --git a/src/main/java/com/nlf/calendar/Lunar.java b/src/main/java/com/nlf/calendar/Lunar.java index e0bf504..5f4d5ac 100644 --- a/src/main/java/com/nlf/calendar/Lunar.java +++ b/src/main/java/com/nlf/calendar/Lunar.java @@ -1,9 +1,7 @@ package com.nlf.calendar; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; +import java.util.*; + import com.nlf.calendar.util.LunarUtil; import com.nlf.calendar.util.SolarUtil; @@ -14,6 +12,36 @@ import com.nlf.calendar.util.SolarUtil; * */ public class Lunar{ + /** 1角度对应的弧度 */ + private static final double RAD_PER_DEGREE = Math.PI / 180; + /** 1弧度对应的角度 */ + private static final double DEGREE_PER_RAD = 180 / Math.PI; + /** 1弧度对应的角秒 */ + private static final double SECOND_PER_RAD = 180 * 3600 / Math.PI; + /** 节气表,国标以冬至为首个节气 */ + private static final String[] JIE_QI = {"冬至","小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪"}; + /** 黄经周期项 */ + private static final double[] E10 = {1.75347045673, 0.00000000000, 0.0000000000, 0.03341656456, 4.66925680417, 6283.0758499914, 0.00034894275, 4.62610241759, 12566.1516999828, 0.00003417571, 2.82886579606, 3.5231183490, 0.00003497056, 2.74411800971, 5753.3848848968, 0.00003135896, 3.62767041758, 77713.7714681205, 0.00002676218, 4.41808351397, 7860.4193924392, 0.00002342687, 6.13516237631, 3930.2096962196, 0.00001273166, 2.03709655772, 529.6909650946, 0.00001324292, 0.74246356352, 11506.7697697936, 0.00000901855, 2.04505443513, 26.2983197998, 0.00001199167, 1.10962944315, 1577.3435424478, 0.00000857223, 3.50849156957, 398.1490034082, 0.00000779786, 1.17882652114, 5223.6939198022, 0.00000990250, 5.23268129594, 5884.9268465832, 0.00000753141, 2.53339053818, 5507.5532386674, 0.00000505264, 4.58292563052, 18849.2275499742, 0.00000492379, 4.20506639861, 775.5226113240, 0.00000356655, 2.91954116867, 0.0673103028, 0.00000284125, 1.89869034186, 796.2980068164, 0.00000242810, 0.34481140906, 5486.7778431750, 0.00000317087, 5.84901952218, 11790.6290886588, 0.00000271039, 0.31488607649, 10977.0788046990, 0.00000206160, 4.80646606059, 2544.3144198834, 0.00000205385, 1.86947813692, 5573.1428014331, 0.00000202261, 2.45767795458, 6069.7767545534, 0.00000126184, 1.08302630210, 20.7753954924, 0.00000155516, 0.83306073807, 213.2990954380, 0.00000115132, 0.64544911683, 0.9803210682, 0.00000102851, 0.63599846727, 4694.0029547076, 0.00000101724, 4.26679821365, 7.1135470008, 0.00000099206, 6.20992940258, 2146.1654164752, 0.00000132212, 3.41118275555, 2942.4634232916, 0.00000097607, 0.68101272270, 155.4203994342, 0.00000085128, 1.29870743025, 6275.9623029906, 0.00000074651, 1.75508916159, 5088.6288397668, 0.00000101895, 0.97569221824, 15720.8387848784, 0.00000084711, 3.67080093025, 71430.6956181291, 0.00000073547, 4.67926565481, 801.8209311238, 0.00000073874, 3.50319443167, 3154.6870848956, 0.00000078756, 3.03698313141, 12036.4607348882, 0.00000079637, 1.80791330700, 17260.1546546904, 0.00000085803, 5.98322631256, 161000.6857376741, 0.00000056963, 2.78430398043, 6286.5989683404, 0.00000061148, 1.81839811024, 7084.8967811152, 0.00000069627, 0.83297596966, 9437.7629348870, 0.00000056116, 4.38694880779, 14143.4952424306, 0.00000062449, 3.97763880587, 8827.3902698748, 0.00000051145, 0.28306864501, 5856.4776591154, 0.00000055577, 3.47006009062, 6279.5527316424, 0.00000041036, 5.36817351402, 8429.2412664666, 0.00000051605, 1.33282746983, 1748.0164130670, 0.00000051992, 0.18914945834, 12139.5535091068, 0.00000049000, 0.48735065033, 1194.4470102246, 0.00000039200, 6.16832995016, 10447.3878396044, 0.00000035566, 1.77597314691, 6812.7668150860, 0.00000036770, 6.04133859347, 10213.2855462110, 0.00000036596, 2.56955238628, 1059.3819301892, 0.00000033291, 0.59309499459, 17789.8456197850, 0.00000035954, 1.70876111898, 2352.8661537718}; + /** 黄经泊松1项 */ + private static final double[] E11 = {6283.31966747491, 0.00000000000, 0.0000000000, 0.00206058863, 2.67823455584, 6283.0758499914, 0.00004303430, 2.63512650414, 12566.1516999828, 0.00000425264, 1.59046980729, 3.5231183490, 0.00000108977, 2.96618001993, 1577.3435424478, 0.00000093478, 2.59212835365, 18849.2275499742, 0.00000119261, 5.79557487799, 26.2983197998, 0.00000072122, 1.13846158196, 529.6909650946, 0.00000067768, 1.87472304791, 398.1490034082, 0.00000067327, 4.40918235168, 5507.5532386674, 0.00000059027, 2.88797038460, 5223.6939198022, 0.00000055976, 2.17471680261, 155.4203994342, 0.00000045407, 0.39803079805, 796.2980068164, 0.00000036369, 0.46624739835, 775.5226113240, 0.00000028958, 2.64707383882, 7.1135470008, 0.00000019097, 1.84628332577, 5486.7778431750, 0.00000020844, 5.34138275149, 0.9803210682, 0.00000018508, 4.96855124577, 213.2990954380, 0.00000016233, 0.03216483047, 2544.3144198834, 0.00000017293, 2.99116864949, 6275.9623029906}; + /** 黄经泊松2项 */ + private static final double[] E12 = {0.00052918870, 0.00000000000, 0.0000000000, 0.00008719837, 1.07209665242, 6283.0758499914, 0.00000309125, 0.86728818832, 12566.1516999828, 0.00000027339, 0.05297871691, 3.5231183490, 0.00000016334, 5.18826691036, 26.2983197998, 0.00000015752, 3.68457889430, 155.4203994342, 0.00000009541, 0.75742297675, 18849.2275499742, 0.00000008937, 2.05705419118, 77713.7714681205, 0.00000006952, 0.82673305410, 775.5226113240, 0.00000005064, 4.66284525271, 1577.3435424478}; + private static final double[] E13 = {0.00000289226, 5.84384198723, 6283.0758499914, 0.00000034955, 0.00000000000, 0.0000000000, 0.00000016819, 5.48766912348, 12566.1516999828}; + private static final double[] E14 = {0.00000114084, 3.14159265359, 0.0000000000, 0.00000007717, 4.13446589358, 6283.0758499914, 0.00000000765, 3.83803776214, 12566.1516999828}; + private static final double[] E15 = {0.00000000878, 3.14159265359, 0.0000000000}; + /** 黄纬周期项 */ + private static final double[] E20 = {0.00000279620, 3.19870156017, 84334.6615813083, 0.00000101643, 5.42248619256, 5507.5532386674, 0.00000080445, 3.88013204458, 5223.6939198022, 0.00000043806, 3.70444689758, 2352.8661537718, 0.00000031933, 4.00026369781, 1577.3435424478, 0.00000022724, 3.98473831560, 1047.7473117547, 0.00000016392, 3.56456119782, 5856.4776591154, 0.00000018141, 4.98367470263, 6283.0758499914, 0.00000014443, 3.70275614914, 9437.7629348870, 0.00000014304, 3.41117857525, 10213.2855462110}; + private static final double[] E21 = {0.00000009030, 3.89729061890, 5507.5532386674, 0.00000006177, 1.73038850355, 5223.6939198022}; + /** 离心率 */ + private static final double[] GXC_E = {0.016708634, -0.000042037, -0.0000001267}; + /** 近点 */ + private static final double[] GXC_P = {102.93735 / DEGREE_PER_RAD, 1.71946 / DEGREE_PER_RAD, 0.00046 / DEGREE_PER_RAD}; + /** 太平黄经 */ + private static final double[] GXC_L = {280.4664567 / DEGREE_PER_RAD, 36000.76982779 / DEGREE_PER_RAD, 0.0003032028 / DEGREE_PER_RAD, 1 / 49931000 / DEGREE_PER_RAD, -1 / 153000000 / DEGREE_PER_RAD}; + /** 光行差常数 */ + private static final double GXC_K = 20.49552 / SECOND_PER_RAD; + /** 章动表 */ + private static final double[] ZD = {2.1824391966, -33.757045954, 0.0000362262, 3.7340E-08, -2.8793E-10, -171996, -1742, 92025, 89, 3.5069406862, 1256.663930738, 0.0000105845, 6.9813E-10, -2.2815E-10, -13187, -16, 5736, -31, 1.3375032491, 16799.418221925, -0.0000511866, 6.4626E-08, -5.3543E-10, -2274, -2, 977, -5, 4.3648783932, -67.514091907, 0.0000724525, 7.4681E-08, -5.7586E-10, 2062, 2, -895, 5, 0.0431251803, -628.301955171, 0.0000026820, 6.5935E-10, 5.5705E-11, -1426, 34, 54, -1, 2.3555557435, 8328.691425719, 0.0001545547, 2.5033E-07, -1.1863E-09, 712, 1, -7, 0, 3.4638155059, 1884.965885909, 0.0000079025, 3.8785E-11, -2.8386E-10, -517, 12, 224, -6, 5.4382493597, 16833.175267879, -0.0000874129, 2.7285E-08, -2.4750E-10, -386, -4, 200, 0, 3.6930589926, 25128.109647645, 0.0001033681, 3.1496E-07, -1.7218E-09, -301, 0, 129, -1, 3.5500658664, 628.361975567, 0.0000132664, 1.3575E-09, -1.7245E-10, 217, -5, -95, 3}; /** 农历年 */ private int year; /** 农历月,闰月为负,即闰2月=-2 */ @@ -32,20 +60,37 @@ public class Lunar{ private int dayGanIndex; /** 日对应的地支下标,0-11 */ private int dayZhiIndex; - /** 月对应的天干下标,0-9 */ + /** 月对应的天干下标(以节交接当天起算),0-9 */ private int monthGanIndex; - /** 月对应的地支下标,0-11 */ + /** 月对应的地支下标(以节交接当天起算),0-11 */ private int monthZhiIndex; - /** 年对应的天干下标,0-9 */ + /** 月对应的天干下标(最精确的,供八字用,以节交接时刻起算),0-9 */ + private int monthGanIndexExact; + /** 月对应的地支下标(最精确的,供八字用,以节交接时刻起算),0-11 */ + private int monthZhiIndexExact; + /** 年对应的天干下标(国标,以正月初一为起点),0-9 */ private int yearGanIndex; - /** 年对应的地支下标,0-11 */ + /** 年对应的地支下标(国标,以正月初一为起点),0-11 */ private int yearZhiIndex; + /** 年对应的天干下标(月干计算用,以立春为起点),0-9 */ + private int yearGanIndexByLiChun; + /** 年对应的地支下标(月支计算用,以立春为起点),0-11 */ + private int yearZhiIndexByLiChun; + /** 年对应的天干下标(最精确的,供八字用,以立春交接时刻为起点),0-9 */ + private int yearGanIndexExact; + /** 年对应的地支下标(最精确的,供八字用,以立春交接时刻为起点),0-11 */ + private int yearZhiIndexExact; + /** 周下标,0-6 */ private int weekIndex; /** 阳历小时 */ private int hour; /** 阳历分钟 */ private int minute; + /** 阳历秒钟 */ + private int second; + /** 24节气表(对应阳历的准确时刻) */ + private Map jieQi = new LinkedHashMap(); /** * 默认使用当前日期初始化 @@ -62,7 +107,7 @@ public class Lunar{ * @param lunarDay 日(农历),1到31 */ public Lunar(int lunarYear,int lunarMonth,int lunarDay){ - this(lunarYear,lunarMonth,lunarDay,0,0); + this(lunarYear,lunarMonth,lunarDay,0,0,0); } /** @@ -73,15 +118,18 @@ public class Lunar{ * @param lunarDay 日(农历),1到31 * @param hour 小时(阳历) * @param minute 分钟(阳历) + * @param second 秒钟(阳历) */ - public Lunar(int lunarYear,int lunarMonth,int lunarDay,int hour,int minute){ + public Lunar(int lunarYear,int lunarMonth,int lunarDay,int hour,int minute,int second){ this.year = lunarYear; this.month = lunarMonth; this.day = lunarDay; this.hour = hour; this.minute = minute; - compute(); + this.second = second; + dayOffset = LunarUtil.computeAddDays(year,month,day); this.solar = toSolar(); + compute(); } /** @@ -136,32 +184,155 @@ public class Lunar{ day = lunarDay; hour = solar.getHour(); minute = solar.getMinute(); + second = solar.getSecond(); + dayOffset = LunarUtil.computeAddDays(year,month,day); compute(); } - private void compute(){ - yearGanIndex = (year-4)%10; - yearZhiIndex = (year-4)%12; - - int m = Math.abs(month); - int leapMonth = LunarUtil.getLeapMonth(year); - if(0==leapMonth||m=0&&ymd.compareTo(eymd)<0){ + break; + } + start = end; + index++; + } + if(index<0){ + index += 12; + } + + monthGanIndex = (index+gOffset)%10; + monthZhiIndex = (index+LunarUtil.BASE_MONTH_ZHI_INDEX)%12; + + //序号:大雪到小寒之间-2,小寒到立春之间-1,立春之后0 + int indexExact = -2; + for(String jie:LunarUtil.JIE){ + end = jieQi.get(jie); + String time = solar.toYmdhms(); + String stime = null==start?time:start.toYmdhms(); + String etime = end.toYmdhms(); + if(time.compareTo(stime)>=0&&time.compareTo(etime)<0){ + break; + } + start = end; + indexExact++; + } + if(indexExact<0){ + indexExact += 12; + } + monthGanIndexExact = (indexExact+gOffsetExact)%10; + monthZhiIndexExact = (indexExact+LunarUtil.BASE_MONTH_ZHI_INDEX)%12; + } + + /** + * 干支纪日计算 + */ + private void computeDay(){ int addDays = (dayOffset + LunarUtil.BASE_DAY_GANZHI_INDEX)%60; dayGanIndex = addDays%10; dayZhiIndex = addDays%12; + } + /** + * 干支纪时计算 + */ + private void computeTime(){ timeZhiIndex = LunarUtil.getTimeZhiIndex((hour<10?"0":"")+hour+":"+(minute<10?"0":"")+minute); timeGanIndex = timeZhiIndex%10; + } + /** + * 星期计算 + */ + private void computeWeek(){ weekIndex = (dayOffset+LunarUtil.BASE_WEEK_INDEX)%7; } + private void compute(){ + computeJieQi(); + computeYear(); + computeMonth(); + computeDay(); + computeTime(); + computeWeek(); + } + /** * 通过指定阳历日期获取农历 * @@ -192,14 +363,15 @@ public class Lunar{ * @param lunarDay 日(农历),1到31 * @param hour 小时(阳历) * @param minute 分钟(阳历) + * @param second 秒钟(阳历) * @return 农历 */ - public static Lunar fromYmdHm(int lunarYear,int lunarMonth,int lunarDay,int hour,int minute){ - return new Lunar(lunarYear,lunarMonth,lunarDay,hour,minute); + public static Lunar fromYmdHms(int lunarYear,int lunarMonth,int lunarDay,int hour,int minute,int second){ + return new Lunar(lunarYear,lunarMonth,lunarDay,hour,minute,second); } /** - * 获取年份的天干 + * 获取年份的天干(以正月初一作为新年的开始) * * @return 天干,如辛 * @deprecated 使用getYearGan @@ -209,7 +381,7 @@ public class Lunar{ } /** - * 获取年份的天干 + * 获取年份的天干(以正月初一作为新年的开始) * * @return 天干,如辛 */ @@ -218,7 +390,25 @@ public class Lunar{ } /** - * 获取年份的地支 + * 获取年份的天干(以立春当天作为新年的开始) + * + * @return 天干,如辛 + */ + public String getYearGanByLiChun(){ + return LunarUtil.GAN[yearGanIndexByLiChun+1]; + } + + /** + * 获取最精确的年份天干(以立春交接的时刻作为新年的开始) + * + * @return 天干,如辛 + */ + public String getYearGanExact(){ + return LunarUtil.GAN[yearGanIndexExact+1]; + } + + /** + * 获取年份的地支(以正月初一作为新年的开始) * * @return 地支,如亥 * @deprecated 使用getYearZhi @@ -228,7 +418,7 @@ public class Lunar{ } /** - * 获取年份的地支 + * 获取年份的地支(以正月初一作为新年的开始) * * @return 地支,如亥 */ @@ -237,13 +427,128 @@ public class Lunar{ } /** - * 获取干支纪年(年柱) + * 获取年份的地支(以立春当天作为新年的开始) + * + * @return 地支,如亥 + */ + public String getYearZhiByLiChun(){ + return LunarUtil.ZHI[yearZhiIndexByLiChun+1]; + } + + /** + * 获取最精确的年份地支(以立春交接的时刻作为新年的开始) + * + * @return 地支,如亥 + */ + public String getYearZhiExact(){ + return LunarUtil.ZHI[yearZhiIndexExact+1]; + } + + /** + * 获取干支纪年(年柱)(以正月初一作为新年的开始) * @return 年份的干支(年柱),如辛亥 */ public String getYearInGanZhi(){ return getYearGan()+getYearZhi(); } + /** + * 获取干支纪年(年柱)(以立春当天作为新年的开始) + * @return 年份的干支(年柱),如辛亥 + */ + public String getYearInGanZhiByLiChun(){ + return getYearGanByLiChun()+getYearZhiByLiChun(); + } + + /** + * 获取干支纪年(年柱)(以立春交接的时刻作为新年的开始) + * @return 年份的干支(年柱),如辛亥 + */ + public String getYearInGanZhiExact(){ + return getYearGanExact()+getYearZhiExact(); + } + + /** + * 获取干支纪月(月柱)(以节交接当天起算) + *

月天干口诀:甲己丙寅首,乙庚戊寅头。丙辛从庚寅,丁壬壬寅求,戊癸甲寅居,周而复始流。

+ *

月地支:正月起寅

+ * + * @return 干支纪月(月柱),如己卯 + */ + public String getMonthInGanZhi(){ + return getMonthGan()+getMonthZhi(); + } + + /** + * 获取精确的干支纪月(月柱)(以节交接时刻起算) + *

月天干口诀:甲己丙寅首,乙庚戊寅头。丙辛从庚寅,丁壬壬寅求,戊癸甲寅居,周而复始流。

+ *

月地支:正月起寅

+ * + * @return 干支纪月(月柱),如己卯 + */ + public String getMonthInGanZhiExact(){ + return getMonthGanExact()+getMonthZhiExact(); + } + + /** + * 获取月天干(以节交接当天起算) + * @return 月天干,如己 + */ + public String getMonthGan(){ + return LunarUtil.GAN[monthGanIndex+1]; + } + + /** + * 获取精确的月天干(以节交接时刻起算) + * @return 月天干,如己 + */ + public String getMonthGanExact(){ + return LunarUtil.GAN[monthGanIndexExact+1]; + } + + /** + * 获取月地支(以节交接当天起算) + * @return 月地支,如卯 + */ + public String getMonthZhi(){ + return LunarUtil.ZHI[monthZhiIndex+1]; + } + + /** + * 获取精确的月地支(以节交接时刻起算) + * @return 月地支,如卯 + */ + public String getMonthZhiExact(){ + return LunarUtil.ZHI[monthZhiIndexExact+1]; + } + + /** + * 获取干支纪日(日柱) + * + * @return 干支纪日(日柱),如己卯 + */ + public String getDayInGanZhi(){ + return getDayGan()+getDayZhi(); + } + + /** + * 获取日天干 + * + * @return 日天干,如甲 + */ + public String getDayGan(){ + return LunarUtil.GAN[dayGanIndex+1]; + } + + /** + * 获取日地支 + * + * @return 日地支,如卯 + */ + public String getDayZhi(){ + return LunarUtil.ZHI[dayZhiIndex+1]; + } + /** * 获取年生肖 * @@ -255,7 +560,7 @@ public class Lunar{ } /** - * 获取年生肖 + * 获取年生肖(以正月初一起算) * * @return 年生肖,如虎 */ @@ -263,6 +568,24 @@ public class Lunar{ return LunarUtil.SHENGXIAO[yearZhiIndex+1]; } + /** + * 获取年生肖(以立春当天起算) + * + * @return 年生肖,如虎 + */ + public String getYearShengXiaoByLiChun(){ + return LunarUtil.SHENGXIAO[yearZhiIndexByLiChun+1]; + } + + /** + * 获取精确的年生肖(以立春交接时刻起算) + * + * @return 年生肖,如虎 + */ + public String getYearShengXiaoExact(){ + return LunarUtil.SHENGXIAO[yearZhiIndexExact+1]; + } + /** * 获取月生肖 * @@ -354,35 +677,148 @@ public class Lunar{ return LunarUtil.SEASON[Math.abs(month)]; } + private double mrad(double rad) { + double pi2 = 2 * Math.PI; + rad = rad % pi2; + return rad<0?rad+pi2:rad; + } + + private void gxc(double t, double[] pos) { + double t1 = t / 36525; + double t2 = t1 * t1; + double t3 = t2 * t1; + double t4 = t3 * t1; + double l = GXC_L[0] + GXC_L[1] * t1 + GXC_L[2] * t2 + GXC_L[3] * t3 + GXC_L[4] * t4; + double p = GXC_P[0] + GXC_P[1] * t1 + GXC_P[2] * t2; + double e = GXC_E[0] + GXC_E[1] * t1 + GXC_E[2] * t2; + double dl = l - pos[0], dp = p - pos[0]; + pos[0] -= GXC_K * (Math.cos(dl) - e * Math.cos(dp)) / Math.cos(pos[1]); + pos[1] -= GXC_K * Math.sin(pos[1]) * (Math.sin(dl) - e * Math.sin(dp)); + pos[0] = mrad(pos[0]); + } + + private double enn(double[] f,double ennt) { + double v = 0; + for(int i=0,j=f.length;i 1e-15) { + k = k2; + } + t = t1 - v1 / k; + // 直线逼近法求根(直线方程的根) + v = calRad(t, rad); + // 一次逼近后,v1就已接近0,如果很大,则应减1周 + if (v > 1) { + v -= 2 * Math.PI; + } + // 已达精度 + if (Math.abs(v) < 1e-8) { + break; + } + t1 = t2; + v1 = v2; + t2 = t; + // 下一次截弦 + v2 = v; + } + return t; + } + /** * 获取节 * * @return 节 */ public String getJie(){ - String s = ""; - int solarYear = solar.getYear(); - int solarMonth = solar.getMonth(); - int solarDay = solar.getDay(); - int index = 0; - int ry = solarYear-SolarUtil.BASE_YEAR+1; - while(ry>=LunarUtil.JIE_YEAR[solarMonth-1][index]){ - index++; + for(String jie:LunarUtil.JIE){ + Solar d = jieQi.get(jie); + if(d.getYear()==solar.getYear()&&d.getMonth()==solar.getMonth()&&d.getDay()==solar.getDay()){ + return jie; + } } - int term = LunarUtil.JIE_MAP[solarMonth-1][4*index+ry%4]; - if(ry==121&&solarMonth==4){ - term = 5; - } - if(ry==132&&solarMonth==4){ - term = 5; - } - if(ry==194&&solarMonth==6){ - term = 6; - } - if(solarDay==term){ - s = LunarUtil.JIE[solarMonth-1]; - } - return s; + return ""; } /** @@ -391,26 +827,13 @@ public class Lunar{ * @return 气 */ public String getQi(){ - String s = ""; - int solarYear = solar.getYear(); - int solarMonth = solar.getMonth(); - int solarDay = solar.getDay(); - int index = 0; - int ry = solarYear-SolarUtil.BASE_YEAR+1; - while(ry>=LunarUtil.QI_YEAR[solarMonth-1][index]){ - index++; + for(String qi:LunarUtil.QI){ + Solar d = jieQi.get(qi); + if(d.getYear()==solar.getYear()&&d.getMonth()==solar.getMonth()&&d.getDay()==solar.getDay()){ + return qi; + } } - int term = LunarUtil.QI_MAP[solarMonth-1][4*index+ry%4]; - if(ry==171&&solarMonth==3){ - term = 21; - } - if(ry==181&&solarMonth==5){ - term = 21; - } - if(solarDay==term){ - s = LunarUtil.QI[solarMonth-1]; - } - return s; + return ""; } /** @@ -526,65 +949,11 @@ public class Lunar{ */ private Solar toSolar(){ Calendar c = Calendar.getInstance(); - c.set(SolarUtil.BASE_YEAR,SolarUtil.BASE_MONTH-1,SolarUtil.BASE_DAY,hour,minute); + c.set(SolarUtil.BASE_YEAR,SolarUtil.BASE_MONTH-1,SolarUtil.BASE_DAY,hour,minute,second); c.add(Calendar.DATE,dayOffset); return new Solar(c); } - /** - * 获取干支纪月(月柱) - *

月天干口诀:甲己丙寅首,乙庚戊寅头。丙辛从庚寅,丁壬壬寅求,戊癸甲寅居,周而复始流。

- *

月地支:正月起寅

- * - * @return 干支纪月(月柱),如己卯 - */ - public String getMonthInGanZhi(){ - return getMonthGan()+getMonthZhi(); - } - - /** - * 获取月天干 - * @return 月天干,如己 - */ - public String getMonthGan(){ - return LunarUtil.GAN[monthGanIndex+1]; - } - - /** - * 获取月地支 - * @return 月地支,如卯 - */ - public String getMonthZhi(){ - return LunarUtil.ZHI[monthZhiIndex+1]; - } - - /** - * 获取干支纪日(日柱) - * - * @return 干支纪日(日柱),如己卯 - */ - public String getDayInGanZhi(){ - return getDayGan()+getDayZhi(); - } - - /** - * 获取日天干 - * - * @return 日天干,如甲 - */ - public String getDayGan(){ - return LunarUtil.GAN[dayGanIndex+1]; - } - - /** - * 获取日地支 - * - * @return 日地支,如卯 - */ - public String getDayZhi(){ - return LunarUtil.ZHI[dayZhiIndex+1]; - } - /** * 获取彭祖百忌天干 * @return 彭祖百忌天干 @@ -768,14 +1137,14 @@ public class Lunar{ } /** - * 获取八字,男性也称乾造,女性也称坤造 + * 获取八字,男性也称乾造,女性也称坤造(以立春交接时刻作为新年的开始) * @return 八字(男性也称乾造,女性也称坤造) */ public List getBaZi(){ List l = new ArrayList(4); String timeGan = LunarUtil.GAN[(dayGanIndex%5*12+timeZhiIndex)%10+1]; - l.add(getYearInGanZhi()); - l.add(getMonthInGanZhi()); + l.add(getYearInGanZhiExact()); + l.add(getMonthInGanZhiExact()); l.add(getDayInGanZhi()); l.add(timeGan+getTimeZhi()); return l; @@ -903,6 +1272,14 @@ public class Lunar{ return LunarUtil.POSITION_TAI_MONTH[month-1]; } + /** + * 获取节气表(节气名称:阳历),节气交接时刻精确到秒,以冬至开头,按先后顺序排列 + * @return 节气表 + */ + public Map getJieQiTable(){ + return jieQi; + } + public String toFullString(){ StringBuilder s = new StringBuilder(); s.append(toString()); @@ -1022,6 +1399,33 @@ public class Lunar{ return day; } + /** + * 获取小时 + * + * @return 0到23之间的数字 + */ + public int getHour(){ + return hour; + } + + /** + * 获取分钟 + * + * @return 0到59之间的数字 + */ + public int getMinute(){ + return minute; + } + + /** + * 获取秒钟 + * + * @return 0到59之间的数字 + */ + public int getSecond(){ + return second; + } + public Solar getSolar(){ return solar; } diff --git a/src/main/java/com/nlf/calendar/Solar.java b/src/main/java/com/nlf/calendar/Solar.java index 7fa07f2..fd87d4e 100644 --- a/src/main/java/com/nlf/calendar/Solar.java +++ b/src/main/java/com/nlf/calendar/Solar.java @@ -13,6 +13,8 @@ import com.nlf.calendar.util.SolarUtil; * */ public class Solar{ + /** 2000年儒略日数(2000-1-1 12:00:00 UTC) */ + public static final double J2000 = 2451545; /** 年 */ private int year; /** 月 */ @@ -23,6 +25,8 @@ public class Solar{ private int hour; /** 分 */ private int minute; + /** 秒 */ + private int second; /** 日历 */ private Calendar calendar; @@ -41,15 +45,7 @@ public class Solar{ * @param day 日,1到31 */ public Solar(int year,int month,int day){ - calendar = Calendar.getInstance(); - calendar.set(year,month-1,day); - calendar.set(Calendar.HOUR_OF_DAY,0); - calendar.set(Calendar.MINUTE,0); - this.year = year; - this.month = month; - this.day = day; - this.hour = 0; - this.minute = 0; + this(year,month,day,0,0,0); } /** @@ -60,15 +56,17 @@ public class Solar{ * @param day 日,1到31 * @param hour 小时,0到23 * @param minute 分钟,0到59 + * @param second 秒钟,0到59 */ - public Solar(int year,int month,int day,int hour,int minute){ + public Solar(int year,int month,int day,int hour,int minute,int second){ calendar = Calendar.getInstance(); - calendar.set(year,month-1,day,hour,minute); + calendar.set(year,month-1,day,hour,minute,second); this.year = year; this.month = month; this.day = day; this.hour = hour; this.minute = minute; + this.second = second; } /** @@ -84,6 +82,7 @@ public class Solar{ day = calendar.get(Calendar.DATE); hour = calendar.get(Calendar.HOUR_OF_DAY); minute = calendar.get(Calendar.MINUTE); + second = calendar.get(Calendar.SECOND); } /** @@ -98,6 +97,63 @@ public class Solar{ day = calendar.get(Calendar.DATE); hour = calendar.get(Calendar.HOUR_OF_DAY); minute = calendar.get(Calendar.MINUTE); + second = calendar.get(Calendar.SECOND); + } + + /** + * 通过儒略日初始化 + * @param julianDay 儒略日 + */ + public Solar(double julianDay){ + julianDay += 0.5; + + // 日数的整数部份 + double a = int2(julianDay); + // 日数的小数部分 + double f = julianDay - a; + double D; + + if (a > 2299161) { + D = int2((a - 1867216.25) / 36524.25); + a += 1 + D - int2(D / 4); + } + // 向前移4年零2个月 + a += 1524; + double y = int2((a - 122.1) / 365.25); + // 去除整年日数后余下日数 + D = a - int2(365.25 * y); + double m = (int)int2(D / 30.6001); + // 去除整月日数后余下日数 + double d = (int)int2(D - int2(m * 30.6001)); + y -= 4716; + m--; + if (m > 12) { + m -= 12; + } + if (m <= 2) { + y++; + } + + // 日的小数转为时分秒 + f *= 24; + double h = (int)int2(f); + + f -= h; + f *= 60; + double mi = int2(f); + + f -= mi; + f *= 60; + double s = int2(f); + + calendar = Calendar.getInstance(); + calendar.set((int)y,(int)m-1,(int)d,(int)h,(int)mi,(int)s); + year = calendar.get(Calendar.YEAR); + month = calendar.get(Calendar.MONTH)+1; + day = calendar.get(Calendar.DATE); + hour = calendar.get(Calendar.HOUR_OF_DAY); + minute = calendar.get(Calendar.MINUTE); + second = calendar.get(Calendar.SECOND); } /** @@ -120,6 +176,16 @@ public class Solar{ return new Solar(calendar); } + /** + * 通过指定儒略日获取阳历 + * + * @param julianDay 儒略日 + * @return 阳历 + */ + public static Solar fromJulianDay(double julianDay){ + return new Solar(julianDay); + } + /** * 通过指定年月日获取阳历 * @@ -140,10 +206,11 @@ public class Solar{ * @param day 日,1到31 * @param hour 小时,0到23 * @param minute 分钟,0到59 + * @param second 秒钟,0到59 * @return 阳历 */ - public static Solar fromYmdHm(int year,int month,int day,int hour,int minute){ - return new Solar(year,month,day,hour,minute); + public static Solar fromYmdHms(int year,int month,int day,int hour,int minute,int second){ + return new Solar(year,month,day,hour,minute,second); } /** @@ -222,32 +289,7 @@ public class Solar{ * @deprecated 使用getXingZuo */ public String getXingzuo(){ - int index = 11,m = month,d = day; - int y = m*100+d; - if(y>=321&&y<=419){ - index = 0; - }else if(y>=420&&y<=520){ - index = 1; - }else if(y>=521&&y<=620){ - index = 2; - }else if(y>=621&&y<=722){ - index = 3; - }else if(y>=723&&y<=822){ - index = 4; - }else if(y>=823&&y<=922){ - index = 5; - }else if(y>=923&&y<=1022){ - index = 6; - }else if(y>=1023&&y<=1121){ - index = 7; - }else if(y>=1122&&y<=1221){ - index = 8; - }else if(y>=1222||y<=119){ - index = 9; - }else if(y<=218){ - index = 10; - } - return SolarUtil.XINGZUO[index]; + return getXingZuo(); } /** @@ -329,6 +371,15 @@ public class Solar{ return minute; } + /** + * 获取秒钟 + * + * @return 0到59之间的数字 + */ + public int getSecond(){ + return second; + } + /** * 获取农历 * @return 农历 @@ -337,6 +388,40 @@ public class Solar{ return new Lunar(calendar.getTime()); } + private double int2(double v){ + v = Math.floor(v); + return v<0?v+1:v; + } + + /** + * 获取儒略日 + * @return 儒略日 + */ + public double getJulianDay(){ + double y = this.year; + double m = this.month; + double n = 0; + + if (m <= 2) { + m += 12; + y--; + } + + // 判断是否为UTC日1582*372+10*31+15 + if (this.year * 372 + this.month * 31 + this.day >= 588829) { + n = int2(y / 100); + // 加百年闰 + n = 2 - n + int2(n / 4); + } + + // 加上年引起的偏移日数 + n += int2(365.2500001 * (y + 4716)); + // 加上月引起的偏移日数及日偏移数 + n += int2(30.6 * (m + 1)) + this.day; + n += ((this.second *1D / 60 + this.minute) / 60 + this.hour) / 24 - 1524.5; + return n; + } + /** * 获取日历 * @@ -348,18 +433,20 @@ public class Solar{ @Override public String toString(){ + return toYmd(); + } + + public String toYmd(){ return year+"-"+(month<10?"0":"")+month+"-"+(day<10?"0":"")+day; } + public String toYmdhms(){ + return toYmd()+" "+(hour<10?"0":"")+hour+":"+(minute<10?"0":"")+minute+":"+(second<10?"0":"")+second; + } + public String toFullString(){ StringBuilder s = new StringBuilder(); - s.append(toString()); - s.append(" "); - s.append(hour<10?"0":""); - s.append(hour); - s.append(":"); - s.append(minute<10?"0":""); - s.append(minute); + s.append(toYmdhms()); if(isLeapYear()){ s.append(" "); s.append("闰年"); @@ -390,7 +477,7 @@ public class Solar{ */ public Solar next(int days){ Calendar c = Calendar.getInstance(); - c.set(year,month-1,day,hour,minute,0); + c.set(year,month-1,day,hour,minute,second); c.add(Calendar.DATE,days); return new Solar(c); } diff --git a/src/main/java/com/nlf/calendar/util/LunarUtil.java b/src/main/java/com/nlf/calendar/util/LunarUtil.java index d86ba07..95ee3d7 100644 --- a/src/main/java/com/nlf/calendar/util/LunarUtil.java +++ b/src/main/java/com/nlf/calendar/util/LunarUtil.java @@ -17,7 +17,9 @@ public class LunarUtil{ public static final int BASE_DAY = 11; /** 农历与阳历年偏移量 */ public static final int BASE_INDEX = 0; - /** 基准对应的干支偏移量 */ + /** 基准对应的年干支偏移量 */ + public static final int BASE_YEAR_GANZHI_INDEX = -4; + /** 基准对应的日干支偏移量 */ public static final int BASE_DAY_GANZHI_INDEX = 15; /** 月份地支偏移量,因正月起寅 */ public static final int BASE_MONTH_ZHI_INDEX = 2; @@ -27,10 +29,6 @@ public class LunarUtil{ public static final int[] LEAP_MONTH_YEAR = {6,14,19,25,33,36,38,41,44,52,55,79,117,136,147,150,155,158,185,193}; /** 闰月表 */ public static final int[] LUNAR_MONTH = {0x00,0x04,0xad,0x08,0x5a,0x01,0xd5,0x54,0xb4,0x09,0x64,0x05,0x59,0x45,0x95,0x0a,0xa6,0x04,0x55,0x24,0xad,0x08,0x5a,0x62,0xda,0x04,0xb4,0x05,0xb4,0x55,0x52,0x0d,0x94,0x0a,0x4a,0x2a,0x56,0x02,0x6d,0x71,0x6d,0x01,0xda,0x02,0xd2,0x52,0xa9,0x05,0x49,0x0d,0x2a,0x45,0x2b,0x09,0x56,0x01,0xb5,0x20,0x6d,0x01,0x59,0x69,0xd4,0x0a,0xa8,0x05,0xa9,0x56,0xa5,0x04,0x2b,0x09,0x9e,0x38,0xb6,0x08,0xec,0x74,0x6c,0x05,0xd4,0x0a,0xe4,0x6a,0x52,0x05,0x95,0x0a,0x5a,0x42,0x5b,0x04,0xb6,0x04,0xb4,0x22,0x6a,0x05,0x52,0x75,0xc9,0x0a,0x52,0x05,0x35,0x55,0x4d,0x0a,0x5a,0x02,0x5d,0x31,0xb5,0x02,0x6a,0x8a,0x68,0x05,0xa9,0x0a,0x8a,0x6a,0x2a,0x05,0x2d,0x09,0xaa,0x48,0x5a,0x01,0xb5,0x09,0xb0,0x39,0x64,0x05,0x25,0x75,0x95,0x0a,0x96,0x04,0x4d,0x54,0xad,0x04,0xda,0x04,0xd4,0x44,0xb4,0x05,0x54,0x85,0x52,0x0d,0x92,0x0a,0x56,0x6a,0x56,0x02,0x6d,0x02,0x6a,0x41,0xda,0x02,0xb2,0xa1,0xa9,0x05,0x49,0x0d,0x0a,0x6d,0x2a,0x09,0x56,0x01,0xad,0x50,0x6d,0x01,0xd9,0x02,0xd1,0x3a,0xa8,0x05,0x29,0x85,0xa5,0x0c,0x2a,0x09,0x96,0x54,0xb6,0x08,0x6c,0x09,0x64,0x45,0xd4,0x0a,0xa4,0x05,0x51,0x25,0x95,0x0a,0x2a,0x72,0x5b,0x04,0xb6,0x04,0xac,0x52,0x6a,0x05,0xd2,0x0a,0xa2,0x4a,0x4a,0x05,0x55,0x94,0x2d,0x0a,0x5a,0x02,0x75,0x61,0xb5,0x02,0x6a,0x03,0x61,0x45,0xa9,0x0a,0x4a,0x05,0x25,0x25,0x2d,0x09,0x9a,0x68,0xda,0x08,0xb4,0x09,0xa8,0x59,0x54,0x03,0xa5,0x0a,0x91,0x3a,0x96,0x04,0xad,0xb0,0xad,0x04,0xda,0x04,0xf4,0x62,0xb4,0x05,0x54,0x0b,0x44,0x5d,0x52,0x0a,0x95,0x04,0x55,0x22,0x6d,0x02,0x5a,0x71,0xda,0x02,0xaa,0x05,0xb2,0x55,0x49,0x0b,0x4a,0x0a,0x2d,0x39,0x36,0x01,0x6d,0x80,0x6d,0x01,0xd9,0x02,0xe9,0x6a,0xa8,0x05,0x29,0x0b,0x9a,0x4c,0xaa,0x08,0xb6,0x08,0xb4,0x38,0x6c,0x09,0x54,0x75,0xd4,0x0a,0xa4,0x05,0x45,0x55,0x95,0x0a,0x9a,0x04,0x55,0x44,0xb5,0x04,0x6a,0x82,0x6a,0x05,0xd2,0x0a,0x92,0x6a,0x4a,0x05,0x55,0x0a,0x2a,0x4a,0x5a,0x02,0xb5,0x02,0xb2,0x31,0x69,0x03,0x31,0x73,0xa9,0x0a,0x4a,0x05,0x2d,0x55,0x2d,0x09,0x5a,0x01,0xd5,0x48,0xb4,0x09,0x68,0x89,0x54,0x0b,0xa4,0x0a,0xa5,0x6a,0x95,0x04,0xad,0x08,0x6a,0x44,0xda,0x04,0x74,0x05,0xb0,0x25,0x54,0x03}; - public static final int[][] JIE_YEAR = {{13,49,85,117,149,185,201,250,250},{13,45,81,117,149,185,201,250,250},{13,48,84,112,148,184,200,201,250},{13,45,76,108,140,172,200,201,250},{13,44,72,104,132,168,200,201,250},{5,33,68,96,124,152,188,200,201},{29,57,85,120,148,176,200,201,250},{13,48,76,104,132,168,196,200,201},{25,60,88,120,148,184,200,201,250},{16,44,76,108,144,172,200,201,250},{28,60,92,124,160,192,200,201,250},{17,53,85,124,156,188,200,201,250}}; - public static final int[][] JIE_MAP = {{7,6,6,6,6,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,5,5,5,5,5,4,5,5},{5,4,5,5,5,4,4,5,5,4,4,4,4,4,4,4,4,3,4,4,4,3,3,4,4,3,3,3},{6,6,6,7,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,5},{5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,4,4,5,5,4,4,4,5,4,4,4,4,5},{6,6,6,7,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,5},{6,6,7,7,6,6,6,7,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,5},{7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,6,6,6,7,7},{8,8,8,9,8,8,8,8,7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,7},{8,8,8,9,8,8,8,8,7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,7},{9,9,9,9,8,9,9,9,8,8,9,9,8,8,8,9,8,8,8,8,7,8,8,8,7,7,8,8,8},{8,8,8,8,7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,7},{7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,6,6,6,7,7}}; - public static final int[][] QI_YEAR = {{13,45,81,113,149,185,201},{21,57,93,125,161,193,201},{21,56,88,120,152,188,200,201},{21,49,81,116,144,176,200,201},{17,49,77,112,140,168,200,201},{28,60,88,116,148,180,200,201},{25,53,84,112,144,172,200,201},{29,57,89,120,148,180,200,201},{17,45,73,108,140,168,200,201},{28,60,92,124,160,192,200,201},{16,44,80,112,148,180,200,201},{17,53,88,120,156,188,200,201}}; - public static final int[][] QI_MAP = {{21,21,21,21,21,20,21,21,21,20,20,21,21,20,20,20,20,20,20,20,20,19,20,20,20,19,19,20},{20,19,19,20,20,19,19,19,19,19,19,19,19,18,19,19,19,18,18,19,19,18,18,18,18,18,18,18},{21,21,21,22,21,21,21,21,20,21,21,21,20,20,21,21,20,20,20,21,20,20,20,20,19,20,20,20,20},{20,21,21,21,20,20,21,21,20,20,20,21,20,20,20,20,19,20,20,20,19,19,20,20,19,19,19,20,20},{21,22,22,22,21,21,22,22,21,21,21,22,21,21,21,21,20,21,21,21,20,20,21,21,20,20,20,21,21},{22,22,22,22,21,22,22,22,21,21,22,22,21,21,21,22,21,21,21,21,20,21,21,21,20,20,21,21,21},{23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,23,23,22,22,22,23,22,22,22,22,23},{23,24,24,24,23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,23,23,22,22,22,23,23},{23,24,24,24,23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,23,23,22,22,22,23,23},{24,24,24,24,23,24,24,24,23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,23,23,23},{23,23,23,23,22,23,23,23,22,22,23,23,22,22,22,23,22,22,22,22,21,22,22,22,21,21,22,22,22},{22,22,23,23,22,22,22,23,22,22,22,22,21,22,22,22,21,21,22,22,21,21,21,22,21,21,21,21,22}}; /** 天干 */ public static final String[] GAN = {"","甲","乙","丙","丁","戊","己","庚","辛","壬","癸"}; /** 喜神方位,《喜神方位歌》:甲己在艮乙庚乾,丙辛坤位喜神安.  丁壬只在离宫坐,戊癸原在在巽间。 */ @@ -51,6 +49,8 @@ public class LunarUtil{ public static final String[] POSITION_TAI_MONTH = {"占房床","占户窗","占门堂","占厨灶","占身床","占床仓","占碓磨","占厕户","占门房","占房床","占炉灶","占房床"}; /** 地支 */ public static final String[] ZHI = {"","子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"}; + /** 六十甲子 */ + public static final String[] JIA_ZI = {"甲子","乙丑","丙寅","丁卯","戊辰","己巳","庚午","辛未","壬申","癸酉","甲戌","乙亥","丙子","丁丑","戊寅","己卯","庚辰","辛巳","壬午","癸未","甲申","乙酉","丙戌","丁亥","戊子","己丑","庚寅","辛卯","壬辰","癸巳","甲午","乙未","丙申","丁酉","戊戌","己亥","庚子","辛丑","壬寅","癸卯","甲辰","乙巳","丙午","丁未","戊申","己酉","庚戌","辛亥","壬子","癸丑","甲寅","乙卯","丙辰","丁巳","戊午","己未","庚申","辛酉","壬戌","癸亥"}; /** 十二值星 */ public static final String[] ZHI_XING = {"","建","除","满","平","定","执","破","危","成","收","开","闭"}; /** 十二天神 */ @@ -113,7 +113,7 @@ public class LunarUtil{ /** 生肖 */ public static final String[] SHENGXIAO = {"","鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"}; /** 气 */ - public static final String[] QI = {"大寒","雨水","春分","谷雨","夏满","夏至","大暑","处暑","秋分","霜降","小雪","冬至"}; + public static final String[] QI = {"大寒","雨水","春分","谷雨","小满","夏至","大暑","处暑","秋分","霜降","小雪","冬至"}; /** 节 */ public static final String[] JIE = {"小寒","立春","惊蛰","清明","立夏","芒种","小暑","立秋","白露","寒露","立冬","大雪"}; /** 日 */ diff --git a/src/test/java/sample/BaZiTest.java b/src/test/java/sample/BaZiTest.java new file mode 100644 index 0000000..3821c46 --- /dev/null +++ b/src/test/java/sample/BaZiTest.java @@ -0,0 +1,61 @@ +package sample; + +import com.nlf.calendar.Lunar; +import com.nlf.calendar.Solar; +import org.junit.Assert; +import org.junit.Test; + +/** + * 八字测试 + */ +public class BaZiTest { + + @Test + public void test1(){ + Solar solar = new Solar(2020,1,1,22,35,0); + Lunar lunar = solar.getLunar(); + //[己亥, 丙子, 癸卯, 癸亥] + System.out.println(lunar.getBaZi()); + } + + @Test + public void test2(){ + Solar solar = new Solar(2020,1,6,14,35,0); + Lunar lunar = solar.getLunar(); + //[己亥, 丁丑, 戊申, 己未] + System.out.println(lunar.getBaZi()); + } + + @Test + public void test3(){ + Solar solar = new Solar(2020,1,6,3,35,0); + Lunar lunar = solar.getLunar(); + //[己亥, 丁丑, 戊辰, 癸亥] + System.out.println(lunar.getBaZi()); + } + + @Test + public void test4(){ + Solar solar = new Solar(2020,1,26,21,41,0); + Lunar lunar = solar.getLunar(); + //[己亥, 丙子, 戊申, 甲寅] + System.out.println(lunar.getBaZi()); + } + + @Test + public void test5(){ + Solar solar = new Solar(2020,2,4,1,42,0); + Lunar lunar = solar.getLunar(); + //[己亥, 丁丑, 丁丑, 辛丑] + System.out.println(lunar.getBaZi()); + } + + @Test + public void test6(){ + Solar solar = new Solar(2020,2,5,21,43,0); + Lunar lunar = solar.getLunar(); + //[庚子, 戊寅, 戊寅, 癸亥] + System.out.println(lunar.getBaZi()); + } + +} diff --git a/src/test/java/test/GanZhiTest.java b/src/test/java/test/GanZhiTest.java new file mode 100644 index 0000000..cd43a0d --- /dev/null +++ b/src/test/java/test/GanZhiTest.java @@ -0,0 +1,199 @@ +package test; + +import com.nlf.calendar.Lunar; +import com.nlf.calendar.Solar; +import org.junit.Assert; +import org.junit.Test; + +/** + * 干支测试 + */ +public class GanZhiTest { + + @Test + public void test(){ + Solar solar = new Solar(2020,1,1,13,22,0); + Lunar lunar = solar.getLunar(); + Assert.assertEquals("己亥",lunar.getYearInGanZhi()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("丙子",lunar.getMonthInGanZhi()); + Assert.assertEquals("丙子",lunar.getMonthInGanZhiExact()); + + + //小寒 + solar = new Solar(2020,1,6,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("己亥",lunar.getYearInGanZhi()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("丁丑",lunar.getMonthInGanZhi()); + Assert.assertEquals("丁丑",lunar.getMonthInGanZhiExact()); + + + solar = new Solar(2020,1,20,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("己亥",lunar.getYearInGanZhi()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("丁丑",lunar.getMonthInGanZhi()); + Assert.assertEquals("丁丑",lunar.getMonthInGanZhiExact()); + + + //春节 + solar = new Solar(2020,1,25,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("庚子",lunar.getYearInGanZhi()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("丁丑",lunar.getMonthInGanZhi()); + Assert.assertEquals("丁丑",lunar.getMonthInGanZhiExact()); + + + solar = new Solar(2020,1,30,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("庚子",lunar.getYearInGanZhi()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("丁丑",lunar.getMonthInGanZhi()); + Assert.assertEquals("丁丑",lunar.getMonthInGanZhiExact()); + + + solar = new Solar(2020,2,1,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("庚子",lunar.getYearInGanZhi()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("丁丑",lunar.getMonthInGanZhi()); + Assert.assertEquals("丁丑",lunar.getMonthInGanZhiExact()); + + + solar = new Solar(2020,2,4,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("庚子",lunar.getYearInGanZhi()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("戊寅",lunar.getMonthInGanZhi()); + Assert.assertEquals("丁丑",lunar.getMonthInGanZhiExact()); + + + solar = new Solar(2020,2,4,18,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("庚子",lunar.getYearInGanZhi()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("戊寅",lunar.getMonthInGanZhi()); + Assert.assertEquals("戊寅",lunar.getMonthInGanZhiExact()); + + + solar = new Solar(2020,2,5,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("庚子",lunar.getYearInGanZhi()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("戊寅",lunar.getMonthInGanZhi()); + Assert.assertEquals("戊寅",lunar.getMonthInGanZhiExact()); + + + solar = new Solar(2020,5,22,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("庚子",lunar.getYearInGanZhi()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("辛巳",lunar.getMonthInGanZhi()); + Assert.assertEquals("辛巳",lunar.getMonthInGanZhiExact()); + + + solar = new Solar(2020,5,23,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("庚子",lunar.getYearInGanZhi()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("辛巳",lunar.getMonthInGanZhi()); + Assert.assertEquals("辛巳",lunar.getMonthInGanZhiExact()); + + solar = new Solar(2020,5,29,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("庚子",lunar.getYearInGanZhi()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("辛巳",lunar.getMonthInGanZhi()); + Assert.assertEquals("辛巳",lunar.getMonthInGanZhiExact()); + + solar = new Solar(2020,6,1,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("庚子",lunar.getYearInGanZhi()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("辛巳",lunar.getMonthInGanZhi()); + Assert.assertEquals("辛巳",lunar.getMonthInGanZhiExact()); + + solar = new Solar(2020,6,29,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("庚子",lunar.getYearInGanZhi()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("庚子",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("壬午",lunar.getMonthInGanZhi()); + Assert.assertEquals("壬午",lunar.getMonthInGanZhiExact()); + + solar = new Solar(2019,5,1,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("己亥",lunar.getYearInGanZhi()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("己亥",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("戊辰",lunar.getMonthInGanZhi()); + Assert.assertEquals("戊辰",lunar.getMonthInGanZhiExact()); + + solar = new Solar(1986,5,29,13,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("丙寅",lunar.getYearInGanZhi()); + Assert.assertEquals("丙寅",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("丙寅",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("癸巳",lunar.getMonthInGanZhi()); + Assert.assertEquals("癸巳",lunar.getMonthInGanZhiExact()); + + solar = new Solar(1986,5,1,1,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("丙寅",lunar.getYearInGanZhi()); + Assert.assertEquals("丙寅",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("丙寅",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("壬辰",lunar.getMonthInGanZhi()); + Assert.assertEquals("壬辰",lunar.getMonthInGanZhiExact()); + + solar = new Solar(1986,5,6,1,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("丙寅",lunar.getYearInGanZhi()); + Assert.assertEquals("丙寅",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("丙寅",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("癸巳",lunar.getMonthInGanZhi()); + Assert.assertEquals("壬辰",lunar.getMonthInGanZhiExact()); + + solar = new Solar(1986,5,6,23,22,0); + lunar = solar.getLunar(); + Assert.assertEquals("丙寅",lunar.getYearInGanZhi()); + Assert.assertEquals("丙寅",lunar.getYearInGanZhiByLiChun()); + Assert.assertEquals("丙寅",lunar.getYearInGanZhiExact()); + + Assert.assertEquals("癸巳",lunar.getMonthInGanZhi()); + Assert.assertEquals("癸巳",lunar.getMonthInGanZhiExact()); + } + +} diff --git a/src/test/java/test/LunarTest.java b/src/test/java/test/LunarTest.java index 1d25edb..301a604 100644 --- a/src/test/java/test/LunarTest.java +++ b/src/test/java/test/LunarTest.java @@ -13,11 +13,11 @@ public class LunarTest { @Test public void test(){ - Lunar date = new Lunar(2019,3,27); + Lunar date = new Lunar(2019,3,27,0,0,0); Assert.assertEquals("贰零壹玖年叁月廿七",date.toString()); Assert.assertEquals("贰零壹玖年叁月廿七 己亥(猪)年 戊辰(龙)月 戊戌(狗)日 子(鼠)时 纳音[平地木 大林木 平地木 海中金] 星期三 (七殿泰山王诞) 西方白虎 星宿[参水猿](吉) 彭祖百忌[戊不受田田主不祥 戌不吃犬作怪上床] 喜神方位[巽](东南) 阳贵神方位[艮](东北) 阴贵神方位[坤](西南) 福神方位[坎](正北) 财神方位[坎](正北) 冲[(壬辰)龙] 煞[北]",date.toFullString()); Assert.assertEquals("2019-05-01",date.getSolar().toString()); - Assert.assertEquals("2019-05-01 00:00 星期三 (劳动节) 金牛座",date.getSolar().toFullString()); + Assert.assertEquals("2019-05-01 00:00:00 星期三 (劳动节) 金牛座",date.getSolar().toFullString()); } } diff --git a/src/test/java/test/SolarTest.java b/src/test/java/test/SolarTest.java index 26a25dd..ef63d5a 100644 --- a/src/test/java/test/SolarTest.java +++ b/src/test/java/test/SolarTest.java @@ -15,7 +15,7 @@ public class SolarTest { public void test(){ Solar date = new Solar(2019,5,1); Assert.assertEquals("2019-05-01",date.toString()); - Assert.assertEquals("2019-05-01 00:00 星期三 (劳动节) 金牛座",date.toFullString()); + Assert.assertEquals("2019-05-01 00:00:00 星期三 (劳动节) 金牛座",date.toFullString()); Assert.assertEquals("贰零壹玖年叁月廿七",date.getLunar().toString()); Assert.assertEquals("贰零壹玖年叁月廿七 己亥(猪)年 戊辰(龙)月 戊戌(狗)日 子(鼠)时 纳音[平地木 大林木 平地木 海中金] 星期三 (七殿泰山王诞) 西方白虎 星宿[参水猿](吉) 彭祖百忌[戊不受田田主不祥 戌不吃犬作怪上床] 喜神方位[巽](东南) 阳贵神方位[艮](东北) 阴贵神方位[坤](西南) 福神方位[坎](正北) 财神方位[坎](正北) 冲[(壬辰)龙] 煞[北]",date.getLunar().toFullString()); } diff --git a/src/test/java/test/TimeTest.java b/src/test/java/test/TimeTest.java index 95133c8..1b90965 100644 --- a/src/test/java/test/TimeTest.java +++ b/src/test/java/test/TimeTest.java @@ -211,7 +211,7 @@ public class TimeTest { hour = Integer.parseInt(hm.substring(0,2),10); minute = Integer.parseInt(hm.substring(3,5),10); } - Lunar lunar = Lunar.fromYmdHm(2020,1,1,hour,minute); + Lunar lunar = Lunar.fromYmdHms(2020,1,1,hour,minute,0); String ganZhi = entry.getValue(); Assert.assertEquals(hm, ganZhi, lunar.getTimeInGanZhi()); } @@ -225,7 +225,7 @@ public class TimeTest { hour = Integer.parseInt(hm.substring(0,2),10); minute = Integer.parseInt(hm.substring(3,5),10); } - Lunar lunar = Lunar.fromYmdHm(2020,1,1,hour,minute); + Lunar lunar = Lunar.fromYmdHms(2020,1,1,hour,minute,0); String gan = entry.getValue(); Assert.assertEquals(hm, gan, lunar.getTimeGan()); }