|  |  | 
 |  |  |  */ | 
 |  |  | public class ChinesischerKalender extends BasisKalender implements Wandler { | 
 |  |  |  | 
 |  |  |   /** | 
 |  |  |    * Der Start der chinesischen Zeitrechung laesst sich aus dem heutigen  | 
 |  |  |    * chinesischen Datum errechnen. Das erste Jahr des ersten Zyklus faellt  | 
 |  |  |    * so auf den 15. Februar -2636 im gregorianischen Kalender. | 
 |  |  |    */ | 
 |  |  |     public static final long STARTTAG = new ISOKalender().zuTagen(-2636, Definition.FEBRUAR, 15); | 
 |  |  |    | 
 |  |  |   private long zyklus; | 
 |  |  |   private boolean schaltmonat; | 
 |  |  |  | 
 |  |  |   /** | 
 |  |  |    * Den Zyklus angeben, in dem ein Jahr des chinesischen Kalenders liegt, das  | 
 |  |  |    * mit der Methode zuTagen(jahr, monat, tag) in ein generisches Datum  | 
 |  |  |    * umgerechnet werden soll. | 
 |  |  |    *  | 
 |  |  |    * Diese Methode ist eine Hilfsfunktion, wenn nicht die Methode  | 
 |  |  |    * zuTagen(zyklus, jahr, monat, schaltmonat, tag) genutzt werden kann. | 
 |  |  |    *  | 
 |  |  |    * @param zyklus der Zyklus im chinesischen á¸°alender | 
 |  |  |    */ | 
 |  |  |   public void setZyklus(long zyklus) { | 
 |  |  |     this.zyklus = zyklus; | 
 |  |  |   } | 
 |  |  |  | 
 |  |  |   /** | 
 |  |  |    * Angeben, ob ein Monat eines Datums im chinesischen Kalender ein  | 
 |  |  |    * Schaltmonat ist, das mit der Methode  | 
 |  |  |    * zuTagen(jahr, monat, tag) in ein generisches Datum  | 
 |  |  |    * umgerechnet werden soll. | 
 |  |  |    *  | 
 |  |  |    * Diese Methode ist eine Hilfsfunktion, wenn nicht die Methode  | 
 |  |  |    * zuTagen(zyklus, jahr, monat, schaltmonat, tag) genutzt werden kann. | 
 |  |  |    *  | 
 |  |  |    * @param schaltmonat  | 
 |  |  |    */ | 
 |  |  |   public void setSchaltmonat(boolean schaltmonat) { | 
 |  |  |     this.schaltmonat = schaltmonat; | 
 |  |  |   } | 
 |  |  |    | 
 |  |  |   /** | 
 |  |  |    * Die Anzahl der Tage ermitteln, die zwischen einem gegebenen Datum  | 
 |  |  |    * des chinesischen Kalenders und dem Tag liegen, der im | 
 |  |  |    * Gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist. | 
 |  |  |    *  | 
 |  |  |    * @param zyklus der Zyklus des chinesischen Kalenders | 
 |  |  |    * @param jahr  das Jahr des chinesischen Kalenders | 
 |  |  |    * @param monat  der Monat des chinesischen Kalenders | 
 |  |  |    * @param schaltmonat true, wenn der Monat ein Schaltmonat ist, sonst false | 
 |  |  |    * @param tag Tag im Monat des chinesischen Kalenders | 
 |  |  |    *  | 
 |  |  |    * @return Anzahl Tage, die zwischen dem gegebenen Datum  | 
 |  |  |    * des chinesischen Kalenders und dem Tag liegen, der im  | 
 |  |  |    * Gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist.  | 
 |  |  |    * Liegt das gegebene Datum vor dem 1. Januar 1 (gregorianisch), wird  | 
 |  |  |    * eine negative Zahl zurueckgegeben.  | 
 |  |  |    */ | 
 |  |  |     public long zuTagen(long zyklus, int jahr, int monat, boolean schaltmonat, int tag) { | 
 |  |  |     this.zyklus = zyklus; | 
 |  |  |     this.schaltmonat = schaltmonat; | 
 |  |  |     return zuTagen(jahr, monat, tag); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |   /** | 
 |  |  |    * Die Anzahl der Tage ermitteln, die zwischen einem gegebenen Datum  | 
 |  |  |    * des chinesischen Kalenders und dem Tag liegen, der im | 
 |  |  |    * Gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist. | 
 |  |  |    *  | 
 |  |  |    * Bei Verwendung dieser Methode muessen zuvor die Methode setZyklus  | 
 |  |  |    * und setSchaltmonat genutzt werden. | 
 |  |  |    *  | 
 |  |  |    * @param jahr das Jahr im betreffenden Kalendersystem | 
 |  |  |    * @param monat der Monat im betreffenden Kalendersystem | 
 |  |  |    * @param tag der Tag im betreffenden Kalendersysem | 
 |  |  |    *  | 
 |  |  |    * @return Anzahl Tage, die zwischen dem gegebenen Datum  | 
 |  |  |    * des chinesischen Kalenders  und dem Tag liegen, der im  | 
 |  |  |    * Gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist.  | 
 |  |  |    * Liegt das gegebene Datum vor dem 1. Januar 1 (gregorianisch), wird  | 
 |  |  |    * eine negative Zahl zurueckgegeben.  | 
 |  |  |    */   | 
 |  |  |   @Override | 
 |  |  |   public long zuTagen(long jahr, int monat, int tag) {     | 
 |  |  |         long midYear = (long)Math.floor(STARTTAG + ((zyklus - 1) * 60 + (jahr - 1) + .5) * MITTLERES_TROPISCHES_JAHR); | 
 |  |  | 
 |  |  |         return priorNewMoon + tag - 1; | 
 |  |  |   } | 
 |  |  |  | 
 |  |  |   /** | 
 |  |  |    * Die Anzahl der Tage ermitteln, die zwischen einem gegebenen Datum  | 
 |  |  |    * des chinesischen Kalenders und dem Tag liegen, der im | 
 |  |  |    * Gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist. | 
 |  |  |    *  | 
 |  |  |    * @param d das Datum im betreffenden Kalendersystem | 
 |  |  |    *  | 
 |  |  |    * @return Anzahl Tage, die zwischen dem gegebenen Datum  | 
 |  |  |    * des chinesischen Kalenders und dem Tag liegen, der im  | 
 |  |  |    * Gregorianischen Kalender mit dem Datum 1. Januar 1 bezeichnet ist.  | 
 |  |  |    * Liegt das gegebene Datum vor dem 1. Januar 1 (gregorianisch), wird  | 
 |  |  |    * eine negative Zahl zurueckgegeben.  | 
 |  |  |    */   | 
 |  |  |   @Override | 
 |  |  |   public long zuTagen(Datum d) { | 
 |  |  |     if(d instanceof ChinesischesDatum) { | 
 |  |  | 
 |  |  |     } | 
 |  |  |   } | 
 |  |  |  | 
 |  |  |   /** | 
 |  |  |    * Das Datum des chinesischen Kalenders fuer ein generisches Datum  | 
 |  |  |    * ermitteln. | 
 |  |  |    *  | 
 |  |  |    * @param tage Anzahl der Tage zwischen 1. Januar 1 im gregorianischen  | 
 |  |  |    * Kalender und dem Tag, dessen Datum des chinesischen Kalenders  | 
 |  |  |    * ermittelt werden soll | 
 |  |  |    * @return das Datum im chinesischen Kalender | 
 |  |  |    */ | 
 |  |  |   @Override | 
 |  |  |   public ChinesischesDatum vonTagen(long tage) { | 
 |  |  |         long s1 = winterSonnenwendeAmOderVor(tage); | 
 |  |  | 
 |  |  |     return new ChinesischesDatum(cycle, year, month, leapMonth, day); | 
 |  |  |   } | 
 |  |  |    | 
 |  |  |   /* ---- */ | 
 |  |  |    | 
 |  |  |     public boolean hatSchaltmonatVorher(long mPrime, long m) { | 
 |  |  |         return m >= mPrime && (keinSolarerHauptabschnitt(m) || hatSchaltmonatVorher(mPrime, chinesischerNeumondVor(m))); | 
 |  |  |     } | 
 |  |  | 	 | 
 |  |  |     public double mitternachtInChina(long date) { | 
 |  |  |         return universalVonStandard(date, chinesischerOrt(date)); | 
 |  |  |     } | 
 |  |  | 	 | 
 |  |  |     public final Ort peking(double tee) { | 
 |  |  |     public long neujahr(long isoJahr) { | 
 |  |  |     ISOKalender g = new ISOKalender(); | 
 |  |  |         long year = g.jahrVonTagen((long)Math.floor(tee)); | 
 |  |  |         return neujahrAmOderVor(g.zuTagen(isoJahr, Definition.JULI, 1)); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public long qingMing(long isoJahr) { | 
 |  |  |     ISOKalender g = new ISOKalender(); | 
 |  |  |         return (long)Math.floor(solarerNebenabschnittAmOderNach(g.zuTagen(isoJahr, Definition.MAERZ, 30))); | 
 |  |  |     } | 
 |  |  |    | 
 |  |  |   /** | 
 |  |  |    * Das generische Datum des Tages mit einem gegebenen festen Datum  | 
 |  |  |    * im chinesischen Kalender fuer ein gegebenes gregorianisches Jahr  | 
 |  |  |    * ermitteln | 
 |  |  |    *  | 
 |  |  |    * @param isoJahr Jahr im gregorischen Kalender, in das ein gesuchtes Ereignis faellt | 
 |  |  |    * @param cMonat Monat im chinesischen Kalender, an dem das Ereignis stattfindet | 
 |  |  |    * @param cTag  Tag im Monat des chinesischen Kalenders, an dem das Ereignis stattfindet | 
 |  |  |    * @return generisches Datum des Ereignisses | 
 |  |  |    */ | 
 |  |  |     public long cDatumZuTagen(long isoJahr, int cMonat, int cTag) { | 
 |  |  |     ISOKalender g = new ISOKalender(); | 
 |  |  |         long elapsedYears = isoJahr - g.jahrVonTagen(STARTTAG) + 1; | 
 |  |  |         long cycle = ganzzahlQuotient(elapsedYears - 1, 60) + 1; | 
 |  |  |         int year = (int)moduloAngepasst(elapsedYears, 60); | 
 |  |  |         return zuTagen(cycle, year, cMonat, false, cTag); | 
 |  |  |     } | 
 |  |  | 	 | 
 |  |  |   /* ---- Hilfsfunktionen --------- */ | 
 |  |  |    | 
 |  |  |     public boolean hatSchaltmonatVorher(long mHaupt, long m) { | 
 |  |  |         return m >= mHaupt && (keinSolarerHauptabschnitt(m) || hatSchaltmonatVorher(mHaupt, chinesischerNeumondVor(m))); | 
 |  |  |     } | 
 |  |  | 	 | 
 |  |  |     public double mitternachtInChina(long tage) { | 
 |  |  |         return universalVonStandard(tage, chinesischerOrt(tage)); | 
 |  |  |     } | 
 |  |  | 	 | 
 |  |  |     public final Ort peking(double t) { | 
 |  |  |     ISOKalender g = new ISOKalender(); | 
 |  |  |         long year = g.jahrVonTagen((long)Math.floor(t)); | 
 |  |  |         return new Ort("Peking", (double) (39.55), winkel(116,25,0),  | 
 |  |  |             (double) (43.5), year < 1929 ? 1397d/180 : 8); | 
 |  |  |     } | 
 |  |  |      | 
 |  |  |     public final Ort chinesischerOrt(double tee) { | 
 |  |  |         return peking(tee); | 
 |  |  |     public final Ort chinesischerOrt(double t) { | 
 |  |  |         return peking(t); | 
 |  |  |     } | 
 |  |  |      | 
 |  |  |     public long neujahrAmOderVor(long tage) { | 
 |  |  | 
 |  |  |         long s2 = winterSonnenwendeAmOderVor(s1 + 370); | 
 |  |  |         long m12 = chinesischerNeumondAmOderNach(s1 + 1); | 
 |  |  |         long m13 = chinesischerNeumondAmOderNach(m12 + 1); | 
 |  |  |         long nextM11 = chinesischerNeumondVor(s2 + 1); | 
 |  |  |         if((Math.round((nextM11 - m12) / MITTLERER_SYNODISCHER_MONAT) == 12) && (keinSolarerHauptabschnitt(m12) || keinSolarerHauptabschnitt(m13))) { | 
 |  |  |         long naechsterM11 = chinesischerNeumondVor(s2 + 1); | 
 |  |  |         if((Math.round((naechsterM11 - m12) / MITTLERER_SYNODISCHER_MONAT) == 12) && (keinSolarerHauptabschnitt(m12) || keinSolarerHauptabschnitt(m13))) { | 
 |  |  |             return chinesischerNeumondAmOderNach(m13 + 1); | 
 |  |  |         } else { | 
 |  |  |             return m13; | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public long neujahr(long gYear) { | 
 |  |  |     ISOKalender g = new ISOKalender(); | 
 |  |  |         return neujahrAmOderVor(g.zuTagen(gYear, Definition.JULI, 1)); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public long qingMing(long gYear) { | 
 |  |  |     ISOKalender g = new ISOKalender(); | 
 |  |  |         return (long)Math.floor(solarerNebenabschnittAmOderNach(g.zuTagen(gYear, Definition.MAERZ, 30))); | 
 |  |  |     } | 
 |  |  |    | 
 |  |  |     public long cDatumZuGenerisch(long isoJahr, int cMonat, int cTag) { | 
 |  |  |     ISOKalender g = new ISOKalender(); | 
 |  |  |         long elapsedYears = isoJahr - g.jahrVonTagen(STARTTAG) + 1; | 
 |  |  |         long cycle = ganzzahlQuotient(elapsedYears - 1, 60) + 1; | 
 |  |  |         int year = (int)moduloAngepasst(elapsedYears, 60); | 
 |  |  |         return zuTagen(cycle, year, cMonat, false, cTag); | 
 |  |  |     } | 
 |  |  | 	 | 
 |  |  |     public long winterSonnenwendeAmOderVor(long date) { | 
 |  |  |         double approx = geschaetzteSolareLaengeVor(mitternachtInChina(date + 1), Definition.WINTER); | 
 |  |  |     public long winterSonnenwendeAmOderVor(long tage) { | 
 |  |  |         double approx = geschaetzteSolareLaengeVor(mitternachtInChina(tage + 1), Definition.WINTER); | 
 |  |  |         long i; | 
 |  |  |         for(i = (long)(Math.floor(approx) - 1); !(Definition.WINTER <= solareLaenge(mitternachtInChina(i + 1))); ++i); | 
 |  |  |         return i; | 
 |  |  |     } | 
 |  |  |        | 
 |  |  |     public boolean keinSolarerHauptabschnitt(long date) { | 
 |  |  |         return aktuellerSolarerHauptabschnitt(date) == | 
 |  |  |             aktuellerSolarerHauptabschnitt(chinesischerNeumondAmOderNach(date + 1)); | 
 |  |  |     public boolean keinSolarerHauptabschnitt(long tage) { | 
 |  |  |         return aktuellerSolarerHauptabschnitt(tage) == | 
 |  |  |             aktuellerSolarerHauptabschnitt(chinesischerNeumondAmOderNach(tage + 1)); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public int aktuellerSolarerHauptabschnitt(long date) { | 
 |  |  |         double s = solareLaenge(standardVonUniversal(date, chinesischerOrt(date))); | 
 |  |  |     public int aktuellerSolarerHauptabschnitt(long tage) { | 
 |  |  |         double s = solareLaenge(standardVonUniversal(tage, chinesischerOrt(tage))); | 
 |  |  |         return (int)moduloAngepasst(2 + ganzzahlQuotient(s, (double) (30)), 12); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public double solarerHauptabschnittAmOderNach(long date) { | 
 |  |  |         double l = modulo(30 * Math.ceil(solareLaenge(mitternachtInChina(date)) / 30), 360); | 
 |  |  |         return chinesischeSolareLaengeAmOderNach(date, l); | 
 |  |  |     public double solarerHauptabschnittAmOderNach(long tage) { | 
 |  |  |         double l = modulo(30 * Math.ceil(solareLaenge(mitternachtInChina(tage)) / 30), 360); | 
 |  |  |         return chinesischeSolareLaengeAmOderNach(tage, l); | 
 |  |  |     } | 
 |  |  |    | 
 |  |  |     public double solarerNebenabschnittAmOderNach(long date) { | 
 |  |  |         double l = modulo(30 * Math.ceil((solareLaenge(mitternachtInChina(date)) - (double) (15)) / 30) + (double) (15), 360); | 
 |  |  |         return chinesischeSolareLaengeAmOderNach(date, l); | 
 |  |  |     public double solarerNebenabschnittAmOderNach(long tage) { | 
 |  |  |         double l = modulo(30 * Math.ceil((solareLaenge(mitternachtInChina(tage)) - (double) (15)) / 30) + (double) (15), 360); | 
 |  |  |         return chinesischeSolareLaengeAmOderNach(tage, l); | 
 |  |  |     } | 
 |  |  |      | 
 |  |  |     public double chinesischeSolareLaengeAmOderNach(long date, double theta) { | 
 |  |  |         Ort beijing = chinesischerOrt(date); | 
 |  |  |         double tee = solareLaengeNach(standardVonUniversal(date, beijing), theta); | 
 |  |  |         return standardVonUniversal(tee, beijing); | 
 |  |  |     public double chinesischeSolareLaengeAmOderNach(long tage, double theta) { | 
 |  |  |         Ort peking = chinesischerOrt(tage); | 
 |  |  |         double t = solareLaengeNach(standardVonUniversal(tage, peking), theta); | 
 |  |  |         return standardVonUniversal(t, peking); | 
 |  |  |     } | 
 |  |  |      | 
 |  |  |     public int aktuellerSolarerUnterabschnitt(long date) { | 
 |  |  |         double s = solareLaenge(mitternachtInChina(date)); | 
 |  |  |     public int aktuellerSolarerUnterabschnitt(long tage) { | 
 |  |  |         double s = solareLaenge(mitternachtInChina(tage)); | 
 |  |  |         return (int)moduloAngepasst(3 + ganzzahlQuotient(s - (double) (15), (double) (30)), 12); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public long chinesischerNeumondAmOderNach(long date) { | 
 |  |  |         double t = neumondNach(mitternachtInChina(date)); | 
 |  |  |     public long chinesischerNeumondAmOderNach(long tage) { | 
 |  |  |         double t = neumondNach(mitternachtInChina(tage)); | 
 |  |  |         return (long)Math.floor(standardVonUniversal(t, chinesischerOrt(t))); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public long chinesischerNeumondVor(long date) { | 
 |  |  |     double t = neumondVor((long) mitternachtInChina(date)); | 
 |  |  |     public long chinesischerNeumondVor(long tage) { | 
 |  |  |     double t = neumondVor((long) mitternachtInChina(tage)); | 
 |  |  |         return (long)Math.floor(standardVonUniversal(t, chinesischerOrt(t))); | 
 |  |  |     } | 
 |  |  | } |