Click here to Skip to main content
15,890,282 members
Articles / Programming Languages / Visual Basic

Calculate and Draw Moon Phase

Rate me:
Please Sign up or sign in to vote.
4.88/5 (32 votes)
12 Aug 2010CPOL1 min read 210.2K   4.2K   40   49
Calculate Moon's age and draw Moon Phase on any given day

Introduction

Many communities pay close attention to the lunar calendar next to the solar calendar, so I looked at many sites on the internet to know how to calculate the age of the moon on any given day. I found many sites offering different ways, I took what I found to give results closer to the truth.

I've noticed that most sites agree on the expense of the Julian date but do not agree to calculate the age of the moon, and found the difference between these sites up to one day, and when the moon's age is 30 days, the result is zero in some sites.

In this program, I calculated the approximate age of the moon in days and did not give attention to the parts of the day of the hours and minutes.

In order for the program would be more useful, I add PictureBox control to display the lighted part of the moon and darkness part of the moon commensurate with the age of the moon.

img039.JPG

Background

I created two projects, I wrote code of one in C# (2003) and wrote another in VB.NET (2003).

The MoonPhase project has one form (frmMoon) with the following controls:

  • MonthCalendar control (MyCalendar)
  • Button control (btnToDay)
  • Button control (btnClose)
  • PictureBox control (PicMoon)
  • Label control (lblAge)

About the Code

Convert date to Julian date:

C#
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)((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;
}

Calculate the approximate moon's age in days:

C#
private double MoonAge(int d, int m, int y)
{ 
    int j = JulianDate(d, m, y);
    //Calculate the approximate phase of the moon
    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)
        ag = ip * 29.53059 + 29.53059 / 2;
    else
        ag = ip * 29.53059 - 29.53059 / 2;
    // Moon's age in days
    ag = Math.Floor(ag) + 1;
    return ag;
}

Draw moon:

C#
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;
} 

You can go back to the source file to read the VB.NET code after you extract Moon_VB.zip file.

Final Words

If you have any idea or find another code to calculate the age of the moon, please tell me. Thanks to Code Project and thanks to all.

Mostafa Kaisoun
m_kaisoun@hotmail.com

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Egypt Egypt
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questiongreat start ... Pin
Southmountain1-Apr-23 10:01
Southmountain1-Apr-23 10:01 
QuestionSome advice needed on calculating ip in sub MoonAge Pin
Member 1447992019-Feb-22 8:04
Member 1447992019-Feb-22 8:04 
QuestionMoon phase program Pin
terry.corridan22-Aug-18 13:31
terry.corridan22-Aug-18 13:31 
AnswerRe: Moon phase program Pin
Southmountain1-Apr-23 11:09
Southmountain1-Apr-23 11:09 
QuestionJulian date calculation Pin
Borrisholt23-Jan-16 4:22
Borrisholt23-Jan-16 4:22 
Hi
Calculation JulianDate could be done a lot easier:

C#
private double DateTimeToJulianDate(DateTime date)
{
    return date.ToOADate() + 2415018.5;
}

private double DateTimeToJulianDate(int d, int m, int y)
{
    return DateTimeToJulianDate(new DateTime(y, m, d));
}



And the long explanation:

