- 浏览: 40846 次
- 性别:
- 来自: 北京
最新评论
一、基本知识
二十四节气起源于黄河流域。远在春秋时代,就定出仲春、仲夏、仲秋和仲冬等四个节气。以后不断地改进与完善,到秦汉年间,二十四节气已完全确立。公元前104年,由邓平等制定的《太初历》,正式把二十四节气订于历法,明确了二十四节气的天文位置。
太阳从黄经零度起,沿黄经每运行15度所经历的时日称为“一个节气”。每年运行360度,共经历24个节气,每月2个。其中,每月第一个节气为“节气”,即:立春、惊蛰、清明、立夏、芒种、小暑、立秋、白露、寒露、立冬、大雪和小寒等12个节气;每月的第二个节气为“中气”,即:雨水、春分、谷雨、小满、夏至、大暑、处暑、秋分、霜降、小雪、冬至和大寒等12个节气。“节气” 和“中气”交替出现,各历时15天,现在人们已经把“节气”和“中气”统称为“节气”。
二十四节气反映了太阳的周年视运动,所以节气在现行的公历中日期基本固定,上半年在6日、21日,下半年在8日、23日,前后不差1~2天。
二、基本概念
儒略日:Julian Day number 或 Julian Day 或 JD。是指从公元前 4712 年开始连续计算日数得出的天数及不满一日的尾数。传统上儒略日的计数是从格林尼治平午,即世界时间 12 点开始的。
格里历:即公历或格列高利历,是现行国际通行的历法,属于阳历的一种,通称阳历,其前身是奥古斯都历,而奥古斯都历的前身是儒略历。其历年为一个回归年(365.2425日),划分为12个历月。是教皇格里高利13世(也译格雷果里)在公元1582年改革儒略历制定的历法,儒略历的回归年为365.25,与实际的回归365.2422相差甚多,当时儒略历和地球实际位置的误差已达14天,格里历将误差纠正,确定所有整数世纪年除了可被400整除的外一律不设闰年,同时规定1582年10月4日之后的那天为1582年10月15日,但原有星期不变。新颁布的历法理论上可以达到两万年内误差不超过一天,但由于地球自转的变化,实际到公元4909年误差就可达一天。与儒略历相比,公历是新制定的历法,所以有时候,包括中华民国《中国国家标准》CNS 7648《数据元及交换格式–信息交换–日期及时间的表示法》,又称新历。
黄经:地球绕太阳运转一周约365天5小时多,运转94,000万公里。地球的公转在地球上人看来就表现为太阳周年视运动,其运行线路(即地球公转轨道在天球上的反映)称为黄道。黄经就是黄道上的度量坐标(经度),按天文学惯例,以春分点为起点自西向东度量,分360度。我国古人把太阳黄经的360度划分成24等份,每份15度,为一个节气。两个节气间相隔日数为15天左右,全年即有二十四节气。二十四节气的太阳黄经度分别为:立春315度,雨水330度,惊蛰345度,春分360度,清明15度,谷雨30度,立夏45度,小满60度,芒种75度,夏至90度,小暑105度,大暑120度,立秋135度,处暑150度,白露165度,秋分180度,寒露195度,霜降210度,立冬225度,小雪240度,大雪255度,冬至270度,小寒285度,大寒300度。
黄纬:黄道上的纬度。
三、基本算法:
3.1:儒略日的计算(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
// ------------------------------------------------------------------------
//
// 儒略日转换为格历日
//
// dbGD[IN]:儒略日
// year[OUT]:年
// month[OUT]:月
// day[OUT]:日
// hour[OUT]:时
// minute[OUT]:分
// second[OUT]:秒
// ------------------------------------------------------------------------
void w_JDToGD(const double &dbJD, int &year, int &month, int &day, int &hour, int &minute, int &second)
{
double dJDM = dbJD + 0.5;
unsigned long ulZ = static_cast<unsigned long>(floor(dJDM));
double dF = dJDM - floor(dJDM);
unsigned long ulA, ulB, ulC, ulD;
int nE, nQ;
if (dbJD < 2299161)
ulA = ulZ;
else
{
nQ = static_cast<int>((ulZ - 1867216.25) / 36524.25);
ulA = ulZ + 1 + nQ - static_cast<int>(nQ >> 2);
}
ulB = ulA + 1524 ;
ulC = static_cast<int>(( ulB - 122.1) / 365.25);
ulD = static_cast<int>(365.25 * ulC);
nE = static_cast<int>((ulB - ulD) / 30.6001);
// 计算日
day = ulB - ulD - int ( 30.6001 * nE ) ;
// 计算时
hour = static_cast<int>(floor(dF * 24.0));
// 计算分
minute = static_cast<int>(((dF * 24.0) - floor(dF * 24.0)) * 60.0);
// 计算秒
second = static_cast<int>((((dF * 24.0) * 60.0) - floor(( dF * 24.0) * 60.0)) * 60.0);
// 计算月
if(nE < 14)
month = nE - 1;
if(nE == 14 || nE == 15)
month = nE - 13;
// 计算年
if(month > 2)
year = ulC - 4716;
if(month == 1 || month == 2)
year = ulC - 4715;
}
// ------------------------------------------------------------------------
//
// 格历日转换为儒略日
//
// year[IN]:年
// month[IN]:月
// day[IN]:日
// hour[IN]:时
// minute[IN]:分
// second[IN]:秒
//
// 返回对应的儒略日
// ------------------------------------------------------------------------
double w_GDToJD(const int &year, const int &month, const int &day, const int &hour, const int &minute, const int &second)
{
int nY = year, nM = month;
double dD = static_cast<double>(day) + hour / 24.0 + (minute / 60.0) / 24.0 + ((second / 60.0) / 60.0) / 24.0;
if(month == 1 || month == 2)
{
nY = year - 1;
nM = month + 12;
}
int nA = nY / 100;
int nB = 2 - nA + (nA >> 2);
return static_cast<double>(static_cast<int>(365.25 * (nY + 4716)) + static_cast<int>(30.6001 * (nM + 1)) + dD + nB - 1524.5);
}
3.2、角度调整
// ------------------------------------------------------------------------
//
// 调整角度到 0-360 之间
//
// dbDegrees[IN]:角度
//
// 返回调整后的角度
// ------------------------------------------------------------------------
double w_MapTo0To360Range(const double &dbDegrees)
{
double dbValue = dbDegrees;
// map it to the range 0 - 360
while(dbValue < 0.0)
dbValue += 360.0;
while(dbValue > 360.0)
dbValue -= 360.0;
return dbValue;
}
四、步骤简述
4.1、按照 5.2 和 5.3 节介绍方法计算出某一时刻太阳黄经和黄纬。
4.2、按照 5.4 、5.5、5.6 节介绍的三次校正方法对黄经进行校正,即可求得某时刻太阳黄经度数。
4.3、综合步骤演示在第 六 节。
4.4、第 七 节演示如何使用二分法求指定节气的时间。
4.5、第 八 节介绍了 本地时间(LST)和格林尼治时间(UTC)之间互换的函数。
4.6、第 九 节罗列出了本代码计算出的 2008年24节气时间(北京时间)
五、太阳黄经、黄纬、向量半径以及校正量的计算
5.1、为了代码可读性,定义类型变量。
//
// 圆周率
const double PI = 3.1415926535897932384626433832795;
//
// 一度代表的弧度
const double dbUnitRadian = PI / 180.0;
//
// 计算太阳黄经赤纬所需类型变量
typedef struct
{
double dA;
double dB;
double dC;
} VSOP87COEFFICIENT, *PVSOP87COEFFICIENT
// 二次修正黄经赤纬所需的天体章动系数类型变量
typedef struct
{
int nD;
int nM;
int nMprime;
int nF;
int nOmega;
int nSincoeff1;
double dSincoeff2;
int nCoscoeff1;
double dCoscoeff2;
} NUTATIONCOEFFICIENT, *PNUTATIONCOEFFICIENT;
//
// 节气枚举
enum SOLARTERMS
{
ST_VERNAL_EQUINOX = 0, // 春分
ST_CLEAR_AND_BRIGHT = 15, // 清明
ST_GRAIN_RAIN = 30, // 谷雨
ST_SUMMER_BEGINS = 45, // 立夏
ST_GRAIN_BUDS = 60, // 小满
ST_GRAIN_IN_EAR = 75, // 芒种
ST_SUMMER_SOLSTICE = 90, // 夏至
ST_SLIGHT_HEAT = 105, // 小暑
ST_GREAT_HEAT = 120, // 大暑
ST_AUTUMN_BEGINS = 135, // 立秋
ST_STOPPING_THE_HEAT = 150, // 处暑
ST_WHITE_DEWS = 165, // 白露
ST_AUTUMN_EQUINOX = 180, // 秋分
ST_COLD_DEWS = 195, // 寒露
ST_HOAR_FROST_FALLS = 210, // 霜降
ST_WINTER_BEGINS = 225, // 立冬
ST_LIGHT_SNOW = 240, // 小雪
ST_HEAVY_SNOW = 255, // 大雪
ST_WINTER_SOLSTICE = 270, // 冬至
ST_SLIGHT_COLD = 285, // 小寒
ST_GREAT_COLD = 300, // 大寒
ST_SPRING_BEGINS = 315, // 立春
ST_THE_RAINS = 330, // 雨水
ST_INSECTS_AWAKEN = 345 // 惊蛰
};
5.2、黄经:(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
//
// 计算太阳黄经用参数
const VSOP87COEFFICIENT Earth_SLG0[64] =
{
{ 175347046.0 , 0.0000000 , 000000.0000000 } ,
{ 3341656.0 , 4.6692568 , 6283.0758500 } ,
{ 34894.0 , 4.6261000 , 12566.1517000 } ,
{ 3497.0 , 2.7441000 , 5753.3849000 } ,
{ 3418.0 , 2.8289000 , 3.5231000 } ,
{ 3136.0 , 3.6277000 , 77713.7715000 } ,
{ 2676.0 , 4.4181000 , 7860.4194000 } ,
{ 2343.0 , 6.1352000 , 3930.2097000 } ,
{ 1324.0 , 0.7425000 , 11506.7698000 } ,
{ 1273.0 , 2.0371000 , 529.6910000 } ,
{ 1199.0 , 1.1096000 , 1577.3435000 } ,
{ 990.0 , 5.2330000 , 5884.9270000 } ,
{ 902.0 , 2.0450000 , 26.2980000 } ,
{ 857.0 , 3.5080000 , 398.1490000 } ,
{ 780.0 , 1.1790000 , 5223.6940000 } ,
{ 753.0 , 2.5330000 , 5507.5530000 } ,
{ 505.0 , 4.5830000 , 18849.2280000 } ,
{ 492.0 , 4.2050000 , 775.5230000 } ,
{ 357.0 , 2.9200000 , 000000.0670000 } ,
{ 317.0 , 5.8490000 , 11790.6290000 } ,
{ 284.0 , 1.8990000 , 796.2880000 } ,
{ 271.0 , 0.3150000 , 10977.0790000 } ,
{ 243.0 , 0.3450000 , 5486.7780000 } ,
{ 206.0 , 4.8060000 , 2544.3140000 } ,
{ 205.0 , 1.8690000 , 5573.1430000 } ,
{ 202.0 , 2.4580000 , 6069.7770000 } ,
{ 156.0 , 0.8330000 , 213.2990000 } ,
{ 132.0 , 3.4110000 , 2942.4630000 } ,
{ 126.0 , 1.0830000 , 20.7750000 } ,
{ 115.0 , 0.6450000 , 000000.9800000 } ,
{ 103.0 , 0.6360000 , 4694.0030000 } ,
{ 102.0 , 0.9760000 , 15720.8390000 } ,
{ 102.0 , 4.2670000 , 7.1140000 } ,
{ 99.0 , 6.2100000 , 2146.1700000 } ,
{ 98.0 , 0.6800000 , 155.4200000 } ,
{ 86.0 , 5.9800000 , 161000.6900000 } ,
{ 85.0 , 1.3000000 , 6275.9600000 } ,
{ 85.0 , 3.6700000 , 71430.7000000 } ,
{ 80.0 , 1.8100000 , 17260.1500000 } ,
{ 79.0 , 3.0400000 , 12036.4600000 } ,
{ 75.0 , 1.7600000 , 5088.6300000 } ,
{ 74.0 , 3.5000000 , 3154.6900000 } ,
{ 74.0 , 4.6800000 , 801.8200000 } ,
{ 70.0 , 0.8300000 , 9437.7600000 } ,
{ 62.0 , 3.9800000 , 8827.3900000 } ,
{ 61.0 , 1.8200000 , 7084.9000000 } ,
{ 57.0 , 2.7800000 , 6286.6000000 } ,
{ 56.0 , 4.3900000 , 14143.5000000 } ,
{ 56.0 , 3.4700000 , 6279.5500000 } ,
{ 52.0 , 0.1900000 , 12139.5500000 } ,
{ 52.0 , 1.3300000 , 1748.0200000 } ,
{ 51.0 , 0.2800000 , 5856.4800000 } ,
{ 49.0 , 0.4900000 , 1194.4500000 } ,
{ 41.0 , 5.3700000 , 8429.2400000 } ,
{ 41.0 , 2.4000000 , 19651.0500000 } ,
{ 39.0 , 6.1700000 , 10447.3900000 } ,
{ 37.0 , 6.0400000 , 10213.2900000 } ,
{ 37.0 , 2.5700000 , 1059.3800000 } ,
{ 36.0 , 1.7100000 , 2352.8700000 } ,
{ 36.0 , 1.7800000 , 6812.7700000 } ,
{ 33.0 , 0.5900000 , 17789.8500000 } ,
{ 30.0 , 0.4400000 , 83996.8500000 } ,
{ 30.0 , 2.7400000 , 1349.8700000 } ,
{ 25.0 , 3.1600000 , 4690.4800000 }
};
const VSOP87COEFFICIENT Earth_SLG1[34] =
{
{ 628331966747.0 , 0.000000 , 00000.0000000 } ,
{ 206059.0 , 2.678235 , 6283.0758500 } ,
{ 4303.0 , 2.635100 , 12566.1517000 } ,
{ 425.0 , 1.590000 , 3.5230000 } ,
{ 119.0 , 5.796000 , 26.2980000 } ,
{ 109.0 , 2.966000 , 1577.3440000 } ,
{ 93.0 , 2.590000 , 18849.2300000 } ,
{ 72.0 , 1.140000 , 529.6900000 } ,
{ 68.0 , 1.870000 , 398.1500000 } ,
{ 67.0 , 4.410000 , 5507.5500000 } ,
{ 59.0 , 2.890000 , 5223.6900000 } ,
{ 56.0 , 2.170000 , 155.4200000 } ,
{ 45.0 , 0.400000 , 796.3000000 } ,
{ 36.0 , 0.470000 , 775.5200000 } ,
{ 29.0 , 2.650000 , 7.1100000 } ,
{ 21.0 , 5.430000 , 00000.9800000 } ,
{ 19.0 , 1.850000 , 5486.7800000 } ,
{ 19.0 , 4.970000 , 213.3000000 } ,
{ 17.0 , 2.990000 , 6275.9600000 } ,
{ 16.0 , 0.030000 , 2544.3100000 } ,
{ 16.0 , 1.430000 , 2146.1700000 } ,
{ 15.0 , 1.210000 , 10977.0800000 } ,
{ 12.0 , 2.830000 , 1748.0200000 } ,
{ 12.0 , 3.260000 , 5088.6300000 } ,
{ 12.0 , 5.270000 , 1194.4500000 } ,
{ 12.0 , 2.080000 , 4694.0000000 } ,
{ 11.0 , 0.770000 , 553.5700000 } ,
{ 10.0 , 1.300000 , 6286.6000000 } ,
{ 10.0 , 4.240000 , 1349.8700000 } ,
{ 9.0 , 2.700000 , 242.7300000 } ,
{ 9.0 , 5.640000 , 951.7200000 } ,
{ 8.0 , 5.300000 , 2352.8700000 } ,
{ 6.0 , 2.650000 , 9437.7600000 } ,
{ 6.0 , 4.670000 , 4690.4800000 }
};
const VSOP87COEFFICIENT Earth_SLG2[20] =
{
{ 52919.0 , 0.0000 , 00000.0000 } ,
{ 8720.0 , 1.0721 , 6283.0758 } ,
{ 309.0 , 0.8670 , 12566.1520 } ,
{ 27.0 , 0.0500 , 3.5200 } ,
{ 16.0 , 5.1900 , 26.3000 } ,
{ 16.0 , 3.6800 , 155.4200 } ,
{ 10.0 , 0.7600 , 18849.2300 } ,
{ 9.0 , 2.0600 , 77713.7700 } ,
{ 7.0 , 0.8300 , 775.5200 } ,
{ 5.0 , 4.6600 , 1577.3400 } ,
{ 4.0 , 1.0300 , 7.1100 } ,
{ 4.0 , 3.4400 , 5573.1400 } ,
{ 3.0 , 5.1400 , 796.3000 } ,
{ 3.0 , 6.0500 , 5507.5500 } ,
{ 3.0 , 1.1900 , 242.7300 } ,
{ 3.0 , 6.1200 , 529.6900 } ,
{ 3.0 , 0.3100 , 398.1500 } ,
{ 3.0 , 2.2800 , 553.5700 } ,
{ 2.0 , 4.3800 , 5223.6900 } ,
{ 2.0 , 3.7500 , 00000.9800 }
};
const VSOP87COEFFICIENT Earth_SLG3[ 7] =
{
{ 289.0 , 5.844 , 6283.076 } ,
{ 35.0 , 0.000 , 00000.000 } ,
{ 17.0 , 5.490 , 12566.150 } ,
{ 3.0 , 5.200 , 155.420 } ,
{ 1.0 , 4.720 , 3.520 } ,
{ 1.0 , 5.300 , 18849.230 } ,
{ 1.0 , 5.970 , 242.730 }
};
const VSOP87COEFFICIENT Earth_SLG4[ 3] =
{
{ 114.0 , 3.142 , 00000.00 } ,
{ 8.0 , 4.130 , 6283.08 } ,
{ 1.0 , 3.840 , 12566.15 }
};
const VSOP87COEFFICIENT Earth_SLG5[ 1] =
{
{ 1.0 , 3.14 , 0.0 }
};
// ------------------------------------------------------------------------
//
// 计算太阳在黄道面上的经度(单位:度)
//
// dbJD[IN]:儒略日(计算该时刻太阳在黄道面上的经度)
//
// 返回太阳黄经度数
// ------------------------------------------------------------------------
double w_GetSunLongitude(const double & dbJD)
{
// 计算τ
double dt = (dbJD - 2451545.0) / 365250.0;
double dL = 0.0, dL0 = 0.0, dL1 = 0.0, dL2 = 0.0, dL3 = 0.0, dL4 = 0.0, dL5 = 0.0;
// L0 38x3
for(int i = 0; i < sizeof(Earth_SLG0) / sizeof(VSOP87COEFFICIENT); i++)
dL0 += (Earth_SLG0[i].dA * cos((Earth_SLG0[i].dB + Earth_SLG0[i].dC * dt)));
// L1 16x3
for(int i = 0; i < sizeof(Earth_SLG1) / sizeof(VSOP87COEFFICIENT); i++)
dL1 += (Earth_SLG1[i].dA * cos((Earth_SLG1[i].dB + Earth_SLG1[i].dC * dt)));
// L2 10x3
for(int i = 0; i < sizeof(Earth_SLG2) / sizeof(VSOP87COEFFICIENT); i++)
dL2 += (Earth_SLG2[i].dA * cos((Earth_SLG2[i].dB + Earth_SLG2[i].dC * dt)));
// L3 8x3
for(int i = 0; i < sizeof(Earth_SLG3) / sizeof(VSOP87COEFFICIENT); i++)
dL3 += (Earth_SLG3[i].dA * cos((Earth_SLG3[i].dB + Earth_SLG3[i].dC * dt)));
// L4 6x3
for(int i = 0; i < sizeof(Earth_SLG4) / sizeof(VSOP87COEFFICIENT); i++)
dL4 += (Earth_SLG4[i].dA * cos((Earth_SLG4[i].dB + Earth_SLG4[i].dC * dt)));
// L5 1x3
for(int i = 0; i < sizeof(Earth_SLG5) / sizeof(VSOP87COEFFICIENT); i++)
dL5 += (Earth_SLG5[i].dA * cos((Earth_SLG5[i].dB + Earth_SLG5[i].dC * dt)));
// 计算 L = ( L0 + L1 * τ^1 + L2 * τ^2 + L3 * τ^3 + L4 * τ^4 + L5 * τ^5 ) / 10^8 ;(单位弧度)
dL = (dL0 + (dL1 * dt) + (dL2 * (dt * dt)) + (dL3 * (dt * dt * dt)) * (dL4 * (dt * dt * dt * dt)) + (dL5 * (dt * dt * dt * dt * dt))) / 100000000.0;
// 转化为度θ = L + 180 (单位度);
return (w_MapTo0To360Range(w_MapTo0To360Range(dL / dbUnitRadian) + 180.0));
}
5.3、黄纬:(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
//
// 计算太阳黄纬用参数
const VSOP87COEFFICIENT Earth_SLT0[ 5] =
{
{ 280.0 , 3.199 , 84334.662 } ,
{ 102.0 , 5.422 , 5507.553 } ,
{ 80.0 , 3.880 , 5223.690 } ,
{ 44.0 , 3.700 , 2352.870 } ,
{ 32.0 , 4.000 , 1577.340 }
};
const VSOP87COEFFICIENT Earth_SLT1[ 2] =
{
{ 9.0 , 3.90 , 5507.55 } ,
{ 6.0 , 1.73 , 5223.69 }
};
const VSOP87COEFFICIENT Earth_SLT2[ 4] =
{
{ 22378.0 , 3.38509 , 10213.28555 } ,
{ 282.0 , 0.00000 , 00000.00000 } ,
{ 173.0 , 5.25600 , 20426.57100 } ,
{ 27.0 , 3.87000 , 30639.86000 }
};
const VSOP87COEFFICIENT Earth_SLT3[ 4] =
{
{ 647.0 , 4.992 , 10213.286 } ,
{ 20.0 , 3.140 , 00000.000 } ,
{ 6.0 , 0.770 , 20426.570 } ,
{ 3.0 , 5.440 , 30639.860 }
};
const VSOP87COEFFICIENT CWDCalendarEngine::Earth_SLT4[ 1] =
{
{ 14.0 , 0.32 , 10213.29 }
};
// ------------------------------------------------------------------------
//
// 计算太阳在黄道面上的纬度(单位:度)
//
// dbJD[IN]:儒略日(计算该时刻太阳在黄道面上的纬度)
//
// 返回太阳黄纬度数
// ------------------------------------------------------------------------
double w_GetSunLatitude(const double & dbJD)
{
// 计算τ
double dbt = (dbJD - 2451545.0) / 365250.0;
double dbB = 0.0, dbB0 = 0.0, dbB1 = 0.0, dbB2 = 0.0, dbB3 = 0.0, dbB4 = 0.0;
// B0 5x3
for(int i = 0; i < sizeof(Earth_SLT0) / sizeof(VSOP87COEFFICIENT); i++)
dbB0 += (Earth_SLT0[i].dA * cos((Earth_SLT0[i].dB + Earth_SLT0[i].dC * dbt)));
// B1 2x3
for(int i = 0; i < sizeof(Earth_SLT1) / sizeof(VSOP87COEFFICIENT); i++)
dbB1 += (Earth_SLT1[i].dA * cos((Earth_SLT1[i].dB + Earth_SLT1[i].dC * dbt)));
// B2 4x3
for(int i = 0; i < sizeof(Earth_SLT2) / sizeof(VSOP87COEFFICIENT); i++)
dbB2 += (Earth_SLT2[i].dA * cos((Earth_SLT2[i].dB + Earth_SLT2[i].dC * dbt)));
// B3 4x3
for(int i = 0; i < sizeof(Earth_SLT3) / sizeof(VSOP87COEFFICIENT); i++)
dbB3 += (Earth_SLT3[i].dA * cos((Earth_SLT3[i].dB + Earth_SLT3[i].dC * dbt)));
// B4 1x3
for(int i = 0; i < sizeof(Earth_SLT4) / sizeof(VSOP87COEFFICIENT); i++)
dbB4 += (Earth_SLT4[i].dA * cos((Earth_SLT4[i].dB + Earth_SLT4[i].dC * dbt)));
// 计算 B = ( B0 + B1 * τ^1 + B2 * τ^2 + B3 * τ^3 + B4 * τ^4 ) / 10^8 ;(单位弧度)
dbB = (dbB0 + (dbB1 * dbt) + (dbB2 * (dbt * dbt)) + (dbB3 * (dbt * dbt * dbt)) * (dbB4 * (dbt * dbt * dbt * dbt))) / 100000000.0;
// 计算 θ(单位度);
return -(dbB / dbUnitRadian);
}
5.4、第一次校正黄经:(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
// ------------------------------------------------------------------------
//
// 修正某时刻太阳在黄道上的经度(黄经)
//
// dbSrcLongitude[IN]:黄经
// dbSrcLatitude[IN]:黄纬
// dbJD[IN]:儒略日(修正在该时刻太阳的黄经)
//
// 返回太阳黄经度数
// ------------------------------------------------------------------------
double w_CorrectionCalcSunLongitude(const double &dbSrcLongitude, const double &dbSrcLatitude, const double &dbJD)
{
double dbT = (dbJD - 2451545.0) / 36525.0;
double dbLdash = dbSrcLongitude - 1.397 * dbT - 0.00031 * dbT * dbT;
// 转换为弧度
dbLdash *= dbUnitRadian;
return (-0.09033 + 0.03916 * (cos(dbLdash) + sin(dbLdash)) * tan(dbSrcLatitude * dbUnitRadian)) / 3600.0;
}
5.5、第二次校正黄经(章动):(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
//
// 二次修正黄经黄纬所需的天体章动系数
const NUTATIONCOEFFICIENT Nutation_Gene[63] =
{
{ 0, 0, 0, 0, 1, -171996, -174.2, 92025, 8.9 },
{ -2, 0, 0, 2, 2, -13187, -1.6, 5736, -3.1 },
{ 0, 0, 0, 2, 2, -2274, -0.2, 977, -0.5 },
{ 0, 0, 0, 0, 2, 2062, 0.2, -895, 0.5 },
{ 0, 1, 0, 0, 0, 1426, -3.4, 54, -0.1 },
{ 0, 0, 1, 0, 0, 712, 0.1, -7, 0 },
{ -2, 1, 0, 2, 2, -517, 1.2, 224, -0.6 },
{ 0, 0, 0, 2, 1, -386, -0.4, 200, 0 },
{ 0, 0, 1, 2, 2, -301, 0, 129, -0.1 },
{ -2, -1, 0, 2, 2, 217, -0.5, -95, 0.3 },
{ -2, 0, 1, 0, 0, -158, 0, 0, 0 },
{ -2, 0, 0, 2, 1, 129, 0.1, -70, 0 },
{ 0, 0, -1, 2, 2, 123, 0, -53, 0 },
{ 2, 0, 0, 0, 0, 63, 0, 0, 0 },
{ 0, 0, 1, 0, 1, 63, 0.1, -33, 0 },
{ 2, 0, -1, 2, 2, -59, 0, 26, 0 },
{ 0, 0, -1, 0, 1, -58, -0.1, 32, 0 },
{ 0, 0, 1, 2, 1, -51, 0, 27, 0 },
{ -2, 0, 2, 0, 0, 48, 0, 0, 0 },
{ 0, 0, -2, 2, 1, 46, 0, -24, 0 },
{ 2, 0, 0, 2, 2, -38, 0, 16, 0 },
{ 0, 0, 2, 2, 2, -31, 0, 13, 0 },
{ 0, 0, 2, 0, 0, 29, 0, 0, 0 },
{ -2, 0, 1, 2, 2, 29, 0, -12, 0 },
{ 0, 0, 0, 2, 0, 26, 0, 0, 0 },
{ -2, 0, 0, 2, 0, -22, 0, 0, 0 },
{ 0, 0, -1, 2, 1, 21, 0, -10, 0 },
{ 0, 2, 0, 0, 0, 17, -0.1, 0, 0 },
{ 2, 0, -1, 0, 1, 16, 0, -8, 0 },
{ -2, 2, 0, 2, 2, -16, 0.1, 7, 0 },
{ 0, 1, 0, 0, 1, -15, 0, 9, 0 },
{ -2, 0, 1, 0, 1, -13, 0, 7, 0 },
{ 0, -1, 0, 0, 1, -12, 0, 6, 0 },
{ 0, 0, 2,-2, 0, 11, 0, 0, 0 },
{ 2, 0, -1, 2, 1, -10, 0, 5, 0 },
{ 2, 0, 1, 2, 2, -8, 0, 3, 0 },
{ 0, 1, 0, 2, 2, 7, 0, -3, 0 },
{ -2, 1, 1, 0, 0, -7, 0, 0, 0 },
{ 0, -1, 0, 2, 2, -7, 0, 3, 0 },
{ 2, 0, 0, 2, 1, -7, 0, 3, 0 },
{ 2, 0, 1, 0, 0, 6, 0, 0, 0 },
{ -2, 0, 2, 2, 2, 6, 0, -3, 0 },
{ -2, 0, 1, 2, 1, 6, 0, -3, 0 },
{ 2, 0, -2, 0, 1, -6, 0, 3, 0 },
{ 2, 0, 0, 0, 1, -6, 0, 3, 0 },
{ 0, -1, 1, 0, 0, 5, 0, 0, 0 },
{ -2, -1, 0, 2, 1, -5, 0, 3, 0 },
{ -2, 0, 0, 0, 1, -5, 0, 3, 0 },
{ 0, 0, 2, 2, 1, -5, 0, 3, 0 },
{ -2, 0, 2, 0, 1, 4, 0, 0, 0 },
{ -2, 1, 0, 2, 1, 4, 0, 0, 0 },
{ 0, 0, 1,-2, 0, 4, 0, 0, 0 },
{ -1, 0, 1, 0, 0, -4, 0, 0, 0 },
{ -2, 1, 0, 0, 0, -4, 0, 0, 0 },
{ 1, 0, 0, 0, 0, -4, 0, 0, 0 },
{ 0, 0, 1, 2, 0, 3, 0, 0, 0 },
{ 0, 0, -2, 2, 2, -3, 0, 0, 0 },
{ -1, -1, 1, 0, 0, -3, 0, 0, 0 },
{ 0, 1, 1, 0, 0, -3, 0, 0, 0 },
{ 0, -1, 1, 2, 2, -3, 0, 0, 0 },
{ 2, -1, -1, 2, 2, -3, 0, 0, 0 },
{ 0, 0, 3, 2, 2, -3, 0, 0, 0 },
{ 2, -1, 0, 2, 2, -3, 0, 0, 0 }
};
// ------------------------------------------------------------------------
//
// 计算天体章动
// 二次修正某时刻太阳在黄道上的纬度(单位:度)
// 使用天体章动系数修正,消除扰动影响
//
// dbJD[IN]:儒略日(计算该时刻天体章动补偿量)
//
// 返回天体扰动干扰量
// ------------------------------------------------------------------------
double w_GetNutationJamScalar(const double &dbJD)
{
double dbT = (dbJD - 2451545.0) / 36525.0;
double dbTsquared = dbT * dbT;
double dbTcubed = dbTsquared * dbT;
double dbD = 297.85036 + 445267.111480 * dbT - 0.0019142 * dbTsquared + dbTcubed / 189474.0;
dbD = w_MapTo0To360Range(dbD);
double dbM = 357.52772 + 35999.050340 * dbT - 0.0001603 * dbTsquared - dbTcubed / 300000.0;
dbM = w_MapTo0To360Range(dbM);
double dbMprime = 134.96298 + 477198.867398 * dbT + 0.0086972 * dbTsquared + dbTcubed / 56250.0;
dbMprime = w_MapTo0To360Range(dbMprime);
double dbF = 93.27191 + 483202.017538 * dbT - 0.0036825 * dbTsquared + dbTcubed / 327270.0;
dbF = w_MapTo0To360Range(dbF);
double dbOmega = 125.04452 - 1934.136261 * dbT + 0.0020708 * dbTsquared + dbTcubed / 450000.0;
dbOmega = w_MapTo0To360Range(dbOmega);
double dbResulte = 0.0 ;
for(int i = 0; i < sizeof(Nutation_Gene) / sizeof(NUTATIONCOEFFICIENT); i++)
{
double dbRadargument = (Nutation_Gene[i].nD * dbD + Nutation_Gene[i].nM * dbM + Nutation_Gene[i].nMprime * dbMprime + Nutation_Gene[i].nF * dbF + Nutation_Gene[i].nOmega * dbOmega) * dbUnitRadian;
dbResulte += (Nutation_Gene[i].nSincoeff1 + Nutation_Gene[i].dSincoeff2 * dbT ) * sin(dbRadargument) * 0.0001;
}
return dbResulte;
}
5.6、第三次校正黄经(太阳半径向量):(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
//
// 计算太阳向量半径用参数
const VSOP87COEFFICIENT Earth_SRV0[40] =
{
{ 100013989 , 0 , 0 },
{ 1670700 , 3.0984635 , 6283.0758500 },
{ 13956 , 3.05525 , 12566.15170 },
{ 3084 , 5.1985 , 77713.7715 },
{ 1628 , 1.1739 , 5753.3849 },
{ 1576 , 2.8469 , 7860.4194 },
{ 925 , 5.453 , 11506.770 },
{ 542 , 4.564 , 3930.210 },
{ 472 , 3.661 , 5884.927 },
{ 346 , 0.964 , 5507.553 },
{ 329 , 5.900 , 5223.694 },
{ 307 , 0.299 , 5573.143 },
{ 243 , 4.273 , 11790.629 },
{ 212 , 5.847 , 1577.344 },
{ 186 , 5.022 , 10977.079 },
{ 175 , 3.012 , 18849.228 },
{ 110 , 5.055 , 5486.778 },
{ 98 , 0.89 , 6069.78 },
{ 86 , 5.69 , 15720.84 },
{ 86 , 1.27 , 161000.69 },
{ 65 , 0.27 , 17260.15 },
{ 63 , 0.92 , 529.69 },
{ 57 , 2.01 , 83996.85 },
{ 56 , 5.24 , 71430.70 },
{ 49 , 3.25 , 2544.31 },
{ 47 , 2.58 , 775.52 },
{ 45 , 5.54 , 9437.76 },
{ 43 , 6.01 , 6275.96 },
{ 39 , 5.36 , 4694.00 },
{ 38 , 2.39 , 8827.39 },
{ 37 , 0.83 , 19651.05 },
{ 37 , 4.90 , 12139.55 },
{ 36 , 1.67 , 12036.46 },
{ 35 , 1.84 , 2942.46 },
{ 33 , 0.24 , 7084.90 },
{ 32 , 0.18 , 5088.63 },
{ 32 , 1.78 , 398.15 },
{ 28 , 1.21 , 6286.60 },
{ 28 , 1.90 , 6279.55 },
{ 26 , 4.59 , 10447.39 }
};
const VSOP87COEFFICIENT Earth_SRV1[10] =
{
{ 103019 , 1.107490 , 6283.075850 },
{ 1721 , 1.0644 , 12566.1517 },
{ 702 , 3.142 , 0 },
{ 32 , 1.02 , 18849.23 },
{ 31 , 2.84 , 5507.55 },
{ 25 , 1.32 , 5223.69 },
{ 18 , 1.42 , 1577.34 },
{ 10 , 5.91 , 10977.08 },
{ 9 , 1.42 , 6275.96 },
{ 9 , 0.27 , 5486.78 }
};
const VSOP87COEFFICIENT Earth_SRV2[ 6] =
{
{ 4359 , 5.7846 , 6283.0758 },
{ 124 , 5.579 , 12566.152 },
{ 12 , 3.14 , 0 },
{ 9 , 3.63 , 77713.77 },
{ 6 , 1.87 , 5573.14 },
{ 3 , 5.47 , 18849.23 }
};
const VSOP87COEFFICIENT Earth_SRV3[ 2] =
{
{ 145 , 4.273 , 6283.076 },
{ 7 , 3.92 , 12566.15 }
};
const VSOP87COEFFICIENT Earth_SRV4[ 1] =
{
{ 4 , 2.56 , 6283.08 }
};
// ------------------------------------------------------------------------
//
// 计算某时刻太阳半径向量
// 三次修正某时刻太阳在黄道上的经度(单位:弧度)
//
// dbJD[IN]:儒略日(计算该时刻太阳半径向量)
//
// 返回太阳半径向量
// ------------------------------------------------------------------------
double w_GetSunRadiusVector(const double &dbJD)
{
// 计算τ
double dbt = (dbJD - 2451545.0) / 365250.0;
double dbR = 0.0, dbR0 = 0.0, dbR1 = 0.0, dbR2 = 0.0, dbR3 = 0.0, dbR4 = 0.0;
// R0 40x3
for(int i = 0; i < sizeof(Earth_SRV0) / sizeof(VSOP87COEFFICIENT); i++)
dbR0 += (Earth_SRV0[i].dA * cos((Earth_SRV0[i].dB + Earth_SRV0[i].dC * dbt)));
// R1 10x3
for(int i = 0; i < sizeof(Earth_SRV1) / sizeof(VSOP87COEFFICIENT); i++)
dbR1 += (Earth_SRV1[i].dA * cos((Earth_SRV1[i].dB + Earth_SRV1[i].dC * dbt)));
// R2 6x3
for(int i = 0; i < sizeof(Earth_SRV2) / sizeof(VSOP87COEFFICIENT); i++)
dbR2 += (Earth_SRV2[i].dA * cos((Earth_SRV2[i].dB + Earth_SRV2[i].dC * dbt)));
// R3 2x3
for(int i = 0; i < sizeof(Earth_SRV3) / sizeof(VSOP87COEFFICIENT); i++)
dbR3 += (Earth_SRV3[i].dA * cos((Earth_SRV3[i].dB + Earth_SRV3[i].dC * dbt)));
// R4 1x3
for(int i = 0; i < sizeof(Earth_SRV4) / sizeof(VSOP87COEFFICIENT); i++)
dbR4 += (Earth_SRV4[i].dA * cos((Earth_SRV4[i].dB + Earth_SRV4[i].dC * dbt)));
// 计算 R = ( R0 + R1 * τ^1 + R2 * τ^2 + R3 * τ^3 + R4 * τ^4 ) / 10^8 ;(单位弧度)
return ((dbR0 + (dbR1 * dbt) + (dbR2 * (dbt * dbt)) + (dbR3 * (dbt * dbt * dbt)) * (dbR4 * (dbt * dbt * dbt * dbt))) / 100000000.0);
}
六、计算指定时刻太阳黄道经度度数(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
利用以上介绍算法,如下:
// ------------------------------------------------------------------------
//
// 计算某时刻太阳黄经黄纬
//
// dbJD[IN]:儒略日(计算该时刻太阳在黄道面上的经度和纬度)
// dbLongitude[OUT]:黄经
// dbLatitude[OUT]:黄纬
// ------------------------------------------------------------------------
void w_CalcEclipticLongLat(const double & dbJD, double &dbLongitude, double &dbLatitude)
{
// 计算太阳黄经
dbLongitude = w_GetSunLongitude(dbJD);
// 计算太阳黄纬
dbLatitude = w_GetSunLatitude(dbJD);
// 一次校正经度
dbLongitude += w_CorrectionCalcSunLongitude(dbLongitude, dbLatitude, dbJD);
// 二次校正天体章动
dbLongitude += w_GetNutationJamScalar(dbJD) / 3600.0;
// 三次校正太阳半径向量
dbLongitude -= (20.4898 / w_GetSunRadiusVector(dbJD)) /3600.0;
// 校正太阳黄纬
dbLatitude += w_CorrectionCalcSunLatitude(dbLongitude, dbJD);
}
七、使用二分法计算指定节气的时间
// ------------------------------------------------------------------------
//
// 计算节气
//
// year[IN]:公历年份(计算该年份,指定节气的时间)
// ST_SolarTerms[IN]:节气指定的节气
//
// 返回指定节气的儒略日时间
// ------------------------------------------------------------------------
double w_CalcSolarTerms(const int &year, const SOLARTERMS &ST_SolarTerms)
{
// 节气月份
int SolarTermsMonth = static_cast<int>(ceil(static_cast<double>((ST_SolarTerms + 90.0) / 30.0)));
SolarTermsMonth = SolarTermsMonth > 12 ? SolarTermsMonth - 12 : SolarTermsMonth;
// 节令的发生日期基本都在每月 4 - 9 号间
int LowerLimitSolarTermsDay = ST_SolarTerms % 15 == 0 && ST_SolarTerms % 30 != 0 ? 4 : 16;
// 节气的发生日期基本都在每月 16 - 24 号间
int UpperLimitSolarTermsDay = ST_SolarTerms % 15 == 0 && ST_SolarTerms % 30 != 0 ? 9 : 24;
// 采用二分法逼近计算
double dbLowerLinit = w_GDToJD(year, SolarTermsMonth, LowerLimitSolarTermsDay, 0, 0, 0);
double dbUpperLinit = w_GDToJD(year, SolarTermsMonth, UpperLimitSolarTermsDay, 23, 59, 59);
// 二分法分界点日期
double dbDichotomyDivisionDayJD = 0;
// 太阳黄经角度
double dbLongitude = 0;
// 对比二分法精度是否达到要求
for(; fabs(dbLongitude - static_cast<double>(ST_SolarTerms)) >= 0.00001;)
{
dbDichotomyDivisionDayJD = ((dbUpperLinit - dbLowerLinit) / 2.0) + dbLowerLinit;
// 计算太阳黄经
dbLongitude = w_GetSunLongitude(dbDichotomyDivisionDayJD);
// 一次校正经度
dbLongitude += w_CorrectionCalcSunLongitude(dbLongitude, w_GetSunLatitude(dbDichotomyDivisionDayJD), dbDichotomyDivisionDayJD);
// 二次校正天体章动
dbLongitude += w_GetNutationJamScalar(dbDichotomyDivisionDayJD) / 3600.0;
// 三次校正太阳半径向量
dbLongitude -= (20.4898 / w_GetSunRadiusVector(dbDichotomyDivisionDayJD)) /3600.0;
// 由于春分这天黄经为 0 度,比较特殊,因此专门判断(如不加以特殊对待则会导致计算范围覆盖整个 360 度角)
dbLongitude = ((ST_SolarTerms == ST_VERNAL_EQUINOX) && (dbLongitude > 345.0)) ? -dbLongitude : dbLongitude;
// 调整二分法上下限
(dbLongitude > static_cast<double>(ST_SolarTerms)) ? dbUpperLinit = dbDichotomyDivisionDayJD : dbLowerLinit = dbDichotomyDivisionDayJD;
}
return dbDichotomyDivisionDayJD;
}
八、本地时间(LST)和格林尼治时间(UTC)的互换(仅限于 VC 代码)
// ------------------------------------------------------------------------
//
// 格林威治时间转本地时间(以格里历表示本地时间)
//
// ------------------------------------------------------------------------
void w_UTCToLST(int &year, int &month, int &day, int &hour, int &minute, int &second)
{
_tzset () ;
// 计算本地时间和标准时间的时差(单位:秒)
int nDifference_hour = static_cast<int>(_timezone / 3600);
int nDifference_minute = static_cast<int>((_timezone - nDifference_hour * 3600) / 60);
int nDifference_second = static_cast<int>((_timezone - nDifference_hour * 3600) - nDifference_minute * 60);
// 格林威治时间 + 时差 = 本地时间
// 秒
second = second - nDifference_second;
if(second >= 60 || second < 0)
{
minute = second > 0 ? minute + 1 : minute - 1 ;
second = abs(abs(second) - 60);
}
// 分
minute = minute - nDifference_minute;
if(minute >= 60 || minute < 0)
{
hour = minute > 0 ? hour + 1 : hour - 1;
minute = abs(abs(minute) - 60);
}
// 时
hour = hour - nDifference_hour;
if(hour >= 24 || hour < 0)
{
day = (hour >= 24 || hour == 0) ? day + 1 : day - 1;
hour = abs(abs(hour) - 24);
}
// 日
int nDaysOfMonth = w_GetDaysOfMonth(year, month);
if(day > nDaysOfMonth || day <= 0)
{
if(day > nDaysOfMonth)
month++;
if(day < nDaysOfMonth || day <= 0)
month--;
day = abs(abs(day) - nDaysOfMonth);
}
// 月
if(month > 12 || month <= 0)
{
year = month > 0 ? year + 1 : year - 1;
month = month > 0 ? abs(month - 12) : abs(12 + month);
}
}
// ------------------------------------------------------------------------
//
// 本地时间转格林威治时间(以格里历表示)
//
// ------------------------------------------------------------------------
void w_LSTToUTC(int &year, int &month, int &day, int &hour, int &minute, int &second)
{
_tzset () ;
// 计算本地时间和标准时间的时差(单位:秒)
int nDifference_hour = static_cast<int>(_timezone / 3600);
int nDifference_minute = static_cast<int>((_timezone - nDifference_hour * 3600) / 60);
int nDifference_second = static_cast<int>((_timezone - nDifference_hour * 3600) - nDifference_minute * 60);
// 本地时间 - 时差 = 格林威治时间
// 秒
second = second + nDifference_second;
if(second >= 60 || second < 0)
{
minute = second > 0 ? minute + 1 : minute - 1 ;
second = abs(abs(second) - 60);
}
// 分
minute = minute + nDifference_minute;
if(minute >= 60 || minute < 0)
{
hour = minute > 0 ? hour + 1 : hour - 1;
minute = abs(abs(minute) - 60);
}
// 时
hour = hour + nDifference_hour;
if(hour >= 24 || hour < 0)
{
day = (hour >= 24 || hour == 0) ? day + 1 : day - 1;
hour = abs(abs(hour) - 24);
}
// 日
int nDaysOfMonth = w_GetDaysOfMonth(year, month);
if(day > nDaysOfMonth || day <= 0)
{
if(day > nDaysOfMonth)
month++;
if(day < nDaysOfMonth || day <= 0)
month--;
day = abs(abs(day) - nDaysOfMonth);
}
// 月
if(month > 12 || month <= 0)
{
year = month > 0 ? year + 1 : year - 1;
month = month > 0 ? abs(month - 12) : abs(12 + month);
}
}
九、2008年全年 24 节气发生时间(北京时间)
春分:03月20日 13:49:24
清明:04月04日 17:46:58
谷雨:04月20日 00:52:17
立夏:05月05日 11:04:35
小满:05月21日 00:02:03
芒种:06月05日 15:12:53
夏至:06月21日 08:00:30
小暑:07月07日 01:27:59
大暑:07月22日 18:55:58
立秋:08月07日 11:17:19
处暑:08月23日 02:03:22
白露:09月07日 14:15:15
秋分:09月22日 23:45:36
寒露:10月08日 05:57:46
霜降:10月23日 09:09:49
立冬:11月07日 09:11:45
小雪:11月22日 06:45:32
大雪:12月07日 02:03:28
冬至:12月21日 20:04:54
小寒:01月06日 07:25:55
大寒:01月21日 00:44:38
立春:02月04日 19:01:30
雨水:02月19日 14:50:40
惊蛰:03月05日 12:59:54
本文给出了一种通过计算得到某一年的节气发生日期,相比之下比通过查表的方法的优点不言而喻,经本人比对(与日梭万年历)在范围公元300-3000年间误差很小,如果对历法进一步熟悉,你会发现历法的计算非常困难,计算的误差也随时间跨度的增加增长的很快,即便是所有查阅到的最权威的书籍数据,也只能保证在前后200年间的准确。
二十四节气起源于黄河流域。远在春秋时代,就定出仲春、仲夏、仲秋和仲冬等四个节气。以后不断地改进与完善,到秦汉年间,二十四节气已完全确立。公元前104年,由邓平等制定的《太初历》,正式把二十四节气订于历法,明确了二十四节气的天文位置。
太阳从黄经零度起,沿黄经每运行15度所经历的时日称为“一个节气”。每年运行360度,共经历24个节气,每月2个。其中,每月第一个节气为“节气”,即:立春、惊蛰、清明、立夏、芒种、小暑、立秋、白露、寒露、立冬、大雪和小寒等12个节气;每月的第二个节气为“中气”,即:雨水、春分、谷雨、小满、夏至、大暑、处暑、秋分、霜降、小雪、冬至和大寒等12个节气。“节气” 和“中气”交替出现,各历时15天,现在人们已经把“节气”和“中气”统称为“节气”。
二十四节气反映了太阳的周年视运动,所以节气在现行的公历中日期基本固定,上半年在6日、21日,下半年在8日、23日,前后不差1~2天。
二、基本概念
儒略日:Julian Day number 或 Julian Day 或 JD。是指从公元前 4712 年开始连续计算日数得出的天数及不满一日的尾数。传统上儒略日的计数是从格林尼治平午,即世界时间 12 点开始的。
格里历:即公历或格列高利历,是现行国际通行的历法,属于阳历的一种,通称阳历,其前身是奥古斯都历,而奥古斯都历的前身是儒略历。其历年为一个回归年(365.2425日),划分为12个历月。是教皇格里高利13世(也译格雷果里)在公元1582年改革儒略历制定的历法,儒略历的回归年为365.25,与实际的回归365.2422相差甚多,当时儒略历和地球实际位置的误差已达14天,格里历将误差纠正,确定所有整数世纪年除了可被400整除的外一律不设闰年,同时规定1582年10月4日之后的那天为1582年10月15日,但原有星期不变。新颁布的历法理论上可以达到两万年内误差不超过一天,但由于地球自转的变化,实际到公元4909年误差就可达一天。与儒略历相比,公历是新制定的历法,所以有时候,包括中华民国《中国国家标准》CNS 7648《数据元及交换格式–信息交换–日期及时间的表示法》,又称新历。
黄经:地球绕太阳运转一周约365天5小时多,运转94,000万公里。地球的公转在地球上人看来就表现为太阳周年视运动,其运行线路(即地球公转轨道在天球上的反映)称为黄道。黄经就是黄道上的度量坐标(经度),按天文学惯例,以春分点为起点自西向东度量,分360度。我国古人把太阳黄经的360度划分成24等份,每份15度,为一个节气。两个节气间相隔日数为15天左右,全年即有二十四节气。二十四节气的太阳黄经度分别为:立春315度,雨水330度,惊蛰345度,春分360度,清明15度,谷雨30度,立夏45度,小满60度,芒种75度,夏至90度,小暑105度,大暑120度,立秋135度,处暑150度,白露165度,秋分180度,寒露195度,霜降210度,立冬225度,小雪240度,大雪255度,冬至270度,小寒285度,大寒300度。
黄纬:黄道上的纬度。
三、基本算法:
3.1:儒略日的计算(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
// ------------------------------------------------------------------------
//
// 儒略日转换为格历日
//
// dbGD[IN]:儒略日
// year[OUT]:年
// month[OUT]:月
// day[OUT]:日
// hour[OUT]:时
// minute[OUT]:分
// second[OUT]:秒
// ------------------------------------------------------------------------
void w_JDToGD(const double &dbJD, int &year, int &month, int &day, int &hour, int &minute, int &second)
{
double dJDM = dbJD + 0.5;
unsigned long ulZ = static_cast<unsigned long>(floor(dJDM));
double dF = dJDM - floor(dJDM);
unsigned long ulA, ulB, ulC, ulD;
int nE, nQ;
if (dbJD < 2299161)
ulA = ulZ;
else
{
nQ = static_cast<int>((ulZ - 1867216.25) / 36524.25);
ulA = ulZ + 1 + nQ - static_cast<int>(nQ >> 2);
}
ulB = ulA + 1524 ;
ulC = static_cast<int>(( ulB - 122.1) / 365.25);
ulD = static_cast<int>(365.25 * ulC);
nE = static_cast<int>((ulB - ulD) / 30.6001);
// 计算日
day = ulB - ulD - int ( 30.6001 * nE ) ;
// 计算时
hour = static_cast<int>(floor(dF * 24.0));
// 计算分
minute = static_cast<int>(((dF * 24.0) - floor(dF * 24.0)) * 60.0);
// 计算秒
second = static_cast<int>((((dF * 24.0) * 60.0) - floor(( dF * 24.0) * 60.0)) * 60.0);
// 计算月
if(nE < 14)
month = nE - 1;
if(nE == 14 || nE == 15)
month = nE - 13;
// 计算年
if(month > 2)
year = ulC - 4716;
if(month == 1 || month == 2)
year = ulC - 4715;
}
// ------------------------------------------------------------------------
//
// 格历日转换为儒略日
//
// year[IN]:年
// month[IN]:月
// day[IN]:日
// hour[IN]:时
// minute[IN]:分
// second[IN]:秒
//
// 返回对应的儒略日
// ------------------------------------------------------------------------
double w_GDToJD(const int &year, const int &month, const int &day, const int &hour, const int &minute, const int &second)
{
int nY = year, nM = month;
double dD = static_cast<double>(day) + hour / 24.0 + (minute / 60.0) / 24.0 + ((second / 60.0) / 60.0) / 24.0;
if(month == 1 || month == 2)
{
nY = year - 1;
nM = month + 12;
}
int nA = nY / 100;
int nB = 2 - nA + (nA >> 2);
return static_cast<double>(static_cast<int>(365.25 * (nY + 4716)) + static_cast<int>(30.6001 * (nM + 1)) + dD + nB - 1524.5);
}
3.2、角度调整
// ------------------------------------------------------------------------
//
// 调整角度到 0-360 之间
//
// dbDegrees[IN]:角度
//
// 返回调整后的角度
// ------------------------------------------------------------------------
double w_MapTo0To360Range(const double &dbDegrees)
{
double dbValue = dbDegrees;
// map it to the range 0 - 360
while(dbValue < 0.0)
dbValue += 360.0;
while(dbValue > 360.0)
dbValue -= 360.0;
return dbValue;
}
四、步骤简述
4.1、按照 5.2 和 5.3 节介绍方法计算出某一时刻太阳黄经和黄纬。
4.2、按照 5.4 、5.5、5.6 节介绍的三次校正方法对黄经进行校正,即可求得某时刻太阳黄经度数。
4.3、综合步骤演示在第 六 节。
4.4、第 七 节演示如何使用二分法求指定节气的时间。
4.5、第 八 节介绍了 本地时间(LST)和格林尼治时间(UTC)之间互换的函数。
4.6、第 九 节罗列出了本代码计算出的 2008年24节气时间(北京时间)
五、太阳黄经、黄纬、向量半径以及校正量的计算
5.1、为了代码可读性,定义类型变量。
//
// 圆周率
const double PI = 3.1415926535897932384626433832795;
//
// 一度代表的弧度
const double dbUnitRadian = PI / 180.0;
//
// 计算太阳黄经赤纬所需类型变量
typedef struct
{
double dA;
double dB;
double dC;
} VSOP87COEFFICIENT, *PVSOP87COEFFICIENT
// 二次修正黄经赤纬所需的天体章动系数类型变量
typedef struct
{
int nD;
int nM;
int nMprime;
int nF;
int nOmega;
int nSincoeff1;
double dSincoeff2;
int nCoscoeff1;
double dCoscoeff2;
} NUTATIONCOEFFICIENT, *PNUTATIONCOEFFICIENT;
//
// 节气枚举
enum SOLARTERMS
{
ST_VERNAL_EQUINOX = 0, // 春分
ST_CLEAR_AND_BRIGHT = 15, // 清明
ST_GRAIN_RAIN = 30, // 谷雨
ST_SUMMER_BEGINS = 45, // 立夏
ST_GRAIN_BUDS = 60, // 小满
ST_GRAIN_IN_EAR = 75, // 芒种
ST_SUMMER_SOLSTICE = 90, // 夏至
ST_SLIGHT_HEAT = 105, // 小暑
ST_GREAT_HEAT = 120, // 大暑
ST_AUTUMN_BEGINS = 135, // 立秋
ST_STOPPING_THE_HEAT = 150, // 处暑
ST_WHITE_DEWS = 165, // 白露
ST_AUTUMN_EQUINOX = 180, // 秋分
ST_COLD_DEWS = 195, // 寒露
ST_HOAR_FROST_FALLS = 210, // 霜降
ST_WINTER_BEGINS = 225, // 立冬
ST_LIGHT_SNOW = 240, // 小雪
ST_HEAVY_SNOW = 255, // 大雪
ST_WINTER_SOLSTICE = 270, // 冬至
ST_SLIGHT_COLD = 285, // 小寒
ST_GREAT_COLD = 300, // 大寒
ST_SPRING_BEGINS = 315, // 立春
ST_THE_RAINS = 330, // 雨水
ST_INSECTS_AWAKEN = 345 // 惊蛰
};
5.2、黄经:(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
//
// 计算太阳黄经用参数
const VSOP87COEFFICIENT Earth_SLG0[64] =
{
{ 175347046.0 , 0.0000000 , 000000.0000000 } ,
{ 3341656.0 , 4.6692568 , 6283.0758500 } ,
{ 34894.0 , 4.6261000 , 12566.1517000 } ,
{ 3497.0 , 2.7441000 , 5753.3849000 } ,
{ 3418.0 , 2.8289000 , 3.5231000 } ,
{ 3136.0 , 3.6277000 , 77713.7715000 } ,
{ 2676.0 , 4.4181000 , 7860.4194000 } ,
{ 2343.0 , 6.1352000 , 3930.2097000 } ,
{ 1324.0 , 0.7425000 , 11506.7698000 } ,
{ 1273.0 , 2.0371000 , 529.6910000 } ,
{ 1199.0 , 1.1096000 , 1577.3435000 } ,
{ 990.0 , 5.2330000 , 5884.9270000 } ,
{ 902.0 , 2.0450000 , 26.2980000 } ,
{ 857.0 , 3.5080000 , 398.1490000 } ,
{ 780.0 , 1.1790000 , 5223.6940000 } ,
{ 753.0 , 2.5330000 , 5507.5530000 } ,
{ 505.0 , 4.5830000 , 18849.2280000 } ,
{ 492.0 , 4.2050000 , 775.5230000 } ,
{ 357.0 , 2.9200000 , 000000.0670000 } ,
{ 317.0 , 5.8490000 , 11790.6290000 } ,
{ 284.0 , 1.8990000 , 796.2880000 } ,
{ 271.0 , 0.3150000 , 10977.0790000 } ,
{ 243.0 , 0.3450000 , 5486.7780000 } ,
{ 206.0 , 4.8060000 , 2544.3140000 } ,
{ 205.0 , 1.8690000 , 5573.1430000 } ,
{ 202.0 , 2.4580000 , 6069.7770000 } ,
{ 156.0 , 0.8330000 , 213.2990000 } ,
{ 132.0 , 3.4110000 , 2942.4630000 } ,
{ 126.0 , 1.0830000 , 20.7750000 } ,
{ 115.0 , 0.6450000 , 000000.9800000 } ,
{ 103.0 , 0.6360000 , 4694.0030000 } ,
{ 102.0 , 0.9760000 , 15720.8390000 } ,
{ 102.0 , 4.2670000 , 7.1140000 } ,
{ 99.0 , 6.2100000 , 2146.1700000 } ,
{ 98.0 , 0.6800000 , 155.4200000 } ,
{ 86.0 , 5.9800000 , 161000.6900000 } ,
{ 85.0 , 1.3000000 , 6275.9600000 } ,
{ 85.0 , 3.6700000 , 71430.7000000 } ,
{ 80.0 , 1.8100000 , 17260.1500000 } ,
{ 79.0 , 3.0400000 , 12036.4600000 } ,
{ 75.0 , 1.7600000 , 5088.6300000 } ,
{ 74.0 , 3.5000000 , 3154.6900000 } ,
{ 74.0 , 4.6800000 , 801.8200000 } ,
{ 70.0 , 0.8300000 , 9437.7600000 } ,
{ 62.0 , 3.9800000 , 8827.3900000 } ,
{ 61.0 , 1.8200000 , 7084.9000000 } ,
{ 57.0 , 2.7800000 , 6286.6000000 } ,
{ 56.0 , 4.3900000 , 14143.5000000 } ,
{ 56.0 , 3.4700000 , 6279.5500000 } ,
{ 52.0 , 0.1900000 , 12139.5500000 } ,
{ 52.0 , 1.3300000 , 1748.0200000 } ,
{ 51.0 , 0.2800000 , 5856.4800000 } ,
{ 49.0 , 0.4900000 , 1194.4500000 } ,
{ 41.0 , 5.3700000 , 8429.2400000 } ,
{ 41.0 , 2.4000000 , 19651.0500000 } ,
{ 39.0 , 6.1700000 , 10447.3900000 } ,
{ 37.0 , 6.0400000 , 10213.2900000 } ,
{ 37.0 , 2.5700000 , 1059.3800000 } ,
{ 36.0 , 1.7100000 , 2352.8700000 } ,
{ 36.0 , 1.7800000 , 6812.7700000 } ,
{ 33.0 , 0.5900000 , 17789.8500000 } ,
{ 30.0 , 0.4400000 , 83996.8500000 } ,
{ 30.0 , 2.7400000 , 1349.8700000 } ,
{ 25.0 , 3.1600000 , 4690.4800000 }
};
const VSOP87COEFFICIENT Earth_SLG1[34] =
{
{ 628331966747.0 , 0.000000 , 00000.0000000 } ,
{ 206059.0 , 2.678235 , 6283.0758500 } ,
{ 4303.0 , 2.635100 , 12566.1517000 } ,
{ 425.0 , 1.590000 , 3.5230000 } ,
{ 119.0 , 5.796000 , 26.2980000 } ,
{ 109.0 , 2.966000 , 1577.3440000 } ,
{ 93.0 , 2.590000 , 18849.2300000 } ,
{ 72.0 , 1.140000 , 529.6900000 } ,
{ 68.0 , 1.870000 , 398.1500000 } ,
{ 67.0 , 4.410000 , 5507.5500000 } ,
{ 59.0 , 2.890000 , 5223.6900000 } ,
{ 56.0 , 2.170000 , 155.4200000 } ,
{ 45.0 , 0.400000 , 796.3000000 } ,
{ 36.0 , 0.470000 , 775.5200000 } ,
{ 29.0 , 2.650000 , 7.1100000 } ,
{ 21.0 , 5.430000 , 00000.9800000 } ,
{ 19.0 , 1.850000 , 5486.7800000 } ,
{ 19.0 , 4.970000 , 213.3000000 } ,
{ 17.0 , 2.990000 , 6275.9600000 } ,
{ 16.0 , 0.030000 , 2544.3100000 } ,
{ 16.0 , 1.430000 , 2146.1700000 } ,
{ 15.0 , 1.210000 , 10977.0800000 } ,
{ 12.0 , 2.830000 , 1748.0200000 } ,
{ 12.0 , 3.260000 , 5088.6300000 } ,
{ 12.0 , 5.270000 , 1194.4500000 } ,
{ 12.0 , 2.080000 , 4694.0000000 } ,
{ 11.0 , 0.770000 , 553.5700000 } ,
{ 10.0 , 1.300000 , 6286.6000000 } ,
{ 10.0 , 4.240000 , 1349.8700000 } ,
{ 9.0 , 2.700000 , 242.7300000 } ,
{ 9.0 , 5.640000 , 951.7200000 } ,
{ 8.0 , 5.300000 , 2352.8700000 } ,
{ 6.0 , 2.650000 , 9437.7600000 } ,
{ 6.0 , 4.670000 , 4690.4800000 }
};
const VSOP87COEFFICIENT Earth_SLG2[20] =
{
{ 52919.0 , 0.0000 , 00000.0000 } ,
{ 8720.0 , 1.0721 , 6283.0758 } ,
{ 309.0 , 0.8670 , 12566.1520 } ,
{ 27.0 , 0.0500 , 3.5200 } ,
{ 16.0 , 5.1900 , 26.3000 } ,
{ 16.0 , 3.6800 , 155.4200 } ,
{ 10.0 , 0.7600 , 18849.2300 } ,
{ 9.0 , 2.0600 , 77713.7700 } ,
{ 7.0 , 0.8300 , 775.5200 } ,
{ 5.0 , 4.6600 , 1577.3400 } ,
{ 4.0 , 1.0300 , 7.1100 } ,
{ 4.0 , 3.4400 , 5573.1400 } ,
{ 3.0 , 5.1400 , 796.3000 } ,
{ 3.0 , 6.0500 , 5507.5500 } ,
{ 3.0 , 1.1900 , 242.7300 } ,
{ 3.0 , 6.1200 , 529.6900 } ,
{ 3.0 , 0.3100 , 398.1500 } ,
{ 3.0 , 2.2800 , 553.5700 } ,
{ 2.0 , 4.3800 , 5223.6900 } ,
{ 2.0 , 3.7500 , 00000.9800 }
};
const VSOP87COEFFICIENT Earth_SLG3[ 7] =
{
{ 289.0 , 5.844 , 6283.076 } ,
{ 35.0 , 0.000 , 00000.000 } ,
{ 17.0 , 5.490 , 12566.150 } ,
{ 3.0 , 5.200 , 155.420 } ,
{ 1.0 , 4.720 , 3.520 } ,
{ 1.0 , 5.300 , 18849.230 } ,
{ 1.0 , 5.970 , 242.730 }
};
const VSOP87COEFFICIENT Earth_SLG4[ 3] =
{
{ 114.0 , 3.142 , 00000.00 } ,
{ 8.0 , 4.130 , 6283.08 } ,
{ 1.0 , 3.840 , 12566.15 }
};
const VSOP87COEFFICIENT Earth_SLG5[ 1] =
{
{ 1.0 , 3.14 , 0.0 }
};
// ------------------------------------------------------------------------
//
// 计算太阳在黄道面上的经度(单位:度)
//
// dbJD[IN]:儒略日(计算该时刻太阳在黄道面上的经度)
//
// 返回太阳黄经度数
// ------------------------------------------------------------------------
double w_GetSunLongitude(const double & dbJD)
{
// 计算τ
double dt = (dbJD - 2451545.0) / 365250.0;
double dL = 0.0, dL0 = 0.0, dL1 = 0.0, dL2 = 0.0, dL3 = 0.0, dL4 = 0.0, dL5 = 0.0;
// L0 38x3
for(int i = 0; i < sizeof(Earth_SLG0) / sizeof(VSOP87COEFFICIENT); i++)
dL0 += (Earth_SLG0[i].dA * cos((Earth_SLG0[i].dB + Earth_SLG0[i].dC * dt)));
// L1 16x3
for(int i = 0; i < sizeof(Earth_SLG1) / sizeof(VSOP87COEFFICIENT); i++)
dL1 += (Earth_SLG1[i].dA * cos((Earth_SLG1[i].dB + Earth_SLG1[i].dC * dt)));
// L2 10x3
for(int i = 0; i < sizeof(Earth_SLG2) / sizeof(VSOP87COEFFICIENT); i++)
dL2 += (Earth_SLG2[i].dA * cos((Earth_SLG2[i].dB + Earth_SLG2[i].dC * dt)));
// L3 8x3
for(int i = 0; i < sizeof(Earth_SLG3) / sizeof(VSOP87COEFFICIENT); i++)
dL3 += (Earth_SLG3[i].dA * cos((Earth_SLG3[i].dB + Earth_SLG3[i].dC * dt)));
// L4 6x3
for(int i = 0; i < sizeof(Earth_SLG4) / sizeof(VSOP87COEFFICIENT); i++)
dL4 += (Earth_SLG4[i].dA * cos((Earth_SLG4[i].dB + Earth_SLG4[i].dC * dt)));
// L5 1x3
for(int i = 0; i < sizeof(Earth_SLG5) / sizeof(VSOP87COEFFICIENT); i++)
dL5 += (Earth_SLG5[i].dA * cos((Earth_SLG5[i].dB + Earth_SLG5[i].dC * dt)));
// 计算 L = ( L0 + L1 * τ^1 + L2 * τ^2 + L3 * τ^3 + L4 * τ^4 + L5 * τ^5 ) / 10^8 ;(单位弧度)
dL = (dL0 + (dL1 * dt) + (dL2 * (dt * dt)) + (dL3 * (dt * dt * dt)) * (dL4 * (dt * dt * dt * dt)) + (dL5 * (dt * dt * dt * dt * dt))) / 100000000.0;
// 转化为度θ = L + 180 (单位度);
return (w_MapTo0To360Range(w_MapTo0To360Range(dL / dbUnitRadian) + 180.0));
}
5.3、黄纬:(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
//
// 计算太阳黄纬用参数
const VSOP87COEFFICIENT Earth_SLT0[ 5] =
{
{ 280.0 , 3.199 , 84334.662 } ,
{ 102.0 , 5.422 , 5507.553 } ,
{ 80.0 , 3.880 , 5223.690 } ,
{ 44.0 , 3.700 , 2352.870 } ,
{ 32.0 , 4.000 , 1577.340 }
};
const VSOP87COEFFICIENT Earth_SLT1[ 2] =
{
{ 9.0 , 3.90 , 5507.55 } ,
{ 6.0 , 1.73 , 5223.69 }
};
const VSOP87COEFFICIENT Earth_SLT2[ 4] =
{
{ 22378.0 , 3.38509 , 10213.28555 } ,
{ 282.0 , 0.00000 , 00000.00000 } ,
{ 173.0 , 5.25600 , 20426.57100 } ,
{ 27.0 , 3.87000 , 30639.86000 }
};
const VSOP87COEFFICIENT Earth_SLT3[ 4] =
{
{ 647.0 , 4.992 , 10213.286 } ,
{ 20.0 , 3.140 , 00000.000 } ,
{ 6.0 , 0.770 , 20426.570 } ,
{ 3.0 , 5.440 , 30639.860 }
};
const VSOP87COEFFICIENT CWDCalendarEngine::Earth_SLT4[ 1] =
{
{ 14.0 , 0.32 , 10213.29 }
};
// ------------------------------------------------------------------------
//
// 计算太阳在黄道面上的纬度(单位:度)
//
// dbJD[IN]:儒略日(计算该时刻太阳在黄道面上的纬度)
//
// 返回太阳黄纬度数
// ------------------------------------------------------------------------
double w_GetSunLatitude(const double & dbJD)
{
// 计算τ
double dbt = (dbJD - 2451545.0) / 365250.0;
double dbB = 0.0, dbB0 = 0.0, dbB1 = 0.0, dbB2 = 0.0, dbB3 = 0.0, dbB4 = 0.0;
// B0 5x3
for(int i = 0; i < sizeof(Earth_SLT0) / sizeof(VSOP87COEFFICIENT); i++)
dbB0 += (Earth_SLT0[i].dA * cos((Earth_SLT0[i].dB + Earth_SLT0[i].dC * dbt)));
// B1 2x3
for(int i = 0; i < sizeof(Earth_SLT1) / sizeof(VSOP87COEFFICIENT); i++)
dbB1 += (Earth_SLT1[i].dA * cos((Earth_SLT1[i].dB + Earth_SLT1[i].dC * dbt)));
// B2 4x3
for(int i = 0; i < sizeof(Earth_SLT2) / sizeof(VSOP87COEFFICIENT); i++)
dbB2 += (Earth_SLT2[i].dA * cos((Earth_SLT2[i].dB + Earth_SLT2[i].dC * dbt)));
// B3 4x3
for(int i = 0; i < sizeof(Earth_SLT3) / sizeof(VSOP87COEFFICIENT); i++)
dbB3 += (Earth_SLT3[i].dA * cos((Earth_SLT3[i].dB + Earth_SLT3[i].dC * dbt)));
// B4 1x3
for(int i = 0; i < sizeof(Earth_SLT4) / sizeof(VSOP87COEFFICIENT); i++)
dbB4 += (Earth_SLT4[i].dA * cos((Earth_SLT4[i].dB + Earth_SLT4[i].dC * dbt)));
// 计算 B = ( B0 + B1 * τ^1 + B2 * τ^2 + B3 * τ^3 + B4 * τ^4 ) / 10^8 ;(单位弧度)
dbB = (dbB0 + (dbB1 * dbt) + (dbB2 * (dbt * dbt)) + (dbB3 * (dbt * dbt * dbt)) * (dbB4 * (dbt * dbt * dbt * dbt))) / 100000000.0;
// 计算 θ(单位度);
return -(dbB / dbUnitRadian);
}
5.4、第一次校正黄经:(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
// ------------------------------------------------------------------------
//
// 修正某时刻太阳在黄道上的经度(黄经)
//
// dbSrcLongitude[IN]:黄经
// dbSrcLatitude[IN]:黄纬
// dbJD[IN]:儒略日(修正在该时刻太阳的黄经)
//
// 返回太阳黄经度数
// ------------------------------------------------------------------------
double w_CorrectionCalcSunLongitude(const double &dbSrcLongitude, const double &dbSrcLatitude, const double &dbJD)
{
double dbT = (dbJD - 2451545.0) / 36525.0;
double dbLdash = dbSrcLongitude - 1.397 * dbT - 0.00031 * dbT * dbT;
// 转换为弧度
dbLdash *= dbUnitRadian;
return (-0.09033 + 0.03916 * (cos(dbLdash) + sin(dbLdash)) * tan(dbSrcLatitude * dbUnitRadian)) / 3600.0;
}
5.5、第二次校正黄经(章动):(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
//
// 二次修正黄经黄纬所需的天体章动系数
const NUTATIONCOEFFICIENT Nutation_Gene[63] =
{
{ 0, 0, 0, 0, 1, -171996, -174.2, 92025, 8.9 },
{ -2, 0, 0, 2, 2, -13187, -1.6, 5736, -3.1 },
{ 0, 0, 0, 2, 2, -2274, -0.2, 977, -0.5 },
{ 0, 0, 0, 0, 2, 2062, 0.2, -895, 0.5 },
{ 0, 1, 0, 0, 0, 1426, -3.4, 54, -0.1 },
{ 0, 0, 1, 0, 0, 712, 0.1, -7, 0 },
{ -2, 1, 0, 2, 2, -517, 1.2, 224, -0.6 },
{ 0, 0, 0, 2, 1, -386, -0.4, 200, 0 },
{ 0, 0, 1, 2, 2, -301, 0, 129, -0.1 },
{ -2, -1, 0, 2, 2, 217, -0.5, -95, 0.3 },
{ -2, 0, 1, 0, 0, -158, 0, 0, 0 },
{ -2, 0, 0, 2, 1, 129, 0.1, -70, 0 },
{ 0, 0, -1, 2, 2, 123, 0, -53, 0 },
{ 2, 0, 0, 0, 0, 63, 0, 0, 0 },
{ 0, 0, 1, 0, 1, 63, 0.1, -33, 0 },
{ 2, 0, -1, 2, 2, -59, 0, 26, 0 },
{ 0, 0, -1, 0, 1, -58, -0.1, 32, 0 },
{ 0, 0, 1, 2, 1, -51, 0, 27, 0 },
{ -2, 0, 2, 0, 0, 48, 0, 0, 0 },
{ 0, 0, -2, 2, 1, 46, 0, -24, 0 },
{ 2, 0, 0, 2, 2, -38, 0, 16, 0 },
{ 0, 0, 2, 2, 2, -31, 0, 13, 0 },
{ 0, 0, 2, 0, 0, 29, 0, 0, 0 },
{ -2, 0, 1, 2, 2, 29, 0, -12, 0 },
{ 0, 0, 0, 2, 0, 26, 0, 0, 0 },
{ -2, 0, 0, 2, 0, -22, 0, 0, 0 },
{ 0, 0, -1, 2, 1, 21, 0, -10, 0 },
{ 0, 2, 0, 0, 0, 17, -0.1, 0, 0 },
{ 2, 0, -1, 0, 1, 16, 0, -8, 0 },
{ -2, 2, 0, 2, 2, -16, 0.1, 7, 0 },
{ 0, 1, 0, 0, 1, -15, 0, 9, 0 },
{ -2, 0, 1, 0, 1, -13, 0, 7, 0 },
{ 0, -1, 0, 0, 1, -12, 0, 6, 0 },
{ 0, 0, 2,-2, 0, 11, 0, 0, 0 },
{ 2, 0, -1, 2, 1, -10, 0, 5, 0 },
{ 2, 0, 1, 2, 2, -8, 0, 3, 0 },
{ 0, 1, 0, 2, 2, 7, 0, -3, 0 },
{ -2, 1, 1, 0, 0, -7, 0, 0, 0 },
{ 0, -1, 0, 2, 2, -7, 0, 3, 0 },
{ 2, 0, 0, 2, 1, -7, 0, 3, 0 },
{ 2, 0, 1, 0, 0, 6, 0, 0, 0 },
{ -2, 0, 2, 2, 2, 6, 0, -3, 0 },
{ -2, 0, 1, 2, 1, 6, 0, -3, 0 },
{ 2, 0, -2, 0, 1, -6, 0, 3, 0 },
{ 2, 0, 0, 0, 1, -6, 0, 3, 0 },
{ 0, -1, 1, 0, 0, 5, 0, 0, 0 },
{ -2, -1, 0, 2, 1, -5, 0, 3, 0 },
{ -2, 0, 0, 0, 1, -5, 0, 3, 0 },
{ 0, 0, 2, 2, 1, -5, 0, 3, 0 },
{ -2, 0, 2, 0, 1, 4, 0, 0, 0 },
{ -2, 1, 0, 2, 1, 4, 0, 0, 0 },
{ 0, 0, 1,-2, 0, 4, 0, 0, 0 },
{ -1, 0, 1, 0, 0, -4, 0, 0, 0 },
{ -2, 1, 0, 0, 0, -4, 0, 0, 0 },
{ 1, 0, 0, 0, 0, -4, 0, 0, 0 },
{ 0, 0, 1, 2, 0, 3, 0, 0, 0 },
{ 0, 0, -2, 2, 2, -3, 0, 0, 0 },
{ -1, -1, 1, 0, 0, -3, 0, 0, 0 },
{ 0, 1, 1, 0, 0, -3, 0, 0, 0 },
{ 0, -1, 1, 2, 2, -3, 0, 0, 0 },
{ 2, -1, -1, 2, 2, -3, 0, 0, 0 },
{ 0, 0, 3, 2, 2, -3, 0, 0, 0 },
{ 2, -1, 0, 2, 2, -3, 0, 0, 0 }
};
// ------------------------------------------------------------------------
//
// 计算天体章动
// 二次修正某时刻太阳在黄道上的纬度(单位:度)
// 使用天体章动系数修正,消除扰动影响
//
// dbJD[IN]:儒略日(计算该时刻天体章动补偿量)
//
// 返回天体扰动干扰量
// ------------------------------------------------------------------------
double w_GetNutationJamScalar(const double &dbJD)
{
double dbT = (dbJD - 2451545.0) / 36525.0;
double dbTsquared = dbT * dbT;
double dbTcubed = dbTsquared * dbT;
double dbD = 297.85036 + 445267.111480 * dbT - 0.0019142 * dbTsquared + dbTcubed / 189474.0;
dbD = w_MapTo0To360Range(dbD);
double dbM = 357.52772 + 35999.050340 * dbT - 0.0001603 * dbTsquared - dbTcubed / 300000.0;
dbM = w_MapTo0To360Range(dbM);
double dbMprime = 134.96298 + 477198.867398 * dbT + 0.0086972 * dbTsquared + dbTcubed / 56250.0;
dbMprime = w_MapTo0To360Range(dbMprime);
double dbF = 93.27191 + 483202.017538 * dbT - 0.0036825 * dbTsquared + dbTcubed / 327270.0;
dbF = w_MapTo0To360Range(dbF);
double dbOmega = 125.04452 - 1934.136261 * dbT + 0.0020708 * dbTsquared + dbTcubed / 450000.0;
dbOmega = w_MapTo0To360Range(dbOmega);
double dbResulte = 0.0 ;
for(int i = 0; i < sizeof(Nutation_Gene) / sizeof(NUTATIONCOEFFICIENT); i++)
{
double dbRadargument = (Nutation_Gene[i].nD * dbD + Nutation_Gene[i].nM * dbM + Nutation_Gene[i].nMprime * dbMprime + Nutation_Gene[i].nF * dbF + Nutation_Gene[i].nOmega * dbOmega) * dbUnitRadian;
dbResulte += (Nutation_Gene[i].nSincoeff1 + Nutation_Gene[i].dSincoeff2 * dbT ) * sin(dbRadargument) * 0.0001;
}
return dbResulte;
}
5.6、第三次校正黄经(太阳半径向量):(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
//
// 计算太阳向量半径用参数
const VSOP87COEFFICIENT Earth_SRV0[40] =
{
{ 100013989 , 0 , 0 },
{ 1670700 , 3.0984635 , 6283.0758500 },
{ 13956 , 3.05525 , 12566.15170 },
{ 3084 , 5.1985 , 77713.7715 },
{ 1628 , 1.1739 , 5753.3849 },
{ 1576 , 2.8469 , 7860.4194 },
{ 925 , 5.453 , 11506.770 },
{ 542 , 4.564 , 3930.210 },
{ 472 , 3.661 , 5884.927 },
{ 346 , 0.964 , 5507.553 },
{ 329 , 5.900 , 5223.694 },
{ 307 , 0.299 , 5573.143 },
{ 243 , 4.273 , 11790.629 },
{ 212 , 5.847 , 1577.344 },
{ 186 , 5.022 , 10977.079 },
{ 175 , 3.012 , 18849.228 },
{ 110 , 5.055 , 5486.778 },
{ 98 , 0.89 , 6069.78 },
{ 86 , 5.69 , 15720.84 },
{ 86 , 1.27 , 161000.69 },
{ 65 , 0.27 , 17260.15 },
{ 63 , 0.92 , 529.69 },
{ 57 , 2.01 , 83996.85 },
{ 56 , 5.24 , 71430.70 },
{ 49 , 3.25 , 2544.31 },
{ 47 , 2.58 , 775.52 },
{ 45 , 5.54 , 9437.76 },
{ 43 , 6.01 , 6275.96 },
{ 39 , 5.36 , 4694.00 },
{ 38 , 2.39 , 8827.39 },
{ 37 , 0.83 , 19651.05 },
{ 37 , 4.90 , 12139.55 },
{ 36 , 1.67 , 12036.46 },
{ 35 , 1.84 , 2942.46 },
{ 33 , 0.24 , 7084.90 },
{ 32 , 0.18 , 5088.63 },
{ 32 , 1.78 , 398.15 },
{ 28 , 1.21 , 6286.60 },
{ 28 , 1.90 , 6279.55 },
{ 26 , 4.59 , 10447.39 }
};
const VSOP87COEFFICIENT Earth_SRV1[10] =
{
{ 103019 , 1.107490 , 6283.075850 },
{ 1721 , 1.0644 , 12566.1517 },
{ 702 , 3.142 , 0 },
{ 32 , 1.02 , 18849.23 },
{ 31 , 2.84 , 5507.55 },
{ 25 , 1.32 , 5223.69 },
{ 18 , 1.42 , 1577.34 },
{ 10 , 5.91 , 10977.08 },
{ 9 , 1.42 , 6275.96 },
{ 9 , 0.27 , 5486.78 }
};
const VSOP87COEFFICIENT Earth_SRV2[ 6] =
{
{ 4359 , 5.7846 , 6283.0758 },
{ 124 , 5.579 , 12566.152 },
{ 12 , 3.14 , 0 },
{ 9 , 3.63 , 77713.77 },
{ 6 , 1.87 , 5573.14 },
{ 3 , 5.47 , 18849.23 }
};
const VSOP87COEFFICIENT Earth_SRV3[ 2] =
{
{ 145 , 4.273 , 6283.076 },
{ 7 , 3.92 , 12566.15 }
};
const VSOP87COEFFICIENT Earth_SRV4[ 1] =
{
{ 4 , 2.56 , 6283.08 }
};
// ------------------------------------------------------------------------
//
// 计算某时刻太阳半径向量
// 三次修正某时刻太阳在黄道上的经度(单位:弧度)
//
// dbJD[IN]:儒略日(计算该时刻太阳半径向量)
//
// 返回太阳半径向量
// ------------------------------------------------------------------------
double w_GetSunRadiusVector(const double &dbJD)
{
// 计算τ
double dbt = (dbJD - 2451545.0) / 365250.0;
double dbR = 0.0, dbR0 = 0.0, dbR1 = 0.0, dbR2 = 0.0, dbR3 = 0.0, dbR4 = 0.0;
// R0 40x3
for(int i = 0; i < sizeof(Earth_SRV0) / sizeof(VSOP87COEFFICIENT); i++)
dbR0 += (Earth_SRV0[i].dA * cos((Earth_SRV0[i].dB + Earth_SRV0[i].dC * dbt)));
// R1 10x3
for(int i = 0; i < sizeof(Earth_SRV1) / sizeof(VSOP87COEFFICIENT); i++)
dbR1 += (Earth_SRV1[i].dA * cos((Earth_SRV1[i].dB + Earth_SRV1[i].dC * dbt)));
// R2 6x3
for(int i = 0; i < sizeof(Earth_SRV2) / sizeof(VSOP87COEFFICIENT); i++)
dbR2 += (Earth_SRV2[i].dA * cos((Earth_SRV2[i].dB + Earth_SRV2[i].dC * dbt)));
// R3 2x3
for(int i = 0; i < sizeof(Earth_SRV3) / sizeof(VSOP87COEFFICIENT); i++)
dbR3 += (Earth_SRV3[i].dA * cos((Earth_SRV3[i].dB + Earth_SRV3[i].dC * dbt)));
// R4 1x3
for(int i = 0; i < sizeof(Earth_SRV4) / sizeof(VSOP87COEFFICIENT); i++)
dbR4 += (Earth_SRV4[i].dA * cos((Earth_SRV4[i].dB + Earth_SRV4[i].dC * dbt)));
// 计算 R = ( R0 + R1 * τ^1 + R2 * τ^2 + R3 * τ^3 + R4 * τ^4 ) / 10^8 ;(单位弧度)
return ((dbR0 + (dbR1 * dbt) + (dbR2 * (dbt * dbt)) + (dbR3 * (dbt * dbt * dbt)) * (dbR4 * (dbt * dbt * dbt * dbt))) / 100000000.0);
}
六、计算指定时刻太阳黄道经度度数(算法描述请参考相关书籍,为了节省空间和时间,这里请罗列出 C++ 实现代码)
利用以上介绍算法,如下:
// ------------------------------------------------------------------------
//
// 计算某时刻太阳黄经黄纬
//
// dbJD[IN]:儒略日(计算该时刻太阳在黄道面上的经度和纬度)
// dbLongitude[OUT]:黄经
// dbLatitude[OUT]:黄纬
// ------------------------------------------------------------------------
void w_CalcEclipticLongLat(const double & dbJD, double &dbLongitude, double &dbLatitude)
{
// 计算太阳黄经
dbLongitude = w_GetSunLongitude(dbJD);
// 计算太阳黄纬
dbLatitude = w_GetSunLatitude(dbJD);
// 一次校正经度
dbLongitude += w_CorrectionCalcSunLongitude(dbLongitude, dbLatitude, dbJD);
// 二次校正天体章动
dbLongitude += w_GetNutationJamScalar(dbJD) / 3600.0;
// 三次校正太阳半径向量
dbLongitude -= (20.4898 / w_GetSunRadiusVector(dbJD)) /3600.0;
// 校正太阳黄纬
dbLatitude += w_CorrectionCalcSunLatitude(dbLongitude, dbJD);
}
七、使用二分法计算指定节气的时间
// ------------------------------------------------------------------------
//
// 计算节气
//
// year[IN]:公历年份(计算该年份,指定节气的时间)
// ST_SolarTerms[IN]:节气指定的节气
//
// 返回指定节气的儒略日时间
// ------------------------------------------------------------------------
double w_CalcSolarTerms(const int &year, const SOLARTERMS &ST_SolarTerms)
{
// 节气月份
int SolarTermsMonth = static_cast<int>(ceil(static_cast<double>((ST_SolarTerms + 90.0) / 30.0)));
SolarTermsMonth = SolarTermsMonth > 12 ? SolarTermsMonth - 12 : SolarTermsMonth;
// 节令的发生日期基本都在每月 4 - 9 号间
int LowerLimitSolarTermsDay = ST_SolarTerms % 15 == 0 && ST_SolarTerms % 30 != 0 ? 4 : 16;
// 节气的发生日期基本都在每月 16 - 24 号间
int UpperLimitSolarTermsDay = ST_SolarTerms % 15 == 0 && ST_SolarTerms % 30 != 0 ? 9 : 24;
// 采用二分法逼近计算
double dbLowerLinit = w_GDToJD(year, SolarTermsMonth, LowerLimitSolarTermsDay, 0, 0, 0);
double dbUpperLinit = w_GDToJD(year, SolarTermsMonth, UpperLimitSolarTermsDay, 23, 59, 59);
// 二分法分界点日期
double dbDichotomyDivisionDayJD = 0;
// 太阳黄经角度
double dbLongitude = 0;
// 对比二分法精度是否达到要求
for(; fabs(dbLongitude - static_cast<double>(ST_SolarTerms)) >= 0.00001;)
{
dbDichotomyDivisionDayJD = ((dbUpperLinit - dbLowerLinit) / 2.0) + dbLowerLinit;
// 计算太阳黄经
dbLongitude = w_GetSunLongitude(dbDichotomyDivisionDayJD);
// 一次校正经度
dbLongitude += w_CorrectionCalcSunLongitude(dbLongitude, w_GetSunLatitude(dbDichotomyDivisionDayJD), dbDichotomyDivisionDayJD);
// 二次校正天体章动
dbLongitude += w_GetNutationJamScalar(dbDichotomyDivisionDayJD) / 3600.0;
// 三次校正太阳半径向量
dbLongitude -= (20.4898 / w_GetSunRadiusVector(dbDichotomyDivisionDayJD)) /3600.0;
// 由于春分这天黄经为 0 度,比较特殊,因此专门判断(如不加以特殊对待则会导致计算范围覆盖整个 360 度角)
dbLongitude = ((ST_SolarTerms == ST_VERNAL_EQUINOX) && (dbLongitude > 345.0)) ? -dbLongitude : dbLongitude;
// 调整二分法上下限
(dbLongitude > static_cast<double>(ST_SolarTerms)) ? dbUpperLinit = dbDichotomyDivisionDayJD : dbLowerLinit = dbDichotomyDivisionDayJD;
}
return dbDichotomyDivisionDayJD;
}
八、本地时间(LST)和格林尼治时间(UTC)的互换(仅限于 VC 代码)
// ------------------------------------------------------------------------
//
// 格林威治时间转本地时间(以格里历表示本地时间)
//
// ------------------------------------------------------------------------
void w_UTCToLST(int &year, int &month, int &day, int &hour, int &minute, int &second)
{
_tzset () ;
// 计算本地时间和标准时间的时差(单位:秒)
int nDifference_hour = static_cast<int>(_timezone / 3600);
int nDifference_minute = static_cast<int>((_timezone - nDifference_hour * 3600) / 60);
int nDifference_second = static_cast<int>((_timezone - nDifference_hour * 3600) - nDifference_minute * 60);
// 格林威治时间 + 时差 = 本地时间
// 秒
second = second - nDifference_second;
if(second >= 60 || second < 0)
{
minute = second > 0 ? minute + 1 : minute - 1 ;
second = abs(abs(second) - 60);
}
// 分
minute = minute - nDifference_minute;
if(minute >= 60 || minute < 0)
{
hour = minute > 0 ? hour + 1 : hour - 1;
minute = abs(abs(minute) - 60);
}
// 时
hour = hour - nDifference_hour;
if(hour >= 24 || hour < 0)
{
day = (hour >= 24 || hour == 0) ? day + 1 : day - 1;
hour = abs(abs(hour) - 24);
}
// 日
int nDaysOfMonth = w_GetDaysOfMonth(year, month);
if(day > nDaysOfMonth || day <= 0)
{
if(day > nDaysOfMonth)
month++;
if(day < nDaysOfMonth || day <= 0)
month--;
day = abs(abs(day) - nDaysOfMonth);
}
// 月
if(month > 12 || month <= 0)
{
year = month > 0 ? year + 1 : year - 1;
month = month > 0 ? abs(month - 12) : abs(12 + month);
}
}
// ------------------------------------------------------------------------
//
// 本地时间转格林威治时间(以格里历表示)
//
// ------------------------------------------------------------------------
void w_LSTToUTC(int &year, int &month, int &day, int &hour, int &minute, int &second)
{
_tzset () ;
// 计算本地时间和标准时间的时差(单位:秒)
int nDifference_hour = static_cast<int>(_timezone / 3600);
int nDifference_minute = static_cast<int>((_timezone - nDifference_hour * 3600) / 60);
int nDifference_second = static_cast<int>((_timezone - nDifference_hour * 3600) - nDifference_minute * 60);
// 本地时间 - 时差 = 格林威治时间
// 秒
second = second + nDifference_second;
if(second >= 60 || second < 0)
{
minute = second > 0 ? minute + 1 : minute - 1 ;
second = abs(abs(second) - 60);
}
// 分
minute = minute + nDifference_minute;
if(minute >= 60 || minute < 0)
{
hour = minute > 0 ? hour + 1 : hour - 1;
minute = abs(abs(minute) - 60);
}
// 时
hour = hour + nDifference_hour;
if(hour >= 24 || hour < 0)
{
day = (hour >= 24 || hour == 0) ? day + 1 : day - 1;
hour = abs(abs(hour) - 24);
}
// 日
int nDaysOfMonth = w_GetDaysOfMonth(year, month);
if(day > nDaysOfMonth || day <= 0)
{
if(day > nDaysOfMonth)
month++;
if(day < nDaysOfMonth || day <= 0)
month--;
day = abs(abs(day) - nDaysOfMonth);
}
// 月
if(month > 12 || month <= 0)
{
year = month > 0 ? year + 1 : year - 1;
month = month > 0 ? abs(month - 12) : abs(12 + month);
}
}
九、2008年全年 24 节气发生时间(北京时间)
春分:03月20日 13:49:24
清明:04月04日 17:46:58
谷雨:04月20日 00:52:17
立夏:05月05日 11:04:35
小满:05月21日 00:02:03
芒种:06月05日 15:12:53
夏至:06月21日 08:00:30
小暑:07月07日 01:27:59
大暑:07月22日 18:55:58
立秋:08月07日 11:17:19
处暑:08月23日 02:03:22
白露:09月07日 14:15:15
秋分:09月22日 23:45:36
寒露:10月08日 05:57:46
霜降:10月23日 09:09:49
立冬:11月07日 09:11:45
小雪:11月22日 06:45:32
大雪:12月07日 02:03:28
冬至:12月21日 20:04:54
小寒:01月06日 07:25:55
大寒:01月21日 00:44:38
立春:02月04日 19:01:30
雨水:02月19日 14:50:40
惊蛰:03月05日 12:59:54
本文给出了一种通过计算得到某一年的节气发生日期,相比之下比通过查表的方法的优点不言而喻,经本人比对(与日梭万年历)在范围公元300-3000年间误差很小,如果对历法进一步熟悉,你会发现历法的计算非常困难,计算的误差也随时间跨度的增加增长的很快,即便是所有查阅到的最权威的书籍数据,也只能保证在前后200年间的准确。
发表评论
-
用天文方法计算日月合朔(新月)
2012-12-15 09:09 1675中国农历的朔望月是农历历法的基础,而朔望月又是严格以日月合朔发 ... -
用天文方法计算二十四节气
2012-12-15 09:08 2473二十四节气在中国古代历法中扮演着非常重要的角色 ... -
Positional Astronomy
2012-12-10 05:49 886http://www.jgiesen.de/elevaz/ba ... -
Ephemeris trail
2012-07-13 14:46 856http://www.astrosurf.com/jephem ... -
de406行星历表的结构
2012-07-12 17:14 1697以下 header.405 KSIZE= 2036 NC ... -
DE405/406星历表算法
2012-07-12 17:16 7176#pragma hdrstop #pragma argsuse ... -
农历24节气算法
2012-07-12 17:16 2596许剑伟 [摘要] 古老而 ... -
万年历计算之干支
2012-06-29 14:20 18911、基本知识 ... -
行星的位置计算
2010-11-20 17:25 3827许剑伟 莆田十中 [摘 ...
相关推荐
比如,可能定义了一个结构体来存储日期信息,并声明了计算节气的相关函数。 `MegaTimeV10.aps`和`megatimev10.aws`可能是编译或调试过程中产生的临时文件,或者与某种特定的开发环境或编译器相关,例如Visual ...
这个程序允许用户查询任何年份的日期信息,不仅限于公历,还包含了中国传统的农历以及与之相关的节气。 在描述“JS完美带农历、二十四节气的、可查询的万年历”中,再次确认了这个万年历的特点,即完美地整合了农历...
《纯JS实现的万年历:融合阴历、节日、星座与24节气》 在Web开发中,实现一个功能全面的日历组件是常见的需求,尤其是一个支持阴历、节假日、星座和24节气的万年历,能够极大地提升用户体验。本项目通过纯...
在实际项目中,开发者还需要具备一定的算法思维和问题解决能力,例如,如何高效地计算节气,如何优雅地处理农历和公历之间的转换等。通过这个项目,开发者不仅可以提升Python编程技能,还能深入理解日期时间处理和...
在本项目中,我们主要探讨的是如何使用Python编程语言,结合PyQt5库来构建一个具有农历和节气功能的万年历用户界面(UI)。PyQt5是Python中的一个强大的图形用户界面工具包,它提供了丰富的控件和功能,使得开发者...
本文将详细讲解一个重要的JavaScript(js)控件:带节日节气农历的万年历日期控件。这个控件集成了公历、农历、节日和节气,提供了一种全面的日历显示和选择功能。 首先,我们来理解“农历”。农历,又称阴历,是...
对于中国的用户来说,农历的重要性不言而喻,因为它涉及到许多传统节日和节气的计算。通过此软件,用户可以轻松查看每年的月、日、节气等农历信息,无论是查询特定日期的农历对应,还是提前准备节假日活动,都能...
### 万年历算法——阳历阴历24节气 #### 阳历算法解析 阳历(公历)的计算主要涉及日期与星期之间的转换。为了确定某一年、月、日对应的星期几,算法通常会通过一系列的数学运算来实现。在提供的代码片段中,可以...
在Android平台上,开发一个能够精确计算农历二十四节气的应用是一个具有挑战性和实用性的项目,尤其对于计算机科学与技术专业的毕业生来说,这样的毕业设计能够展示出扎实的编程基础和对传统文化的理解。下面将详细...
总之,这个MySQL万年历数据库集成了中国传统的农历、节气、天干地支和现代的星座等元素,为开发者提供了强大的日期和时间信息处理能力,适用于多种场景,无论是学术研究、软件开发还是日常生活查询。
开发过程中,开发者需要编写程序来计算节气,确保电子万年历能自动在正确的日期显示相应的节气信息。 此外,电路设计也是电子万年历项目的重要部分。电路图中会包含电源管理、MCU、RTC、显示屏和温度传感器的连接...
"日期js 万年历中提取的单天日期包括洋历农历节日节气等全部信息"这个主题涉及到了JavaScript编程语言中的日期处理,以及如何构建一个功能完备的万年历系统。下面我们将深入探讨这些知识点。 首先,JavaScript中的...
支持计算农历在1970-2040年 3、支持24节气显示。 4、支持日程记录,采用sqllite数据记录日程。 5、显示固定节假日。 6、万年历支持任意一年。支持跳转设置。 7、支持日程安排、提醒。 7、支持多平台,亲测!
本项目“Proteus单片机仿真 万年历支持温度农历24节气显示+源程序”是单片机编程的一个实例,它将万年历、温度显示、农历以及24节气功能集于一体,为学习者提供了丰富的实践素材。 1. Proteus仿真:Proteus是一款...
万年历数据库是一种专门用于存储和检索历法信息的数据库,包括公历、农历、节气等多样化的时间数据。在IT行业中,此类数据库通常被用于开发日历应用、时间管理软件或者与日期相关的计算工具。这里提到的"万年历...
在这个万年历程序中,`wannian.h`可能定义了表示日期的结构体,以及用于计算日期之间关系和移动日期的函数声明。这些函数可能包括: 1. 初始化日历:初始化当前日期,可能使用了`time()`函数获取系统时间。 2. 显示...
在Java万年历中,开发者需要编写特定的算法来计算每年的节气日期,确保与实际天文现象相吻合。 此外,Java万年历还支持显示系统当前时间,这需要调用Java的日期和时间API,如`java.util.Date`、`java.time`包中的`...
在C语言中,实现计算星期几以及构建一个万年历系统涉及到多个编程概念和技术。首先,我们需要理解基础的日期和时间处理,以及如何利用数学和逻辑来确定特定日期是星期几。以下是一些相关的知识点: 1. **日期表示**...
标题中的“Proteus单片机仿真 万年历支持温度农历24节气显示+源程序 硬件开发 - 单片机”表明这是一个关于使用Proteus软件进行单片机硬件开发的项目,重点是实现一个具有万年历功能的装置,能够显示温度、农历以及24...
在Android平台上开发应用程序时,有时候我们需要集成农历和万年历的功能,这通常涉及到中国的传统节气计算。"nongli.zip"是一个包含Android和Java代码的压缩包,它提供了农历和节气计算的相关功能。本文将详细介绍这...