diff --git a/README.md b/README.md index c13a582..3715745 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,6 @@ lunar是一款无第三方依赖的公历(阳历)和农历(阴历、老黄历) [English](https://github.com/6tail/lunar-java/blob/master/README_EN.md) -非快照版本存在月干支的重大错误不建议使用,请使用快照版本。 - ### 快照版本 ```xml diff --git a/src/main/java/com/nlf/calendar/EightChar.java b/src/main/java/com/nlf/calendar/EightChar.java index fa3d780..4721e47 100644 --- a/src/main/java/com/nlf/calendar/EightChar.java +++ b/src/main/java/com/nlf/calendar/EightChar.java @@ -1,5 +1,6 @@ package com.nlf.calendar; +import com.nlf.calendar.eightchar.Yun; import com.nlf.calendar.util.LunarUtil; import java.util.ArrayList; @@ -9,128 +10,146 @@ import java.util.Map; /** * 八字 + * * @author 6tail */ public class EightChar { - /** 月支,按正月起寅排列 */ - private static final String[] MONTH_ZHI = {"","寅","卯","辰","巳","午","未","申","酉","戌","亥","子","丑"}; - /** 长生十二神 */ - public static final String[] CHANG_SHENG = {"长生","沐浴","冠带","临官","帝旺","衰","病","死","墓","绝","胎","养"}; - /** 长生十二神日干偏移值,五阳干顺推,五阴干逆推 */ - private static final Map CHANG_SHENG_OFFSET = new HashMap(){ + /** + * 月支,按正月起寅排列 + */ + private static final String[] MONTH_ZHI = {"", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥", "子", "丑"}; + /** + * 长生十二神 + */ + public static final String[] CHANG_SHENG = {"长生", "沐浴", "冠带", "临官", "帝旺", "衰", "病", "死", "墓", "绝", "胎", "养"}; + /** + * 长生十二神日干偏移值,五阳干顺推,五阴干逆推 + */ + private static final Map CHANG_SHENG_OFFSET = new HashMap() { private static final long serialVersionUID = 1; + { //阳 - put("甲",11); - put("丙",2); - put("戊",2); - put("庚",5); - put("壬",8); + put("甲", 11); + put("丙", 2); + put("戊", 2); + put("庚", 5); + put("壬", 8); //阴 - put("乙",6); - put("丁",9); - put("己",9); - put("辛",0); - put("癸",3); + put("乙", 6); + put("丁", 9); + put("己", 9); + put("辛", 0); + put("癸", 3); } }; - /** 阴历 */ + /** + * 阴历 + */ protected Lunar lunar; - public EightChar(Lunar lunar){ + public EightChar(Lunar lunar) { this.lunar = lunar; } - public static EightChar fromLunar(Lunar lunar){ + public static EightChar fromLunar(Lunar lunar) { return new EightChar(lunar); } @Override - public String toString(){ - return getYear()+" "+getMonth()+" "+getDay()+" "+getTime(); + public String toString() { + return getYear() + " " + getMonth() + " " + getDay() + " " + getTime(); } /** * 获取年柱 + * * @return 年柱 */ - public String getYear(){ + public String getYear() { return lunar.getYearInGanZhiExact(); } /** * 获取年干 + * * @return 天干 */ - public String getYearGan(){ + public String getYearGan() { return lunar.getYearGanExact(); } /** * 获取年支 + * * @return 地支 */ - public String getYearZhi(){ + public String getYearZhi() { return lunar.getYearZhiExact(); } /** * 获取年柱地支藏干,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 + * * @return 天干 */ - public List getYearHideGan(){ + public List getYearHideGan() { return LunarUtil.ZHI_HIDE_GAN.get(getYearZhi()); } /** * 获取年柱五行 + * * @return 五行 */ - public String getYearWuXing(){ - return LunarUtil.WU_XING_GAN.get(lunar.getYearGanExact())+LunarUtil.WU_XING_ZHI.get(lunar.getYearZhiExact()); + public String getYearWuXing() { + return LunarUtil.WU_XING_GAN.get(lunar.getYearGanExact()) + LunarUtil.WU_XING_ZHI.get(lunar.getYearZhiExact()); } /** * 获取年柱纳音 + * * @return 纳音 */ - public String getYearNaYin(){ + public String getYearNaYin() { return LunarUtil.NAYIN.get(getYear()); } /** * 获取年柱天干十神 + * * @return 十神 */ - public String getYearShiShenGan(){ - return LunarUtil.SHI_SHEN_GAN.get(getDayGan()+getYearGan()); + public String getYearShiShenGan() { + return LunarUtil.SHI_SHEN_GAN.get(getDayGan() + getYearGan()); } - private List getShiShenZhi(String zhi){ + private List getShiShenZhi(String zhi) { List hideGan = LunarUtil.ZHI_HIDE_GAN.get(zhi); List l = new ArrayList(hideGan.size()); - for(String gan:hideGan){ - l.add(LunarUtil.SHI_SHEN_ZHI.get(getDayGan()+zhi+gan)); + for (String gan : hideGan) { + l.add(LunarUtil.SHI_SHEN_ZHI.get(getDayGan() + zhi + gan)); } return l; } /** * 获取年柱地支十神,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 + * * @return 十神 */ - public List getYearShiShenZhi(){ + public List getYearShiShenZhi() { return getShiShenZhi(getYearZhi()); } - private String getDiShi(int zhiIndex){ + private String getDiShi(int zhiIndex) { int offset = CHANG_SHENG_OFFSET.get(getDayGan()); - int index = offset + (lunar.getDayGanIndexExact()%2==0?zhiIndex:-zhiIndex); - if(index>=12){ + int index = offset + (lunar.getDayGanIndexExact() % 2 == 0 ? zhiIndex : -zhiIndex); + if (index >= 12) { index -= 12; } - if(index<0){ + if (index < 0) { index += 12; } return CHANG_SHENG[index]; @@ -138,277 +157,308 @@ public class EightChar { /** * 获取年柱地势(长生十二神) + * * @return 地势 */ - public String getYearDiShi(){ + public String getYearDiShi() { return getDiShi(lunar.getYearZhiIndexExact()); } /** * 获取月柱 + * * @return 月柱 */ - public String getMonth(){ + public String getMonth() { return lunar.getMonthInGanZhiExact(); } /** * 获取月干 + * * @return 天干 */ - public String getMonthGan(){ + public String getMonthGan() { return lunar.getMonthGanExact(); } /** * 获取月支 + * * @return 地支 */ - public String getMonthZhi(){ + public String getMonthZhi() { return lunar.getMonthZhiExact(); } /** * 获取月柱地支藏干,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 + * * @return 天干 */ - public List getMonthHideGan(){ + public List getMonthHideGan() { return LunarUtil.ZHI_HIDE_GAN.get(getMonthZhi()); } /** * 获取月柱五行 + * * @return 五行 */ - public String getMonthWuXing(){ - return LunarUtil.WU_XING_GAN.get(lunar.getMonthGanExact())+LunarUtil.WU_XING_ZHI.get(lunar.getMonthZhiExact()); + public String getMonthWuXing() { + return LunarUtil.WU_XING_GAN.get(lunar.getMonthGanExact()) + LunarUtil.WU_XING_ZHI.get(lunar.getMonthZhiExact()); } /** * 获取月柱纳音 + * * @return 纳音 */ - public String getMonthNaYin(){ + public String getMonthNaYin() { return LunarUtil.NAYIN.get(getMonth()); } /** * 获取月柱天干十神 + * * @return 十神 */ - public String getMonthShiShenGan(){ - return LunarUtil.SHI_SHEN_GAN.get(getDayGan()+getMonthGan()); + public String getMonthShiShenGan() { + return LunarUtil.SHI_SHEN_GAN.get(getDayGan() + getMonthGan()); } /** * 获取月柱地支十神,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 + * * @return 十神 */ - public List getMonthShiShenZhi(){ + public List getMonthShiShenZhi() { return getShiShenZhi(getMonthZhi()); } /** * 获取月柱地势(长生十二神) + * * @return 地势 */ - public String getMonthDiShi(){ + public String getMonthDiShi() { return getDiShi(lunar.getMonthZhiIndexExact()); } /** * 获取日柱 + * * @return 日柱 */ - public String getDay(){ + public String getDay() { return lunar.getDayInGanZhiExact(); } /** * 获取日干 + * * @return 天干 */ - public String getDayGan(){ + public String getDayGan() { return lunar.getDayGanExact(); } /** * 获取日支 + * * @return 地支 */ - public String getDayZhi(){ + public String getDayZhi() { return lunar.getDayZhiExact(); } /** * 获取日柱地支藏干,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 + * * @return 天干 */ - public List getDayHideGan(){ + public List getDayHideGan() { return LunarUtil.ZHI_HIDE_GAN.get(getDayZhi()); } /** * 获取日柱五行 + * * @return 五行 */ - public String getDayWuXing(){ - return LunarUtil.WU_XING_GAN.get(lunar.getDayGanExact())+LunarUtil.WU_XING_ZHI.get(lunar.getDayZhiExact()); + public String getDayWuXing() { + return LunarUtil.WU_XING_GAN.get(lunar.getDayGanExact()) + LunarUtil.WU_XING_ZHI.get(lunar.getDayZhiExact()); } /** * 获取日柱纳音 + * * @return 纳音 */ - public String getDayNaYin(){ + public String getDayNaYin() { return LunarUtil.NAYIN.get(getDay()); } /** * 获取日柱天干十神,也称日元、日干 + * * @return 十神 */ - public String getDayShiShenGan(){ + public String getDayShiShenGan() { return "日主"; } /** * 获取日柱地支十神,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 + * * @return 十神 */ - public List getDayShiShenZhi(){ + public List getDayShiShenZhi() { return getShiShenZhi(getDayZhi()); } /** * 获取日柱地势(长生十二神) + * * @return 地势 */ - public String getDayDiShi(){ + public String getDayDiShi() { return getDiShi(lunar.getDayZhiIndexExact()); } /** * 获取时柱 + * * @return 时柱 */ - public String getTime(){ + public String getTime() { return lunar.getTimeInGanZhi(); } /** * 获取时干 + * * @return 天干 */ - public String getTimeGan(){ + public String getTimeGan() { return lunar.getTimeGan(); } /** * 获取时支 + * * @return 地支 */ - public String getTimeZhi(){ + public String getTimeZhi() { return lunar.getTimeZhi(); } /** * 获取时柱地支藏干,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 + * * @return 天干 */ - public List getTimeHideGan(){ + public List getTimeHideGan() { return LunarUtil.ZHI_HIDE_GAN.get(getTimeZhi()); } /** * 获取时柱五行 + * * @return 五行 */ - public String getTimeWuXing(){ - return LunarUtil.WU_XING_GAN.get(lunar.getTimeGan())+LunarUtil.WU_XING_ZHI.get(lunar.getTimeZhi()); + public String getTimeWuXing() { + return LunarUtil.WU_XING_GAN.get(lunar.getTimeGan()) + LunarUtil.WU_XING_ZHI.get(lunar.getTimeZhi()); } /** * 获取时柱纳音 + * * @return 纳音 */ - public String getTimeNaYin(){ + public String getTimeNaYin() { return LunarUtil.NAYIN.get(getTime()); } /** * 获取时柱天干十神 + * * @return 十神 */ - public String getTimeShiShenGan(){ - return LunarUtil.SHI_SHEN_GAN.get(getDayGan()+getTimeGan()); + public String getTimeShiShenGan() { + return LunarUtil.SHI_SHEN_GAN.get(getDayGan() + getTimeGan()); } /** * 获取时柱地支十神,由于藏干分主气、余气、杂气,所以返回结果可能为1到3个元素 + * * @return 十神 */ - public List getTimeShiShenZhi(){ + public List getTimeShiShenZhi() { return getShiShenZhi(getTimeZhi()); } /** * 获取时柱地势(长生十二神) + * * @return 地势 */ - public String getTimeDiShi(){ + public String getTimeDiShi() { return getDiShi(lunar.getTimeZhiIndex()); } /** * 获取胎元 + * * @return 胎元 */ - public String getTaiYuan(){ + public String getTaiYuan() { int ganIndex = lunar.getMonthGanIndexExact() + 1; - if(ganIndex>=10){ + if (ganIndex >= 10) { ganIndex -= 10; } int zhiIndex = lunar.getMonthZhiIndexExact() + 3; - if(zhiIndex>=12){ + if (zhiIndex >= 12) { zhiIndex -= 12; } - return LunarUtil.GAN[ganIndex+1]+LunarUtil.ZHI[zhiIndex+1]; + return LunarUtil.GAN[ganIndex + 1] + LunarUtil.ZHI[zhiIndex + 1]; } /** * 获取胎元纳音 + * * @return 纳音 */ - public String getTaiYuanNaYin(){ + public String getTaiYuanNaYin() { return LunarUtil.NAYIN.get(getTaiYuan()); } /** * 获取命宫 + * * @return 命宫 */ - public String getMingGong(){ + public String getMingGong() { int monthZhiIndex = 0; int timeZhiIndex = 0; - for(int i=0,j=MONTH_ZHI.length;i12){ + int zhiIndex = 26 - (monthZhiIndex + timeZhiIndex); + if (zhiIndex > 12) { zhiIndex -= 12; } - int jiaZiIndex = LunarUtil.getJiaZiIndex(lunar.getMonthInGanZhiExact()) - (monthZhiIndex-zhiIndex); - if(jiaZiIndex>=60){ + int jiaZiIndex = LunarUtil.getJiaZiIndex(lunar.getMonthInGanZhiExact()) - (monthZhiIndex - zhiIndex); + if (jiaZiIndex >= 60) { jiaZiIndex -= 60; } - if(jiaZiIndex<0){ + if (jiaZiIndex < 0) { jiaZiIndex += 60; } return LunarUtil.JIA_ZI[jiaZiIndex]; @@ -416,34 +466,36 @@ public class EightChar { /** * 获取命宫纳音 + * * @return 纳音 */ - public String getMingGongNaYin(){ + public String getMingGongNaYin() { return LunarUtil.NAYIN.get(getMingGong()); } /** * 获取身宫 + * * @return 身宫 */ - public String getShenGong(){ + public String getShenGong() { int monthZhiIndex = 0; int timeZhiIndex = 0; - for(int i=0,j=MONTH_ZHI.length;i=60){ + int zhiIndex = (2 + (monthZhiIndex + timeZhiIndex)) % 12; + int jiaZiIndex = LunarUtil.getJiaZiIndex(lunar.getMonthInGanZhiExact()) - (monthZhiIndex - zhiIndex); + if (jiaZiIndex >= 60) { jiaZiIndex -= 60; } - if(jiaZiIndex<0){ + if (jiaZiIndex < 0) { jiaZiIndex += 60; } return LunarUtil.JIA_ZI[jiaZiIndex]; @@ -451,10 +503,26 @@ public class EightChar { /** * 获取身宫纳音 + * * @return 纳音 */ - public String getShenGongNaYin(){ + public String getShenGongNaYin() { return LunarUtil.NAYIN.get(getShenGong()); } + public Lunar getLunar() { + return lunar; + } + + /** + * 获取运 + * + * @param gender 性别:1男,0女 + * @return 运 + */ + public Yun getYun(int gender) { + return new Yun(this, gender); + } + + } diff --git a/src/main/java/com/nlf/calendar/JieQi.java b/src/main/java/com/nlf/calendar/JieQi.java new file mode 100644 index 0000000..65a0597 --- /dev/null +++ b/src/main/java/com/nlf/calendar/JieQi.java @@ -0,0 +1,56 @@ +package com.nlf.calendar; + +/** + * 节气 + * + * @author 6tail + */ +public class JieQi { + + /** 名称 */ + private String name; + + /** 阳历日期 */ + private Solar solar; + + public JieQi() { + } + + public JieQi(String name, Solar solar) { + this.name = name; + this.solar = solar; + } + + /** + * 获取名称 + * @return 名称 + */ + public String getName() { + return name; + } + + /** + * 设置名称 + * @param name 名称 + */ + public void setName(String name) { + this.name = name; + } + + /** + * 获取阳历日期 + * @return 阳历日期 + */ + public Solar getSolar() { + return solar; + } + + /** + * 设置阳历日期 + * @param solar 阳历日期 + */ + public void setSolar(Solar solar) { + this.solar = solar; + } + +} diff --git a/src/main/java/com/nlf/calendar/Lunar.java b/src/main/java/com/nlf/calendar/Lunar.java index 4677012..798215f 100644 --- a/src/main/java/com/nlf/calendar/Lunar.java +++ b/src/main/java/com/nlf/calendar/Lunar.java @@ -1915,6 +1915,89 @@ public class Lunar{ return jieQi; } + /** + * 获取下一节(顺推的第一个节) + * @return 节气 + */ + public JieQi getNextJie(){ + return getNearJieQi(true,LunarUtil.JIE); + } + + /** + * 获取上一节(逆推的第一个节) + * @return 节气 + */ + public JieQi getPrevJie(){ + return getNearJieQi(false,LunarUtil.JIE); + } + + /** + * 获取下一节气(顺推的第一个节气) + * @return 节气 + */ + public JieQi getNextJieQi(){ + return getNearJieQi(true,null); + } + + /** + * 获取上一节气(逆推的第一个节气) + * @return 节气 + */ + public JieQi getPrevJieQi(){ + return getNearJieQi(false,null); + } + + /** + * 获取最近的节气,如果未找到匹配的,返回null + * @param forward 是否顺推,true为顺推,false为逆推 + * @param conditions 过滤条件,如果设置过滤条件,仅返回匹配该名称的 + * @return 节气 + */ + protected JieQi getNearJieQi(boolean forward, String[] conditions){ + String name = null; + Solar near = null; + Set filters = new HashSet(); + if(null!=conditions) { + Collections.addAll(filters, conditions); + } + boolean filter = !filters.isEmpty(); + String today = solar.toYmdHms(); + for(Map.Entry entry:jieQi.entrySet()){ + String jq = entry.getKey(); + if("DONG_ZHI".equals(jq)){ + jq = "冬至"; + } + if(filter){ + if(!filters.contains(jq)){ + continue; + } + } + Solar solar = entry.getValue(); + String day = solar.toYmdHms(); + if(forward){ + if(day.compareTo(today)<0){ + continue; + } + if(null==near || day.compareTo(near.toYmdHms())<0){ + name = jq; + near = solar; + } + }else{ + if(day.compareTo(today)>0){ + continue; + } + if(null==near || day.compareTo(near.toYmdHms())>0) { + name = jq; + near = solar; + } + } + } + if(null==near){ + return null; + } + return new JieQi(name, near); + } + public String toFullString(){ StringBuilder s = new StringBuilder(); s.append(toString()); diff --git a/src/main/java/com/nlf/calendar/eightchar/DaYun.java b/src/main/java/com/nlf/calendar/eightchar/DaYun.java new file mode 100644 index 0000000..aeeecf9 --- /dev/null +++ b/src/main/java/com/nlf/calendar/eightchar/DaYun.java @@ -0,0 +1,135 @@ +package com.nlf.calendar.eightchar; + +import com.nlf.calendar.Lunar; +import com.nlf.calendar.util.LunarUtil; + +/** + * 大运 + * + * @author 6tail + */ +public class DaYun { + /** + * 开始年(含) + */ + private int startYear; + /** + * 结束年(含) + */ + private int endYear; + /** + * 开始年龄(含) + */ + private int startAge; + /** + * 结束年龄(含) + */ + private int endAge; + /** + * 序数,0-9 + */ + private int index; + /** + * 运 + */ + private Yun yun; + private Lunar lunar; + + public DaYun(Yun yun, int index) { + this.yun = yun; + this.lunar = yun.getLunar(); + this.index = index; + int year = yun.getStartSolar().getYear(); + if (index < 1) { + this.startYear = lunar.getSolar().getYear(); + this.startAge = 1; + this.endYear = year - 1; + this.endAge = yun.getStartYear(); + } else { + int add = (index - 1) * 10; + this.startYear = year + add; + this.startAge = yun.getStartYear() + add + 1; + this.endYear = this.startYear + 9; + this.endAge = this.startAge + 9; + } + } + + public int getStartYear() { + return startYear; + } + + public int getEndYear() { + return endYear; + } + + public int getStartAge() { + return startAge; + } + + public int getEndAge() { + return endAge; + } + + public int getIndex() { + return index; + } + + public Lunar getLunar() { + return lunar; + } + + /** + * 获取干支 + * + * @return 干支 + */ + public String getGanZhi() { + if (index < 1) { + return ""; + } + int offset = LunarUtil.getJiaZiIndex(lunar.getMonthInGanZhiExact()); + offset += yun.isForward() ? index : -index; + int size = LunarUtil.JIA_ZI.length; + if (offset >= size) { + offset -= size; + } + if (offset < 0) { + offset += size; + } + return LunarUtil.JIA_ZI[offset]; + } + + /** + * 获取流年 + * + * @return 流年 + */ + public LiuNian[] getLiuNian() { + int n = 10; + if (index < 1) { + n = endYear-startYear+1; + } + LiuNian[] l = new LiuNian[n]; + for (int i = 0; i < n; i++) { + l[i] = new LiuNian(this, i); + } + return l; + } + + /** + * 获取小运 + * + * @return 小运 + */ + public XiaoYun[] getXiaoYun() { + int n = 10; + if (index < 1) { + n = endYear-startYear+1; + } + XiaoYun[] l = new XiaoYun[n]; + for (int i = 0; i < n; i++) { + l[i] = new XiaoYun(this, i, yun.isForward()); + } + return l; + } +} diff --git a/src/main/java/com/nlf/calendar/eightchar/LiuNian.java b/src/main/java/com/nlf/calendar/eightchar/LiuNian.java new file mode 100644 index 0000000..dbdbbd5 --- /dev/null +++ b/src/main/java/com/nlf/calendar/eightchar/LiuNian.java @@ -0,0 +1,72 @@ +package com.nlf.calendar.eightchar; + +import com.nlf.calendar.Lunar; +import com.nlf.calendar.util.LunarUtil; + +/** + * 流年 + * + * @author 6tail + */ +public class LiuNian { + /** + * 序数,0-9 + */ + private int index; + /** + * 大运 + */ + private DaYun daYun; + /** + * 年 + */ + private int year; + /** + * 年龄 + */ + private int age; + private Lunar lunar; + + public LiuNian(DaYun daYun, int index) { + this.daYun = daYun; + this.lunar = daYun.getLunar(); + this.index = index; + this.year = daYun.getStartYear() + index; + this.age = daYun.getStartAge() + index; + } + + public int getIndex() { + return index; + } + + public int getYear() { + return year; + } + + public int getAge() { + return age; + } + + /** + * 获取干支 + * + * @return 干支 + */ + public String getGanZhi() { + int offset = LunarUtil.getJiaZiIndex(lunar.getYearInGanZhiExact()) + this.index; + if (daYun.getIndex() > 0) { + offset += daYun.getStartAge() - 1; + } + offset %= LunarUtil.JIA_ZI.length; + return LunarUtil.JIA_ZI[offset]; + } + + public LiuYue[] getLiuYue() { + int n = 12; + LiuYue[] l = new LiuYue[n]; + for (int i = 0; i < n; i++) { + l[i] = new LiuYue(this, i); + } + return l; + } +} diff --git a/src/main/java/com/nlf/calendar/eightchar/LiuYue.java b/src/main/java/com/nlf/calendar/eightchar/LiuYue.java new file mode 100644 index 0000000..fb57dad --- /dev/null +++ b/src/main/java/com/nlf/calendar/eightchar/LiuYue.java @@ -0,0 +1,64 @@ +package com.nlf.calendar.eightchar; + +import com.nlf.calendar.util.LunarUtil; + +/** + * 流月 + * + * @author 6tail + */ +public class LiuYue { + /** + * 序数,0-9 + */ + private int index; + private LiuNian liuNian; + + public LiuYue(LiuNian liuNian, int index) { + this.liuNian = liuNian; + this.index = index; + } + + public int getIndex() { + return index; + } + + /** + * 获取中文的月 + * + * @return 中文月,如正 + */ + public String getMonthInChinese() { + return LunarUtil.MONTH[index + 1]; + } + + /** + * 获取干支 + *

+ * 《五虎遁》 + * 甲己之年丙作首, + * 乙庚之年戊为头, + * 丙辛之年寻庚上, + * 丁壬壬寅顺水流, + * 若问戊癸何处走, + * 甲寅之上好追求。 + * + * @return 干支 + */ + public String getGanZhi() { + int offset = 0; + String yearGan = liuNian.getGanZhi().substring(0, 1); + if ("甲".equals(yearGan) || "己".equals(yearGan)) { + offset = 2; + } else if ("乙".equals(yearGan) || "庚".equals(yearGan)) { + offset = 4; + } else if ("丙".equals(yearGan) || "辛".equals(yearGan)) { + offset = 6; + } else if ("丁".equals(yearGan) || "壬".equals(yearGan)) { + offset = 8; + } + String gan = LunarUtil.GAN[(index + offset) % 10 + 1]; + String zhi = LunarUtil.ZHI[(index + LunarUtil.BASE_MONTH_ZHI_INDEX) % 12 + 1]; + return gan + zhi; + } +} diff --git a/src/main/java/com/nlf/calendar/eightchar/XiaoYun.java b/src/main/java/com/nlf/calendar/eightchar/XiaoYun.java new file mode 100644 index 0000000..49c1256 --- /dev/null +++ b/src/main/java/com/nlf/calendar/eightchar/XiaoYun.java @@ -0,0 +1,74 @@ +package com.nlf.calendar.eightchar; + +import com.nlf.calendar.Lunar; +import com.nlf.calendar.util.LunarUtil; + +/** + * 小运 + * + * @author 6tail + */ +public class XiaoYun { + /** + * 序数,0-9 + */ + private int index; + /** + * 大运 + */ + private DaYun daYun; + /** + * 年 + */ + private int year; + /** + * 年龄 + */ + private int age; + /** + * 是否顺推 + */ + private boolean forward; + private Lunar lunar; + + public XiaoYun(DaYun daYun, int index, boolean forward) { + this.daYun = daYun; + this.lunar = daYun.getLunar(); + this.index = index; + this.year = daYun.getStartYear() + index; + this.age = daYun.getStartAge() + index; + this.forward = forward; + } + + public int getIndex() { + return index; + } + + public int getYear() { + return year; + } + + public int getAge() { + return age; + } + + /** + * 获取干支 + * + * @return 干支 + */ + public String getGanZhi() { + int offset = LunarUtil.getJiaZiIndex(lunar.getTimeInGanZhi()); + int add = this.index + 1; + if (daYun.getIndex() > 0) { + add += daYun.getStartAge() - 1; + } + offset += forward ? add : -add; + int size = LunarUtil.JIA_ZI.length; + while (offset < 0) { + offset += size; + } + offset %= size; + return LunarUtil.JIA_ZI[offset]; + } +} diff --git a/src/main/java/com/nlf/calendar/eightchar/Yun.java b/src/main/java/com/nlf/calendar/eightchar/Yun.java new file mode 100644 index 0000000..946aef6 --- /dev/null +++ b/src/main/java/com/nlf/calendar/eightchar/Yun.java @@ -0,0 +1,162 @@ +package com.nlf.calendar.eightchar; + +import com.nlf.calendar.EightChar; +import com.nlf.calendar.JieQi; +import com.nlf.calendar.Lunar; +import com.nlf.calendar.Solar; +import com.nlf.calendar.util.LunarUtil; + +import java.util.Calendar; + +/** + * 运 + * + * @author 6tail + */ +public class Yun { + /** + * 性别(1男,0女) + */ + private int gender; + /** + * 起运年数 + */ + private int startYear; + /** + * 起运月数 + */ + private int startMonth; + /** + * 起运天数 + */ + private int startDay; + /** + * 是否顺推 + */ + private boolean forward; + private Lunar lunar; + + public Yun(EightChar eightChar, int gender) { + this.lunar = eightChar.getLunar(); + this.gender = gender; + // 阳 + boolean yang = 0 == lunar.getYearGanIndexExact() % 2; + // 男 + boolean man = 1 == gender; + forward = (yang && man) || (!yang && !man); + computeStart(); + } + + /** + * 起运计算 + */ + private void computeStart() { + // 上节 + JieQi prev = lunar.getPrevJie(); + // 下节 + JieQi next = lunar.getNextJie(); + // 出生日期 + Solar current = lunar.getSolar(); + // 阳男阴女顺推,阴男阳女逆推 + Solar start = forward ? current : prev.getSolar(); + Solar end = forward ? next.getSolar() : current; + // 时辰差 + int hourDiff = LunarUtil.getTimeZhiIndex(end.toYmdHms().substring(11, 16)) - LunarUtil.getTimeZhiIndex(start.toYmdHms().substring(11, 16)); + Calendar endCalendar = Calendar.getInstance(); + endCalendar.set(end.getYear(), end.getMonth() - 1, end.getDay(), 0, 0, 0); + endCalendar.set(Calendar.MILLISECOND, 0); + Calendar startCalendar = Calendar.getInstance(); + startCalendar.set(start.getYear(), start.getMonth() - 1, start.getDay(), 0, 0, 0); + startCalendar.set(Calendar.MILLISECOND, 0); + // 天数差 + int dayDiff = (int) ((endCalendar.getTimeInMillis() - startCalendar.getTimeInMillis()) / (1000 * 3600 * 24)); + if (hourDiff < 0) { + hourDiff += 12; + dayDiff--; + } + int monthDiff = hourDiff * 10 / 30; + int month = dayDiff * 4 + monthDiff; + int day = hourDiff * 10 - monthDiff * 30; + int year = month / 12; + month = month - year * 12; + this.startYear = year; + this.startMonth = month; + this.startDay = day; + } + + /** + * 获取性别 + * + * @return 性别(1男 , 0女) + */ + public int getGender() { + return gender; + } + + /** + * 获取起运年数 + * + * @return 起运年数 + */ + public int getStartYear() { + return startYear; + } + + /** + * 获取起运月数 + * + * @return 起运月数 + */ + public int getStartMonth() { + return startMonth; + } + + /** + * 获取起运天数 + * + * @return 起运天数 + */ + public int getStartDay() { + return startDay; + } + + /** + * 是否顺推 + * + * @return true/false + */ + public boolean isForward() { + return forward; + } + + public Lunar getLunar() { + return lunar; + } + + /** + * 获取起运的阳历日期 + * + * @return 阳历日期 + */ + public Solar getStartSolar() { + Solar birth = lunar.getSolar(); + Calendar c = Calendar.getInstance(); + c.set(birth.getYear() + startYear, birth.getMonth() - 1 + startMonth, birth.getDay() + startDay, 0, 0, 0); + return Solar.fromCalendar(c); + } + + /** + * 获取大运 + * + * @return 大运 + */ + public DaYun[] getDaYun() { + int n = 10; + DaYun[] l = new DaYun[n]; + for (int i = 0; i < n; i++) { + l[i] = new DaYun(this, i); + } + return l; + } +} + diff --git a/src/test/java/sample/BaZiTestNew.java b/src/test/java/sample/BaZiTestNew.java index e3e5b0b..3bb1ba2 100644 --- a/src/test/java/sample/BaZiTestNew.java +++ b/src/test/java/sample/BaZiTestNew.java @@ -1,60 +1,64 @@ package sample; +import com.nlf.calendar.EightChar; import com.nlf.calendar.Lunar; import com.nlf.calendar.Solar; +import com.nlf.calendar.eightchar.*; +import org.junit.Assert; import org.junit.Test; import java.util.List; /** * 八字测试 + * * @author 6tail */ public class BaZiTestNew { @Test - public void test1(){ - Solar solar = new Solar(2020,1,1,22,35,0); + public void test1() { + Solar solar = new Solar(2020, 1, 1, 22, 35, 0); Lunar lunar = solar.getLunar(); //己亥 丙子 癸卯 癸亥 System.out.println(lunar.getEightChar()); } @Test - public void test2(){ - Solar solar = new Solar(2020,1,6,14,35,0); + public void test2() { + Solar solar = new Solar(2020, 1, 6, 14, 35, 0); Lunar lunar = solar.getLunar(); //己亥, 丁丑, 戊申, 己未] System.out.println(lunar.getEightChar()); } @Test - public void test3(){ - Solar solar = new Solar(2020,1,6,3,35,0); + public void test3() { + Solar solar = new Solar(2020, 1, 6, 3, 35, 0); Lunar lunar = solar.getLunar(); //己亥, 丁丑, 戊辰, 癸亥] System.out.println(lunar.getEightChar()); } @Test - public void test4(){ - Solar solar = new Solar(2020,1,26,21,41,0); + public void test4() { + Solar solar = new Solar(2020, 1, 26, 21, 41, 0); Lunar lunar = solar.getLunar(); //己亥, 丙子, 戊申, 甲寅] System.out.println(lunar.getEightChar()); } @Test - public void test5(){ - Solar solar = new Solar(2020,2,4,1,42,0); + public void test5() { + Solar solar = new Solar(2020, 2, 4, 1, 42, 0); Lunar lunar = solar.getLunar(); //己亥, 丁丑, 丁丑, 辛丑] System.out.println(lunar.getEightChar()); } @Test - public void test6(){ - Solar solar = new Solar(2020,2,5,21,43,0); + public void test6() { + Solar solar = new Solar(2020, 2, 5, 21, 43, 0); Lunar lunar = solar.getLunar(); //庚子, 戊寅, 戊寅, 癸亥] System.out.println(lunar.getEightChar()); @@ -70,8 +74,8 @@ public class BaZiTestNew { } @Test - public void test7(){ - Solar solar = new Solar(2020,5,26,23,43,0); + public void test7() { + Solar solar = new Solar(2020, 5, 26, 23, 43, 0); Lunar lunar = solar.getLunar(); //庚子, 辛巳, 庚午, 丙子] System.out.println(lunar.getEightChar()); @@ -106,7 +110,7 @@ public class BaZiTestNew { @Test public void testBaziShiShenZhi() { - Solar solar = new Solar(2020,1,1,22,35,0); + Solar solar = new Solar(2020, 1, 1, 22, 35, 0); Lunar lunar = solar.getLunar(); //己亥 丙子 癸卯 癸亥 System.out.println(lunar.getEightChar()); @@ -129,4 +133,185 @@ public class BaZiTestNew { System.out.println(lunar.getEightChar().getTimeShiShenZhi()); } + /** + * 起运 + */ + @Test + public void testQiYun() { + Solar solar = new Solar(1983, 2, 15, 20, 0, 0); + Lunar lunar = solar.getLunar(); + EightChar bazi = lunar.getEightChar(); + Yun yun = bazi.getYun(0); + Assert.assertEquals(6, yun.getStartYear()); + Assert.assertEquals(2, yun.getStartMonth()); + Assert.assertEquals(20, yun.getStartDay()); + Assert.assertEquals("1989-05-05", yun.getStartSolar().toYmd()); + + solar = new Solar(2013, 7, 13, 16, 17, 0); + lunar = solar.getLunar(); + bazi = lunar.getEightChar(); + yun = bazi.getYun(0); + Assert.assertEquals(8, yun.getStartYear()); + Assert.assertEquals(4, yun.getStartMonth()); + Assert.assertEquals(0, yun.getStartDay()); + Assert.assertEquals("2021-11-13", yun.getStartSolar().toYmd()); + + solar = new Solar(2020, 8, 18, 10, 0, 0); + lunar = solar.getLunar(); + bazi = lunar.getEightChar(); + yun = bazi.getYun(0); + Assert.assertEquals(3, yun.getStartYear()); + Assert.assertEquals(8, yun.getStartMonth()); + Assert.assertEquals(0, yun.getStartDay()); + Assert.assertEquals("2024-04-18", yun.getStartSolar().toYmd()); + + solar = new Solar(1972, 6, 15, 0, 0, 0); + lunar = solar.getLunar(); + bazi = lunar.getEightChar(); + yun = bazi.getYun(1); + Assert.assertEquals(7, yun.getStartYear()); + Assert.assertEquals(5, yun.getStartMonth()); + Assert.assertEquals(10, yun.getStartDay()); + Assert.assertEquals("1979-11-25", yun.getStartSolar().toYmd()); + + solar = new Solar(1968, 11, 22, 0, 0, 0); + lunar = solar.getLunar(); + bazi = lunar.getEightChar(); + yun = bazi.getYun(1); + Assert.assertEquals(5, yun.getStartYear()); + Assert.assertEquals(1, yun.getStartMonth()); + Assert.assertEquals(20, yun.getStartDay()); + Assert.assertEquals("1974-01-11", yun.getStartSolar().toYmd()); + + solar = new Solar(1968, 11, 23, 0, 0, 0); + lunar = solar.getLunar(); + bazi = lunar.getEightChar(); + yun = bazi.getYun(1); + Assert.assertEquals(4, yun.getStartYear()); + Assert.assertEquals(9, yun.getStartMonth()); + Assert.assertEquals(20, yun.getStartDay()); + Assert.assertEquals("1973-09-12", yun.getStartSolar().toYmd()); + } + + /** + * 大运 + */ + @Test + public void testDaYun() { + int[] startYears = {1983, 1989, 1999, 2009, 2019, 2029, 2039, 2049, 2059, 2069}; + int[] endYears = {1988, 1998, 2008, 2018, 2028, 2038, 2048, 2058, 2068, 2078}; + int[] startAges = {1, 7, 17, 27, 37, 47, 57, 67, 77, 87}; + int[] endAges = {6, 16, 26, 36, 46, 56, 66, 76, 86, 96}; + String[] yearGanZhi = {"", "乙卯", "丙辰", "丁巳", "戊午", "己未", "庚申", "辛酉", "壬戌", "癸亥"}; + Solar solar = new Solar(1983, 2, 15, 20, 0, 0); + Lunar lunar = solar.getLunar(); + EightChar bazi = lunar.getEightChar(); + Yun yun = bazi.getYun(0); + DaYun[] l = yun.getDaYun(); + for (int i = 0, j = l.length; i < j; i++) { + DaYun daYun = l[i]; + Assert.assertEquals(startYears[i], daYun.getStartYear()); + Assert.assertEquals(endYears[i], daYun.getEndYear()); + Assert.assertEquals(startAges[i], daYun.getStartAge()); + Assert.assertEquals(endAges[i], daYun.getEndAge()); + Assert.assertEquals(yearGanZhi[i], daYun.getGanZhi()); + } + } + + /** + * 流年 + */ + @Test + public void testLiuNian() { + Solar solar = new Solar(1983, 2, 15, 20, 0, 0); + Lunar lunar = solar.getLunar(); + EightChar bazi = lunar.getEightChar(); + Yun yun = bazi.getYun(0); + DaYun[] daYun = yun.getDaYun(); + + int[] years = {1983, 1984, 1985, 1986, 1987, 1988}; + int[] ages = {1, 2, 3, 4, 5, 6}; + String[] ganZhi = {"癸亥", "甲子", "乙丑", "丙寅", "丁卯", "戊辰"}; + LiuNian[] l = daYun[0].getLiuNian(); + for (int i = 0, j = l.length; i < j; i++) { + LiuNian liuNian = l[i]; + Assert.assertEquals(years[i], liuNian.getYear()); + Assert.assertEquals(ages[i], liuNian.getAge()); + Assert.assertEquals(ganZhi[i], liuNian.getGanZhi()); + } + + years = new int[]{2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038}; + ages = new int[]{47, 48, 49, 50, 51, 52, 53, 54, 55, 56}; + ganZhi = new String[]{"己酉", "庚戌", "辛亥", "壬子", "癸丑", "甲寅", "乙卯", "丙辰", "丁巳", "戊午"}; + l = daYun[5].getLiuNian(); + for (int i = 0, j = l.length; i < j; i++) { + LiuNian liuNian = l[i]; + Assert.assertEquals(years[i], liuNian.getYear()); + Assert.assertEquals(ages[i], liuNian.getAge()); + Assert.assertEquals(years[i] + "年", ganZhi[i], liuNian.getGanZhi()); + } + } + + /** + * 小运 + */ + @Test + public void testXiaoYun() { + Solar solar = new Solar(1983, 2, 15, 20, 0, 0); + Lunar lunar = solar.getLunar(); + EightChar bazi = lunar.getEightChar(); + Yun yun = bazi.getYun(0); + DaYun[] daYun = yun.getDaYun(); + + int[] years = {1983, 1984, 1985, 1986, 1987, 1988}; + int[] ages = {1, 2, 3, 4, 5, 6}; + String[] ganZhi = {"乙亥", "丙子", "丁丑", "戊寅", "己卯", "庚辰"}; + XiaoYun[] l = daYun[0].getXiaoYun(); + for (int i = 0, j = l.length; i < j; i++) { + XiaoYun xiaoYun = l[i]; + Assert.assertEquals(years[i], xiaoYun.getYear()); + Assert.assertEquals(ages[i], xiaoYun.getAge()); + Assert.assertEquals(ganZhi[i], xiaoYun.getGanZhi()); + } + + years = new int[]{2029, 2030, 2031, 2032, 2033, 2034, 2035, 2036, 2037, 2038}; + ages = new int[]{47, 48, 49, 50, 51, 52, 53, 54, 55, 56}; + ganZhi = new String[]{"辛酉", "壬戌", "癸亥", "甲子", "乙丑", "丙寅", "丁卯", "戊辰", "己巳", "庚午"}; + l = daYun[5].getXiaoYun(); + for (int i = 0, j = l.length; i < j; i++) { + XiaoYun xiaoYun = l[i]; + Assert.assertEquals(years[i], xiaoYun.getYear()); + Assert.assertEquals(ages[i], xiaoYun.getAge()); + Assert.assertEquals(years[i] + "年", ganZhi[i], xiaoYun.getGanZhi()); + } + } + + /** + * 流月 + */ + @Test + public void testLiuYue() { + Solar solar = new Solar(1983, 2, 15, 20, 0, 0); + Lunar lunar = solar.getLunar(); + EightChar bazi = lunar.getEightChar(); + Yun yun = bazi.getYun(0); + DaYun[] daYun = yun.getDaYun(); + + String[] ganZhi = {"甲寅", "乙卯", "丙辰", "丁巳", "戊午", "己未", "庚申", "辛酉", "壬戌", "癸亥", "甲子", "乙丑"}; + LiuNian[] liuNian = daYun[0].getLiuNian(); + LiuYue[] l = liuNian[0].getLiuYue(); + for (int i = 0, j = l.length; i < j; i++) { + LiuYue liuYue = l[i]; + Assert.assertEquals(ganZhi[i], liuYue.getGanZhi()); + } + + ganZhi = new String[]{"庚寅", "辛卯", "壬辰", "癸巳", "甲午", "乙未", "丙申", "丁酉", "戊戌", "己亥", "庚子", "辛丑"}; + liuNian = daYun[4].getLiuNian(); + l = liuNian[2].getLiuYue(); + for (int i = 0, j = l.length; i < j; i++) { + LiuYue liuYue = l[i]; + Assert.assertEquals(ganZhi[i], liuYue.getGanZhi()); + } + } + }