using System; using System.Collections.Generic; using System.Text.RegularExpressions; namespace RobvanderWoude { internal class Easter { static readonly string progver = "1.00"; static readonly DateTime referencefullmoon = DateTime.Parse( "2022-01-17 23:48" ); static readonly double mooncycleindays = 29.53; static int Main( string[] args ) { int year; string dateformat = "yyyy-MM-dd"; if ( args.Length == 0 ) { year= DateTime.Now.Year; } else if ( args.Length > 2 || !int.TryParse( args[0], out year ) ) { return ShowHelp( ); } if ( args.Length == 2 ) { // date delimiters allowed: hyphen, forward slash, dot or space Regex regex = new Regex( "^(short|long|[dMy/ .-]{6,10})", RegexOptions.IgnoreCase ); if ( !regex.IsMatch( args[1] ) ) { return ShowHelp( "Invalid date format \"{0}\"", args[1] ); } dateformat = args[1].ToLower( ).Replace( 'm', 'M' ).Replace( "/", "'/'" ).Replace( "-", "'-'" ).Replace( ".", "'.'" ).Replace( " ", "' '" ); } // Easter is at first Sunday after the first full moon at or after the Spring equinox (21 March) // Calculation explained: https://www.timeanddate.com/calendar/determining-easter-date.html // For Easter calculations, the Spring equinox is always assumed to be at 21 March DateTime springequinox = DateTime.Parse( string.Format( "{0}-03-21", year ) ); // Calculate full moon cycles to first full moon after Spring equinox of specified year int fullcycles = (int)Math.Ceiling( springequinox.Subtract( referencefullmoon ).Days / mooncycleindays ); // Date of first full moon after Spring equinox of specified year DateTime fullmoonafterequinox = referencefullmoon.AddDays( fullcycles * mooncycleindays ); // First Sunday following first full moon at or after Spring equinox of specified year DateTime eastersunday = fullmoonafterequinox.AddDays( 7 - (int)fullmoonafterequinox.DayOfWeek ).Date; // Display reasult on screen string wasisorwillbe = "is today,"; if ( DateTime.Compare( eastersunday, DateTime.Now.Date ) < 0 ) { wasisorwillbe = "was at"; } else if ( DateTime.Compare( eastersunday, DateTime.Now.Date ) > 0 ) { wasisorwillbe = "will be at"; } string easterdatestring; if ( dateformat == "short" ) { easterdatestring = eastersunday.ToShortDateString( ); } else if ( dateformat == "long" ) { easterdatestring = eastersunday.ToLongDateString( ); } else { easterdatestring = eastersunday.ToString( dateformat ); } Console.WriteLine( "Easter Sunday {0} {1} {2}", year, wasisorwillbe, easterdatestring ); // Return code equals Easter Sunday's DayOfYear return eastersunday.DayOfYear; } static int ShowHelp( params string[] errmsg ) { #region Error Message if ( errmsg.Length > 0 ) { List errargs = new List( errmsg ); errargs.RemoveAt( 0 ); Console.Error.WriteLine( ); Console.ForegroundColor = ConsoleColor.Red; Console.Error.Write( "ERROR:\t" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) ); Console.ResetColor( ); } #endregion Error Message #region Help Text /* Easter.exe, Version 1.00 Calculate the date of Easter Sunday for the specified year Usage: Easter.exe [ year [ format ] ] Where: year is the year to calculate Easter date for (default: current year; see notes for before 100 AD) format is the output format for the returned date: either "short", "long" or a combination of 6..10 "y", "M", "d" characters, hyphens, forward slashes, dots and/or spaces (default: "yyyy-MM-dd") Notes: Easter Sunday is at the first Sunday after the first full moon at or after the Spring equinox, which for Easter calculations is assumed to be always at March 21. Years before 100 AD will be interpreted as 2000 + specified year. The program's return code equals the calculated date's DayOfYear value, or -1 in case of (command line) errors. Credits: Easter calculation explained: https://www.timeanddate.com/calendar/determining-easter-date.html Fix to use alternative date delimiter by Jon Skeet: https://stackoverflow.com/a/5641084 Written by Rob van der Woude https://www.robvanderwoude.com */ #endregion Help Text #region Display Help Text Console.Error.WriteLine( ); Console.Error.WriteLine( "Easter.exe, Version {0}", progver ); Console.Error.WriteLine( "Calculate the date of Easter Sunday for the specified year" ); Console.Error.WriteLine( ); Console.Error.Write( "Usage: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "Easter.exe [ year [ format ] ]" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Where: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "year" ); Console.ResetColor( ); Console.Error.WriteLine( " is the year to calculate Easter date for" ); Console.Error.WriteLine( " (default: current year; see notes for before 100 AD)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " format" ); Console.ResetColor( ); Console.Error.WriteLine( " is the output format for the returned date: either" ); Console.ResetColor( ); Console.Error.Write( " \"" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "short" ); Console.ResetColor( ); Console.Error.Write( "\", \"" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "long" ); Console.ResetColor( ); Console.Error.Write( "\" or a combination of 6..10 \"" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "y" ); Console.ResetColor( ); Console.Error.Write( "\", \"" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "M" ); Console.ResetColor( ); Console.Error.WriteLine( "\"," ); Console.Error.Write( " \"" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "d" ); Console.ResetColor( ); Console.Error.WriteLine( "\" characters, hyphens, forward slashes, dots and/or" ); Console.Error.Write( " spaces (default: \"" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "yyyy-MM-dd" ); Console.ResetColor( ); Console.Error.WriteLine( "\")" ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Notes: Easter Sunday is at the first Sunday after the first full moon at or" ); Console.Error.WriteLine( " after the Spring equinox, which for Easter calculations is assumed" ); Console.Error.WriteLine( " to be always at March 21." ); Console.Error.WriteLine( " Years before 100 AD will be interpreted as 2000 + specified year." ); Console.Error.WriteLine( " The program's return code equals the calculated date's DayOfYear" ); Console.Error.WriteLine( " value, or -1 in case of (command line) errors." ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Credits: Easter calculation explained:" ); Console.ForegroundColor = ConsoleColor.DarkGray; Console.Error.WriteLine( " https://www.timeanddate.com/calendar/determining-easter-date.html" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Written by Rob van der Woude" ); Console.Error.WriteLine( "https://www.robvanderwoude.com" ); #endregion Display Help Text return -1; } } }