KDE Core/Astronomical Calendars/Chinese: Difference between revisions
Yuvrajtoamr (talk | contribs) (Created page with "== Introduction == The Chinese calendar is a lunisolar calendar, as it uses months to approximate the tropical year. By the modern definition, the tropical year has been defined ...") |
Yuvrajtoamr (talk | contribs) |
||
(18 intermediate revisions by the same user not shown) | |||
Line 94: | Line 94: | ||
== The Year == | == The Year == | ||
Chinese Calendar = solar calendar + lunisolar calendar | '''Chinese Calendar = solar calendar + lunisolar calendar''' | ||
The solar calendar starts at the December Solstice and follows the 24 solar terms. It is known as sui. The lunisolar calendar starts at the Chinese New Year and it consists of 12 or 13 months. It is called nian. The solar calendar follows the tropical year more closely than the lunisolar calendar,. The solar year has a fixed length whereas the length of the lunisolar year is variable. An important rule in implementing the Chinese calendar is the definition of the leap month. The rule followed is: | The solar calendar starts at the December Solstice and follows the 24 solar terms. It is known as sui. The lunisolar calendar starts at the Chinese New Year and it consists of 12 or 13 months. It is called nian. The solar calendar follows the tropical year more closely than the lunisolar calendar,. The solar year has a fixed length whereas the length of the lunisolar year is variable. An important rule in implementing the Chinese calendar is the definition of the leap month. The rule followed is: | ||
*December solstice falls in month 11. A sui is a leap sui if there are 12 complete months between the two 11th months at the beginning and the end of the sui. | *December solstice falls in month 11. A sui is a leap sui if there are 12 complete months between the two 11th months at the beginning and the end of the sui. | ||
Line 110: | Line 111: | ||
#Xingqi Liu (Weekday Six) | #Xingqi Liu (Weekday Six) | ||
#Xingqi Tian (Sun Day) | #Xingqi Tian (Sun Day) | ||
== Research Sources == | |||
The research has been documented from the following sources, namely: | |||
#Calendrical Calculations: Third Edition - Nachum Dershowitz and Edward M. Reingold | |||
#Notes and Errata on Calendrical Calculations: Third Edition - 25th May 2011 | |||
#Astronomical Algorithms: First Edition - Jean Meeus | |||
#Practical Astronomy with your Calculator: Third Edition - Peter Duffet-Smith | |||
#How to compute planetary positions - Paul Schlyter | |||
#Mathematics of Chinese Calendar - Helmer Aslaksen | |||
== Astro Library == | |||
Most of the astronomical functions have already been described in the implementation of Chinese Calendar. A few functions were appended to the [http://community.kde.org/KDE_Core/Astronomical_Calendars/Islamic#Astro_Library previously described] Astro Library, namely: | |||
===astro.h=== | |||
====int roundOff(double value)==== | |||
Rounds off the double value to the integer value | |||
===astrolunar.h=== | |||
====double newMoonBefore(double time)==== | |||
Returns the moment of a New Moon occurrence before the given ''time'' | |||
====double newMoonAtOrAfter(double time)==== | |||
Returns the moment of a New Moon occurrence at or after the given ''time'' | |||
===astrosolar.h=== | |||
====double estimatePriorSolarLongitude(double longitude, double time)==== | |||
This function has an important role to play in implementing astronomical solar calendars, as it determines a particular solar longitude on or before the given date. The solar longitude can correspondingly help to find the day of the New Year as per the astronomical calendar. | |||
==KCalendarSystem API== | |||
To implement the Chinese calendar, certain changes had to be made in the KCalendar System API in order to incorporate features requiring leap months, namely: | |||
===QString monthName(double month, int year, MonthNameFormat format = LongName)=== | |||
Gets specific calendar type month for a given date. The monthName() method is overloaded to use a double type value of the month returned by calculations. | |||
===bool julianDayToDate(int jd, int &year, double &month, double &day) const=== | |||
Method to convert Julian day to calendar specific date. | |||
===bool dateToJulianDay(int year, double month, double day, int &jd) const=== | |||
Method to convert calendar specific date to Julian day. | |||
===int daysInMonth(int year, double month) const=== | |||
Returns the number of days in that month of the year. The double data type implements functionalities for leap months. | |||
== The Chinese Calendar == | |||
The header file defining the implementation of Chinese Lunisolar Calendar is kcalendarsystemchinese.h. It has defined two classes: | |||
=== KCalendarSystemChinese === | |||
Class definition in the public domain, publicly inherited from KCalendarSystem. It re-implements the virtual functions defined in the KCalendarSystem class. The re-implemented functions are defined in the public domain of the class. | |||
====virtual QString calendarType() const==== | |||
Returns the calendar system type. | |||
====virtual QDate epoch() const==== | |||
Returns a QDate holding the epoch of the calendar system. Chinese epoch is defined on Julian Day 758326. (8th March 2637 BCE in Julian Calendar) | |||
====virtual QDate earliestValidDate() const==== | |||
Returns the earliest date valid in this calendar system implementation, i.e. the epoch of the calendar system as the Chinese calendar is not proleptic. | |||
====virtual QDate latestValidDate() const==== | |||
Returns the latest date valid in this calendar system implementation, i.e. 30th December 9999 in Chinese Calendar (which becomes 5th February 7303 in Gregorian Calendar). | |||
====virtual bool isValid(int year, int month, int day) const==== | |||
Returns whether a given date is valid in this calendar system. | |||
====virtual bool isValid(const QDate &date) const==== | |||
Returns whether a given date is valid in this calendar system. | |||
====virtual bool isLeapYear(int year) const==== | |||
Returns whether a given year is a leap year. | |||
====virtual bool isLeapYear(const QDate &date) const==== | |||
Returns whether a given year(taken from the QDate) is a leap year. | |||
====virtual QString monthName(double month, int year, MonthNameFormat format = LongName) const==== | |||
Gets specific calendar type month name for a given month number If an invalid month is specified, QString() is returned. The double data type is used to incorporate functionalities requiring leap months. | |||
====virtual QString monthName(const QDate &date, MonthNameFormat format = LongName) const==== | |||
Gets specific calendar type month name for a given date. | |||
====virtual QString weekDayName(int weekDay, WeekDayNameFormat format = LongDayName) const==== | |||
Gets specific calendar type week day name. If an invalid week day is specified, QString() is returned. | |||
====virtual QString weekDayName(const QDate &date, WeekDayNameFormat format = LongDayName) const==== | |||
Gets specific calendar type week day name. | |||
====virtual int weekDayOfPray() const==== | |||
Returns the weekday of pray for this calendar system, i.e. Sunday (7th day of the Chinese Week). | |||
====virtual bool isLunar() const==== | |||
Returns whether the calendar is lunar. (False) | |||
====virtual bool isLunisolar() const==== | |||
Returns whether the calendar is lunisolar. (True) | |||
====virtual bool isSolar() const==== | |||
Returns whether the calendar is solar. (False) | |||
====virtual bool isProleptic() const==== | |||
Returns whether the calendar is proleptic, i.e, supports dates before the epoch. (False) | |||
=== KCalendarSystemChinesePrivate === | |||
Class definition in the private domain, publicy inherited from KCalendarSystemPrivate. It re-implements the virtual functions defined in the KCalendarSystem class. The re-implemented functions are defined in the public domain of the class. | |||
====virtual AstroLocale* chineseLocation(int date)==== | |||
Defines the Chinese Locale(as explained in the previous section) for implementing the Chinese Calendar | |||
====double midnightInChina(int date)==== | |||
Computes the Chinese Universal Time for implementing astronomical calculations | |||
====int currentMajorSolarTerm(int date)==== | |||
Returns the major solar term number at the given date, after computing the solar longitude at the given date. | |||
====int winterSolsticeOnOrAfter(int date)==== | |||
Returns the date of December Solstice on or after the given date. | |||
====int chineseNewMoonOnOrAfter(int date)==== | |||
Returns the date when the New Moon is observed at the Chinese Locale on or after the given date. | |||
====int chineseNewMoonBefore(int date)==== | |||
Returns the date when the New Moon is observed at the Chinese Locale before the given date. | |||
====bool noMajorSolarTerm(int date)==== | |||
Checks whether the month containing the given date has a major solar term or not. | |||
====bool priorLeapMonth(int m1, int m2)==== | |||
Checks whether there is a leap month from the date m1(inclusive) to date m2. | |||
====int newYearInSui(int date)==== | |||
Returns the starting date of Chinese New Year after December Solstice. | |||
====int newYearOnOrBefore(int date)==== | |||
Returns the date of Chinese New Year on or before the given date. | |||
====void chineseDateToJulianDay(int year, double month, bool leap, int day, int &jd)==== | |||
Converts Chinese date to Julian day. | |||
====void julianDayToChineseDate(int &year, double &month, bool &leap, int &day, int jd)==== | |||
Converts Julian day to Chinese date. | |||
====virtual KLocale::CalendarSystem calendarSystem() const==== | |||
Returns the calendar type. | |||
====virtual int monthsInYear(int year) const==== | |||
Returns the number of months in the year used by this calendar system. | |||
====virtual int daysInMonth(int year, double month) const==== | |||
Returns the number of days in a month used by this calendar system. The double data type implements functionalities for leap months. | |||
====virtual int daysInYear(int year) const==== | |||
Returns the number of days in a year used by this calendar system. | |||
====virtual int daysInWeek() const==== | |||
Returns the number of days in a week used by this calendar system, i.e, 7. | |||
====virtual bool isLeapYear(int year) const==== | |||
Checks whether a year is a leap year or not. | |||
====virtual bool hasLeapMonths() const==== | |||
Returns true is this calendar system has leap months. The Chinese calendar has leap months. | |||
====virtual bool hasYearZero() const==== | |||
Returns true is this calendar system uses year 0. The Chinese calendar doesn't have a year 0. | |||
====virtual int maxDaysInWeek() const==== | |||
Returns the maximum number of days in a week in this calendar system, i.e, 7. | |||
====virtual int maxMonthsInYear() const==== | |||
Returns the maximum number of months in a year in this calendar system, i.e. 13. | |||
====virtual int earliestValidYear() const==== | |||
Returns the earliest valid year in this calendar system, i.e., year 1. | |||
====virtual int latestValidYear() const==== | |||
Returns the latest valid year in this calendar system, i.e., year 9999. | |||
====virtual QString monthName(double month, int year, Locale::DateTimeComponentFormat format, bool possessive) const==== | |||
Gets specific calendar type month name for a given month number If an invalid month is specified, QString() is returned. | |||
====virtual QString weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const==== | |||
Gets specific calendar type weekday name for a given month number If an invalid weekday is specified, QString() is returned. | |||
=== Astronomical Implementation === | |||
Re-implementations of the functions dateToJulianDay() and julianDayToDate() using the functions defined in the Astro Library. | |||
====bool julianDayToDate(int jd, int &year, double &month, double &day) const==== | |||
Returns the date implemented in this calendar system from Julian day. It implements the previously defined ''julianDayToChineseDate()'' function. | |||
====bool dateToJulianDay(int &jd, int year, double month, double day) const==== | |||
Returns the Julian day from the date in this calendar system. It implements the previously defined ''chineseDateToJulianDay()'' function. | |||
The calculations for implementing the Chinese Calendar have been derived from the public domain Lisp code/Mathematical functions of ''Calendrical Calculations'' by Edward M. Reingold on the Illinois Institute of Technology website, and from the book ''Astronomical Algorithms'' by Jean Meeus |
Latest revision as of 17:13, 16 August 2011
Introduction
The Chinese calendar is a lunisolar calendar, as it uses months to approximate the tropical year. By the modern definition, the tropical year has been defined as the time taken by the Sun's mean longitude to increase by 360 degrees. The Chinese lunar calendar is followed by many Asian countries like Japan, Vietnam and Korea. Similar to the Islamic Calendar, 12 synodic months fall short by 11 days to the tropical year. However, instead of using a leap year to compensate for this difference, the Chinese use 'leap months' in about every third year to maintain the synchronization with the tropical year. A more predictable method to get the insertion of leap months is to follow the Metonic Cycle according to which 235 synodic months are equal to 19 tropical years (with a difference of only two hours). To break this down in calendar arithmetics:
- 235 = 19x12 + 7
Therefore, 7 leap months are inserted in a period of 19 years. More details about the leap months have been mentioned in the forthcoming sections.
Despite the controversial debates going on between the Chinese calendar epoch, in our calculations we have been defined the Chinese epoch as March 8, 2637 BCE. There have been various controversies regarding the selection of the Chinese epoch. Scholars have claimed that the calendar was invented during the reign of Yellow Emperor Huangdi, which began in 2697 BCE. The debate is that some scholars claim that the year was invented in the first year of his reign (2697 BCE) while others claim that the year was invented in the 61st year of his reign (2637 BCE). There have been more than 50 calendar reforms in the Chinese calendar since its inception.
The Solar Terms
The Chinese astronomers use 24 solar nodes(solar terms) which correspond to significant events in the Chinese culture. Seasonal markers cut the ecliptic in 4 sections of 90degrees each. Solar terms cut the ecliptic in 24 sections of 15degrees each. The even terms are called the major solar terms or Zhongqi and the odd ones are called minor solar terms of Jieqi.
Ecliptic longitude | Chinese name | Approx Gregorian date | Translation |
---|---|---|---|
315° | lichun | February 4 | start of spring |
330° | yushui | February 19 | rain water |
345° | jingzhe | March 5 | insects awaken |
0° | chunfen | March 20 | vernal equinox |
15° | qingming | April 5 | clear and bright |
30° | guyu | April 20 | grain rains |
45° | lixia | May 6 | start of summer |
60° | xiaoman | May 21 | grain full |
75° | mangzhong | June 6 | grain in ear |
90° | xiazhi | June 21 | summer solstice |
105° | xiaoshu | July 7 | minor heat |
120° | dashu | July 23 | major heat |
135° | liqiu | August 7 | start of autumn |
150° | chushu | August 23 | limit of heat |
165° | bailu | September 8 | white dew |
180° | qiufen | September 23 | autumnal equinox |
195° | hanlu | October 8 | cold dew |
210° | shuangjiang | October 23 | descent of frost |
225° | lidong | November 7 | start of winter |
240° | xiaoxue | November 22 | minor snow |
255° | daxue | December 7 | major snow |
270° | dongzhi | December 22 | winter solstice |
285° | xiaohan | January 6 | minor cold |
300° | dahan | January 20 | major cold |
The Month
The Chinese system of 12 double hours starts at 11pm. This has a significant role to play in Chinese astrology. The new moon marks the beginning of the new Chinese month. Regarding the calculations based on locale, before 1929 the calculations of the Chinese astronomy were based on the meridian in Beijing(39.9167degrees, 116.4167degrees); but in 1928, China adopted the standard time zone of 120degrees longitude which is close to the republican capital Nanjing. There are a variety of series for naming months, such as flowers, numbers, etc.
# | Corresponding to Zodiac Sign | Solar Longitude | Corresponding to Flowers |
---|---|---|---|
1 | 正月 zhengyue | 330° | 正月Primens |
2 | 二月 eryue | 0° | 杏月 Apricomens |
3 | 三月 sanyue | 30° | 桃月 Peacimens |
4 | 四月 siyue | 60° | 梅月 Plumens |
5 | 五月 wuyue | 90° | 榴月 Guavamens |
6 | 六月 liuyue | 120° | 荷月 Lotumens |
7 | 七月 qiyue | 150° | 蘭月 Orchimens |
8 | 八月 bayue | 180° | 桂月 Osmanthumens |
9 | 九月 jiuyue | 210° | 菊月 Chrysanthemens |
10 | 十月 shiyue | 240° | 良月 Benimens |
11 | 十一月 shiyiyue | 270° | 冬月 Hiemens |
12 | 十二月 shieryue | 300° | 臘月 Ultimens |
The Year
Chinese Calendar = solar calendar + lunisolar calendar
The solar calendar starts at the December Solstice and follows the 24 solar terms. It is known as sui. The lunisolar calendar starts at the Chinese New Year and it consists of 12 or 13 months. It is called nian. The solar calendar follows the tropical year more closely than the lunisolar calendar,. The solar year has a fixed length whereas the length of the lunisolar year is variable. An important rule in implementing the Chinese calendar is the definition of the leap month. The rule followed is:
- December solstice falls in month 11. A sui is a leap sui if there are 12 complete months between the two 11th months at the beginning and the end of the sui.
- In a leap sui, the first month that does not contain a major solar term is the leap month.
- Leap months take the same number as the preceding month, and a prefix "Leap (閏)" before the number.
The Week
The modern Chinese calendar follows a 7-day week with Monday of the Gregorian Calendar being the first day of the week. The weekdays are named in pinyin as:
- Xingqi Yi (Weekday One)
- Xingqi Er (Weekday Two)
- Xingqi San(Weekday Three)
- Xingqi Si (Weekday Four)
- Xingqi Wu (Weekday Five)
- Xingqi Liu (Weekday Six)
- Xingqi Tian (Sun Day)
Research Sources
The research has been documented from the following sources, namely:
- Calendrical Calculations: Third Edition - Nachum Dershowitz and Edward M. Reingold
- Notes and Errata on Calendrical Calculations: Third Edition - 25th May 2011
- Astronomical Algorithms: First Edition - Jean Meeus
- Practical Astronomy with your Calculator: Third Edition - Peter Duffet-Smith
- How to compute planetary positions - Paul Schlyter
- Mathematics of Chinese Calendar - Helmer Aslaksen
Astro Library
Most of the astronomical functions have already been described in the implementation of Chinese Calendar. A few functions were appended to the previously described Astro Library, namely:
astro.h
int roundOff(double value)
Rounds off the double value to the integer value
astrolunar.h
double newMoonBefore(double time)
Returns the moment of a New Moon occurrence before the given time
double newMoonAtOrAfter(double time)
Returns the moment of a New Moon occurrence at or after the given time
astrosolar.h
double estimatePriorSolarLongitude(double longitude, double time)
This function has an important role to play in implementing astronomical solar calendars, as it determines a particular solar longitude on or before the given date. The solar longitude can correspondingly help to find the day of the New Year as per the astronomical calendar.
KCalendarSystem API
To implement the Chinese calendar, certain changes had to be made in the KCalendar System API in order to incorporate features requiring leap months, namely:
QString monthName(double month, int year, MonthNameFormat format = LongName)
Gets specific calendar type month for a given date. The monthName() method is overloaded to use a double type value of the month returned by calculations.
bool julianDayToDate(int jd, int &year, double &month, double &day) const
Method to convert Julian day to calendar specific date.
bool dateToJulianDay(int year, double month, double day, int &jd) const
Method to convert calendar specific date to Julian day.
int daysInMonth(int year, double month) const
Returns the number of days in that month of the year. The double data type implements functionalities for leap months.
The Chinese Calendar
The header file defining the implementation of Chinese Lunisolar Calendar is kcalendarsystemchinese.h. It has defined two classes:
KCalendarSystemChinese
Class definition in the public domain, publicly inherited from KCalendarSystem. It re-implements the virtual functions defined in the KCalendarSystem class. The re-implemented functions are defined in the public domain of the class.
virtual QString calendarType() const
Returns the calendar system type.
virtual QDate epoch() const
Returns a QDate holding the epoch of the calendar system. Chinese epoch is defined on Julian Day 758326. (8th March 2637 BCE in Julian Calendar)
virtual QDate earliestValidDate() const
Returns the earliest date valid in this calendar system implementation, i.e. the epoch of the calendar system as the Chinese calendar is not proleptic.
virtual QDate latestValidDate() const
Returns the latest date valid in this calendar system implementation, i.e. 30th December 9999 in Chinese Calendar (which becomes 5th February 7303 in Gregorian Calendar).
virtual bool isValid(int year, int month, int day) const
Returns whether a given date is valid in this calendar system.
virtual bool isValid(const QDate &date) const
Returns whether a given date is valid in this calendar system.
virtual bool isLeapYear(int year) const
Returns whether a given year is a leap year.
virtual bool isLeapYear(const QDate &date) const
Returns whether a given year(taken from the QDate) is a leap year.
virtual QString monthName(double month, int year, MonthNameFormat format = LongName) const
Gets specific calendar type month name for a given month number If an invalid month is specified, QString() is returned. The double data type is used to incorporate functionalities requiring leap months.
virtual QString monthName(const QDate &date, MonthNameFormat format = LongName) const
Gets specific calendar type month name for a given date.
virtual QString weekDayName(int weekDay, WeekDayNameFormat format = LongDayName) const
Gets specific calendar type week day name. If an invalid week day is specified, QString() is returned.
virtual QString weekDayName(const QDate &date, WeekDayNameFormat format = LongDayName) const
Gets specific calendar type week day name.
virtual int weekDayOfPray() const
Returns the weekday of pray for this calendar system, i.e. Sunday (7th day of the Chinese Week).
virtual bool isLunar() const
Returns whether the calendar is lunar. (False)
virtual bool isLunisolar() const
Returns whether the calendar is lunisolar. (True)
virtual bool isSolar() const
Returns whether the calendar is solar. (False)
virtual bool isProleptic() const
Returns whether the calendar is proleptic, i.e, supports dates before the epoch. (False)
KCalendarSystemChinesePrivate
Class definition in the private domain, publicy inherited from KCalendarSystemPrivate. It re-implements the virtual functions defined in the KCalendarSystem class. The re-implemented functions are defined in the public domain of the class.
virtual AstroLocale* chineseLocation(int date)
Defines the Chinese Locale(as explained in the previous section) for implementing the Chinese Calendar
double midnightInChina(int date)
Computes the Chinese Universal Time for implementing astronomical calculations
int currentMajorSolarTerm(int date)
Returns the major solar term number at the given date, after computing the solar longitude at the given date.
int winterSolsticeOnOrAfter(int date)
Returns the date of December Solstice on or after the given date.
int chineseNewMoonOnOrAfter(int date)
Returns the date when the New Moon is observed at the Chinese Locale on or after the given date.
int chineseNewMoonBefore(int date)
Returns the date when the New Moon is observed at the Chinese Locale before the given date.
bool noMajorSolarTerm(int date)
Checks whether the month containing the given date has a major solar term or not.
bool priorLeapMonth(int m1, int m2)
Checks whether there is a leap month from the date m1(inclusive) to date m2.
int newYearInSui(int date)
Returns the starting date of Chinese New Year after December Solstice.
int newYearOnOrBefore(int date)
Returns the date of Chinese New Year on or before the given date.
void chineseDateToJulianDay(int year, double month, bool leap, int day, int &jd)
Converts Chinese date to Julian day.
void julianDayToChineseDate(int &year, double &month, bool &leap, int &day, int jd)
Converts Julian day to Chinese date.
virtual KLocale::CalendarSystem calendarSystem() const
Returns the calendar type.
virtual int monthsInYear(int year) const
Returns the number of months in the year used by this calendar system.
virtual int daysInMonth(int year, double month) const
Returns the number of days in a month used by this calendar system. The double data type implements functionalities for leap months.
virtual int daysInYear(int year) const
Returns the number of days in a year used by this calendar system.
virtual int daysInWeek() const
Returns the number of days in a week used by this calendar system, i.e, 7.
virtual bool isLeapYear(int year) const
Checks whether a year is a leap year or not.
virtual bool hasLeapMonths() const
Returns true is this calendar system has leap months. The Chinese calendar has leap months.
virtual bool hasYearZero() const
Returns true is this calendar system uses year 0. The Chinese calendar doesn't have a year 0.
virtual int maxDaysInWeek() const
Returns the maximum number of days in a week in this calendar system, i.e, 7.
virtual int maxMonthsInYear() const
Returns the maximum number of months in a year in this calendar system, i.e. 13.
virtual int earliestValidYear() const
Returns the earliest valid year in this calendar system, i.e., year 1.
virtual int latestValidYear() const
Returns the latest valid year in this calendar system, i.e., year 9999.
virtual QString monthName(double month, int year, Locale::DateTimeComponentFormat format, bool possessive) const
Gets specific calendar type month name for a given month number If an invalid month is specified, QString() is returned.
virtual QString weekDayName(int weekDay, KLocale::DateTimeComponentFormat format) const
Gets specific calendar type weekday name for a given month number If an invalid weekday is specified, QString() is returned.
Astronomical Implementation
Re-implementations of the functions dateToJulianDay() and julianDayToDate() using the functions defined in the Astro Library.
bool julianDayToDate(int jd, int &year, double &month, double &day) const
Returns the date implemented in this calendar system from Julian day. It implements the previously defined julianDayToChineseDate() function.
bool dateToJulianDay(int &jd, int year, double month, double day) const
Returns the Julian day from the date in this calendar system. It implements the previously defined chineseDateToJulianDay() function.
The calculations for implementing the Chinese Calendar have been derived from the public domain Lisp code/Mathematical functions of Calendrical Calculations by Edward M. Reingold on the Illinois Institute of Technology website, and from the book Astronomical Algorithms by Jean Meeus