C#
/*if (Month< 3) ...: To make the magic numbers work our right, they're putting February at the 'end' of the year.
      (153 * Month - 457) / 5: Wow, that's some serious magic numbers.

      Normally, the number of days in each month is 31 28 31 30 31 30 31 31 30 31 30 31, but after that adjustment in the if statement,
      it becomes 31 30 31 30 31 31 30 31 30 31 31 28. Or, subtract 30 and you end up with 1 0 1 0 1 1 0 1 0 1 1 -2.
      They're creating that pattern of 1s and 0s by doing that division in integer space.

      Re-written to floating point, it would be(int)(30.6 * Month - 91.4).
      30.6 is the average number of days per month, excluding February(30.63 repeating, to be exact).
      91.4 is almost the number of days in 3 average non-February months. (30.6 * 3 is 91.8).

      So, let's remove the 30, and just focus on that 0.6 days. If we multiply it by the number of months, and then truncate to an integer, we'll get a pattern of 0s and 1s.
      •  0.6 * 0 = 0.0 -> 0
      •  0.6 * 1 = 0.6 -> 0 (difference of 0)
      •  0.6 * 2 = 1.2 -> 1 (difference of 1)
      •  0.6 * 3 = 1.8 -> 1 (difference of 0)
      •  0.6 * 4 = 2.4 -> 2 (difference of 1)
      •  0.6 * 5 = 3.0 -> 3 (difference of 1)
      •  0.6 * 6 = 3.6 -> 3 (difference of 0)
      •  0.6 * 7 = 4.2 -> 4 (difference of 1)
      •  0.6 * 8 = 4.8 -> 4 (difference of 0)

      See that pattern of differences in the right? That's the same pattern in the list above, the number of days in each month minus 30.
      The subtraction of 91.8 would compensate for the number of days in the first three months, that were moved to the 'end' of the year,
      and adjusting it by 0.4 moves the successive differences of 1 (0.6 * 4 and 0.6 * 5 in the above table) to align with the adjacent months that are 31 days.

      Since February is now at the 'end' of the year, we don't need to deal with its length.
      It could be 45 days long (46 on a leap year), and the only thing that would have to change is the constant for the number of days in a year, 365.
      Note that this relies on the pattern of 30 and 31 month days.If we had two months in a row that were 30 days, this would not be possible.
      365 * Year: Days per year (Year / 4) - (Year / 100) + (Year / 400): Plus one leap day every 4 years, minus one every 100, plus one every 400.

      + 1721119: This is the Julian Date of March 2nd, 1 BC.
      Since we moved the 'start' of the calendar from January to March, we use this as our offset, rather than January 1st.Since there is no year zero,
      1 BC gets the integer value 0. As for why March 2nd instead of March 1st, I'm guessing that's because that whole month calculation was still a little off at the end.
      If the original writer had used - 462 instead of - 457 (- 92.4 instead of - 91.4 in floating point math), then the offset would have been to March 1st.*/

QuestionAdd more feature Pin
Christianirwan26-Jun-13 0:39
Christianirwan26-Jun-13 0:39 
AnswerRe: Add more feature Pin
Mostafa Kaisoun26-Jun-13 3:02
Mostafa Kaisoun26-Jun-13 3:02 
SuggestionMoon phase Pin
Edward Omowa16-Apr-13 11:29
professionalEdward Omowa16-Apr-13 11:29 
GeneralRe: Moon phase Pin
Mostafa Kaisoun16-Apr-13 14:43
Mostafa Kaisoun16-Apr-13 14:43 
GeneralRe: Moon phase Pin
t9mike28-Mar-15 15:44
t9mike28-Mar-15 15:44 
Questionfrmoon Pin
Edward Omowa16-Apr-13 11:23
professionalEdward Omowa16-Apr-13 11:23 
GeneralMy vote of 5 Pin
DanielSheets5-Mar-13 7:31
DanielSheets5-Mar-13 7:31 
GeneralRe: My vote of 5 Pin
Mostafa Kaisoun6-Mar-13 5:40
Mostafa Kaisoun6-Mar-13 5:40 
GeneralMy vote of 5 Pin
Manoj Kumar Choubey1-Mar-12 22:18
professionalManoj Kumar Choubey1-Mar-12 22:18 
QuestionError, and another algorithm Pin
Robert Baker II7-Sep-11 5:50
Robert Baker II7-Sep-11 5:50 
AnswerRe: Error, and another algorithm Pin
Robert Baker II7-Sep-11 5:55
Robert Baker II7-Sep-11 5:55 
AnswerRe: Error, and another algorithm Pin
Mostafa Kaisoun7-Sep-11 9:03
Mostafa Kaisoun7-Sep-11 9:03 
GeneralDraw Moon Phase Pin
SergentX12-Jun-11 10:02
SergentX12-Jun-11 10:02 
GeneralRe: Draw Moon Phase Pin
Mostafa Kaisoun13-Jun-11 14:24
Mostafa Kaisoun13-Jun-11 14:24 
GeneralMy vote of 5 Pin
dim13123-Dec-10 4:38
dim13123-Dec-10 4:38 
GeneralMy vote of 5 Pin
Paul Conrad15-Sep-10 13:50
professionalPaul Conrad15-Sep-10 13:50 
GeneralGood job - Thanks for sharing... Pin
Steve Hageman16-Aug-10 19:11
Steve Hageman16-Aug-10 19:11 
GeneralRe: Good job - Thanks for sharing... Pin
Mostafa Kaisoun17-Aug-10 8:34
Mostafa Kaisoun17-Aug-10 8:34 
GeneralGood article Pin
dwilliss10-Aug-10 15:50
dwilliss10-Aug-10 15:50 
GeneralRe: Good article Pin
Mostafa Kaisoun11-Aug-10 3:58
Mostafa Kaisoun11-Aug-10 3:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.