在研究日历的时候,通常会关注公历,但很少有人注意到农历。为了计算任何给定日期的月球年龄,浏览了互联网上的许多网站。发现许多网站提供了不同的计算方法,采纳了其中一些方法,以期得到更接近真实情况的结果。
注意到,大多数网站在计算儒略日时意见一致,但在计算月球年龄时却存在分歧,这些网站之间的差异可能高达一天。当月球年龄为30天时,一些网站的结果为零。
在这个程序中,计算了月球的大致年龄(以天为单位),并没有关注小时和分钟的部分。为了让程序更有用,添加了一个PictureBox控件来显示与月球年龄相对应的月球亮面和暗面。
创建了两个项目,一个用C#(2003)编写,另一个用VB.NET(2003)编写。MoonPhase项目有一个表单(frmMoon),包含以下控件:MonthCalendar控件(MyCalendar)、Button控件(btnToDay)、Button控件(btnClose)、PictureBox控件(PicMoon)和Label控件(lblAge)。
将日期转换为儒略日:
private int JulianDate(int d, int m, int y) {
    int mm, yy;
    int k1, k2, k3;
    int j;
    yy = y - (int)((12 - m) / 10);
    mm = m + 9;
    if (mm >= 12) {
        mm = mm - 12;
    }
    k1 = (int)(365.25 * (yy + 4712));
    k2 = (int)(30.6001 * mm + 0.5);
    k3 = (int)((yy / 100) + 49) * 0.75 - 38;
    // 'j' for dates in Julian calendar:
    j = k1 + k2 + d + 59;
    if (j > 2299160) {
        // For Gregorian calendar:
        j = j - k3;
    }
    // 'j' is the Julian date at 12h UT (Universal Time)
    return j;
}
    
计算月球的大致年龄(以天为单位):
private double MoonAge(int d, int m, int y) {
    int j = JulianDate(d, m, y);
    // Calculate the approximate phase of the moon
    double ip = (j + 4.867) / 29.53059;
    ip = ip - Math.Floor(ip);
    // After several trials I've seen to add the following lines,
    // which gave the result was not bad
    if (ip < 0.5) {
        double ag = ip * 29.53059 + 29.53059 / 2;
    } else {
        double ag = ip * 29.53059 - 29.53059 / 2;
    }
    // Moon's age in days
    ag = Math.Floor(ag) + 1;
    return ag;
}
    
绘制月球:
private void DrawMoon() {
    int Xpos, Ypos, Rpos;
    int Xpos1, Xpos2;
    double Phase;
    Phase = ip;
    // Width of 'ImageToDraw' Object = Width of 'PicMoon' control
    int PageWidth = PicMoon.Width;
    // Height of 'ImageToDraw' Object = Height of 'PicMoon' control
    int PageHeight = PicMoon.Height;
    // Initiate 'ImageToDraw' Object with size = size of control 'PicMoon' control
    Bitmap ImageToDraw = new Bitmap(PageWidth, PageHeight);
    // Create graphics object for alteration.
    Graphics newGraphics = Graphics.FromImage(ImageToDraw);
    Pen PenB = new Pen(Color.Black);
    // For darkness part of the moon
    Pen PenW = new Pen(Color.White);
    // For the lighted part of the moon
    for (Ypos = 0; Ypos <= 45; Ypos++) {
        Xpos = (int)Math.Sqrt(45 * 45 - Ypos * Ypos);
        // Draw darkness part of the moon
        Point pB1 = new Point(90 - Xpos, Ypos + 90);
        Point pB2 = new Point(Xpos + 90, Ypos + 90);
        Point pB3 = new Point(90 - Xpos, 90 - Ypos);
        Point pB4 = new Point(Xpos + 90, 90 - Ypos);
        newGraphics.DrawLine(PenB, pB1, pB2);
        newGraphics.DrawLine(PenB, pB3, pB4);
        // Determine the edges of the lighted part of the moon
        Rpos = 2 * Xpos;
        if (Phase < 0.5) {
            Xpos1 = -Xpos;
            Xpos2 = (int)(Rpos - 2 * Phase * Rpos - Xpos);
        } else {
            Xpos1 = Xpos;
            Xpos2 = (int)(Xpos - 2 * Phase * Rpos + Rpos);
        }
        // Draw the lighted part of the moon
        Point pW1 = new Point(Xpos1 + 90, 90 - Ypos);
        Point pW2 = new Point(Xpos2 + 90, 90 - Ypos);
        Point pW3 = new Point(Xpos1 + 90, Ypos + 90);
        Point pW4 = new Point(Xpos2 + 90, Ypos + 90);
        newGraphics.DrawLine(PenW, pW1, pW2);
        newGraphics.DrawLine(PenW, pW3, pW4);
    }
    // Display the bitmap in the picture box.
    PicMoon.Image = ImageToDraw;
    // Release graphics object
    PenB.Dispose();
    PenW.Dispose();
    newGraphics.Dispose();
    ImageToDraw = null;
}
    
如果想查看VB.NET代码,请解压Moon_VB.zip文件后返回源文件。