//============================================================================
//ZedGraph Class Library - A Flexible Line Graph/Bar Graph Library in C#
//Copyright ?2004  John Champion
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU Lesser General Public
//License as published by the Free Software Foundation; either
//version 2.1 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//Lesser General Public License for more details.
//
//You should have received a copy of the GNU Lesser General Public
//License along with this library; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//=============================================================================
using System;
namespace DrawGraph
{
	
	/// 
	/// This struct encapsulates a date and time value, and handles associated
	/// calculations and conversions between various formats.
	/// 
	/// 
	/// This format stored as a double value representing days since a reference date
	/// (XL date 0.0 is December 30, 1899 at 00:00 hrs).
	/// Negative values are permissible, and the
	/// range of valid dates is from noon on January 1st, 4713 B.C. forward.  Internally, the
	/// date calculations are done using Astronomical Julian Day numbers.  The Astronomical Julian
	/// Day number is defined as the number of days since noon on January 1st, 4713 B.C.
	/// (also referred to as 12:00 on January 1, -4712).
	/// NOTE: MS Excel actually has an error in the Serial Date calculations because it
	/// errantly assumes 1900 is a leap year.  The XDate calculations do not have this same
	/// error.  Therefore, XDate and Excel Date Serial values are 1 day different up until
	/// the date value of 60 (in Excel, this is February 29th, 1900, and in XDate, this is
	/// February 28th, 1900).  At a value of 61 (March 1st, 1900) or greater, they agree with
	/// eachother.
	/// 
	///  John Champion 
	///  $Revision: 3.20 $ $Date: 2007/03/11 02:08:16 $ 
	public struct XDate //: ICloneable
	{
	#region Fields & Constants
		// =========================================================================
		// Internal Variables
		// =========================================================================
	
		/// 
		/// The actual date value in MS Excel format.  This is the only data field in
		/// the  struct.
		/// 
		private double _xlDate;
		
		/// 
		/// The Astronomical Julian Day number that corresponds to XL Date 0.0
		/// 
		public const double XLDay1 = 2415018.5;
		/// 
		/// The minimum valid Julian Day, which corresponds to January 1st, 4713 B.C.
		/// 
		public const double JulDayMin = 0.0;
		/// 
		/// The maximum valid Julian Day, which corresponds to December 31st, 9999 A.D.
		/// 
		public const double JulDayMax = 5373483.5;
		/// 
		/// The minimum valid Excel Day, which corresponds to January 1st, 4713 B.C.
		/// 
		public const double XLDayMin = JulDayMin - XLDay1;
		/// 
		/// The maximum valid Excel Day, which corresponds to December 31st, 9999 A.D.
		/// 
		public const double XLDayMax = JulDayMax - XLDay1;
		/// 
		/// The number of months in a year
		/// 
		public const double MonthsPerYear = 12.0;
		/// 
		/// The number of hours in a day
		/// 
		public const double HoursPerDay = 24.0;
		/// 
		/// The number of minutes in an hour
		/// 
		public const double MinutesPerHour = 60.0;
		/// 
		/// The number of seconds in a minute
		/// 
		public const double SecondsPerMinute = 60.0;
		/// 
		/// The number of minutes in a day
		/// 
		public const double MinutesPerDay = 1440.0;
		/// 
		/// The number of seconds in a day
		/// 
		public const double SecondsPerDay = 86400.0;
		/// 
		/// The number of milliseconds in a second
		/// 
		public const double MillisecondsPerSecond = 1000.0;
		/// 
		/// The number of milliseconds in a day
		/// 
		public const double MillisecondsPerDay = 86400000.0;
		/// 
		/// The default format string to be used in  when
		/// no format is provided
		/// 
//		public const string DefaultFormatStr = "&d-&mmm-&yy &hh:&nn";
		public const string DefaultFormatStr = "g";
	#endregion
	
	#region Constructors
		// =========================================================================
		// Constructors
		// =========================================================================
		/// 
		/// Construct a date class from an XL date value.
		/// 
		/// 
		/// An XL Date value in floating point double format
		/// 
		public XDate( double xlDate )
		{
			_xlDate = xlDate;
		}
		
		/// 
		/// Construct a date class from a  struct.
		/// 
		/// 
		/// A  struct containing the initial date information.
		/// 
		public XDate( DateTime dateTime )
		{
			_xlDate = CalendarDateToXLDate( dateTime.Year, dateTime.Month,
							dateTime.Day, dateTime.Hour, dateTime.Minute, dateTime.Second,
							dateTime.Millisecond );
		}
		
		/// 
		/// Construct a date class from a calendar date (year, month, day).  Assumes the time
		/// of day is 00:00 hrs
		/// 
		/// An integer value for the year, e.g., 1995.
		/// An integer value for the day of the month, e.g., 23.
		/// It is permissible to have day numbers outside of the 1-31 range,
		/// which will rollover to the previous or next month and year.
		/// An integer value for the month of the year, e.g.,
		/// 8 for August.  It is permissible to have months outside of the 1-12 range,
		/// which will rollover to the previous or next year.
		public XDate( int year, int month, int day )
		{
			_xlDate = CalendarDateToXLDate( year, month, day, 0, 0, 0 );
		}
		
		/// 
		/// Construct a date class from a calendar date and time (year, month, day, hour, minute,
		/// second). 
		/// 
		/// An integer value for the year, e.g., 1995.
		/// An integer value for the day of the month, e.g., 23.
		/// It is permissible to have day numbers outside of the 1-31 range,
		/// which will rollover to the previous or next month and year.
		/// An integer value for the month of the year, e.g.,
		/// 8 for August.  It is permissible to have months outside of the 1-12 range,
		/// which will rollover to the previous or next year.
		/// An integer value for the hour of the day, e.g. 15.
		/// It is permissible to have hour values outside the 0-23 range, which
		/// will rollover to the previous or next day.
		/// An integer value for the minute, e.g. 45.
		/// It is permissible to have hour values outside the 0-59 range, which
		/// will rollover to the previous or next hour.
		/// An integer value for the second, e.g. 35.
		/// It is permissible to have second values outside the 0-59 range, which
		/// will rollover to the previous or next minute.
		public XDate( int year, int month, int day, int hour, int minute, int second )
		{
			_xlDate = CalendarDateToXLDate( year, month, day, hour, minute, second );
		}
		
		/// 
		/// Construct a date class from a calendar date and time (year, month, day, hour, minute,
		/// second), where seconds is a  value (allowing fractional seconds). 
		/// 
		/// An integer value for the year, e.g., 1995.
		/// An integer value for the day of the month, e.g., 23.
		/// It is permissible to have day numbers outside of the 1-31 range,
		/// which will rollover to the previous or next month and year.
		/// An integer value for the month of the year, e.g.,
		/// 8 for August.  It is permissible to have months outside of the 1-12 range,
		/// which will rollover to the previous or next year.
		/// An integer value for the hour of the day, e.g. 15.
		/// It is permissible to have hour values outside the 0-23 range, which
		/// will rollover to the previous or next day.
		/// An integer value for the minute, e.g. 45.
		/// It is permissible to have hour values outside the 0-59 range, which
		/// will rollover to the previous or next hour.
		/// A double value for the second, e.g. 35.75.
		/// It is permissible to have second values outside the 0-59 range, which
		/// will rollover to the previous or next minute.
		public XDate( int year, int month, int day, int hour, int minute, double second )
		{
			_xlDate = CalendarDateToXLDate( year, month, day, hour, minute, second );
		}
		
		/// 
		/// Construct a date class from a calendar date and time (year, month, day, hour, minute,
		/// second, millisecond). 
		/// 
		/// An integer value for the year, e.g., 1995.
		/// An integer value for the day of the month, e.g., 23.
		/// It is permissible to have day numbers outside of the 1-31 range,
		/// which will rollover to the previous or next month and year.
		/// An integer value for the month of the year, e.g.,
		/// 8 for August.  It is permissible to have months outside of the 1-12 range,
		/// which will rollover to the previous or next year.
		/// An integer value for the hour of the day, e.g. 15.
		/// It is permissible to have hour values outside the 0-23 range, which
		/// will rollover to the previous or next day.
		/// An integer value for the minute, e.g. 45.
		/// It is permissible to have hour values outside the 0-59 range, which
		/// will rollover to the previous or next hour.
		/// An integer value for the second, e.g. 35.
		/// It is permissible to have second values outside the 0-59 range, which
		/// will rollover to the previous or next minute.
		/// An integer value for the millisecond, e.g. 632.
		/// It is permissible to have millisecond values outside the 0-999 range, which
		/// will rollover to the previous or next second.
		public XDate( int year, int month, int day, int hour, int minute, int second, int millisecond )
		{
			_xlDate = CalendarDateToXLDate( year, month, day, hour, minute, second, millisecond );
		}
		
		/// 
		/// The Copy Constructor
		/// 
		/// The GraphPane object from which to copy
		public XDate( XDate rhs )
		{
			_xlDate = rhs._xlDate;
		}
/*
		/// 
		/// Implement the  interface in a typesafe manner by just
		/// calling the typed version of 
		/// 
		/// A deep copy of this object
		object ICloneable.Clone()
		{
			return this.Clone();
		}
		/// 
		/// Typesafe, deep-copy clone method.
		/// 
		/// A new, independent copy of this class
		public XDate Clone()
		{
			return new XDate( this );
		}
*/
	#endregion
	
	#region Properties
		// =========================================================================
		// Properties
		// =========================================================================
	
		/// 
		/// Gets or sets the date value for this item in MS Excel format.
		/// 
		public double XLDate
		{
			get { return _xlDate; }
			set { _xlDate = value; }
		}
		/// 
		/// Returns true if this  struct is in the valid date range
		/// 
		public bool IsValidDate
		{
			get { return _xlDate >= XLDayMin && _xlDate <= XLDayMax; }
		}
		
		/// 
		/// Gets or sets the date value for this item in .Net DateTime format.
		/// 
		public DateTime DateTime
		{
			get { return XLDateToDateTime( _xlDate ); }
			set { _xlDate = DateTimeToXLDate( value ); }
		}
		
		/// 
		/// Gets or sets the date value for this item in Julain day format.  This is the
		/// Astronomical Julian Day number, so a value of 0.0 corresponds to noon GMT on
		/// January 1st, -4712.  Thus, Julian Day number 2,400,000.0 corresponds to
		/// noon GMT on November 16, 1858.
		/// 
		public double JulianDay
		{
			get { return XLDateToJulianDay( _xlDate ); }
			set { _xlDate = JulianDayToXLDate( value ); }
		}
		
		/// 
		/// Gets or sets the decimal year number (i.e., 1997.345) corresponding to this item.
		/// 
		public double DecimalYear
		{
			get { return XLDateToDecimalYear( _xlDate ); }
			set { _xlDate = DecimalYearToXLDate( value ); }
		}
	#endregion
	
	#region Get/Set Date Methods
		/// 
		/// Returns true if the specified date value is in the valid range
		/// 
		/// The XL date value to be verified for validity
		/// true for a valid date, false otherwise
		private static bool CheckValidDate( double xlDate )
		{
			return xlDate >= XLDayMin && xlDate <= XLDayMax;
		}
		/// 
		/// Take the specified date, and bound it to the valid date range for the XDate struct.
		/// 
		/// The date to be bounded
		/// An XLDate value that lies between the minimum and maximum valid date ranges
		/// (see  and )
		public static double MakeValidDate( double xlDate )
		{
			if ( xlDate < XLDayMin )
				xlDate = XLDayMin;
			if ( xlDate > XLDayMax )
				xlDate = XLDayMax;
			return xlDate;
		}
		/// 
		/// Get the calendar date (year, month, day) corresponding to this instance.
		/// 
		/// An integer value for the year, e.g., 1995.
		/// An integer value for the day of the month, e.g., 23.
		/// An integer value for the month of the year, e.g.,
		/// 8 for August.
		public void GetDate( out int year, out int month, out int day )
		{
			int hour, minute, second;
			
			XLDateToCalendarDate( _xlDate, out year, out month, out day, out hour, out minute, out second );
		}
		
		/// 
		/// Set the calendar date (year, month, day) of this instance.
		/// 
		/// An integer value for the year, e.g., 1995.
		/// An integer value for the day of the month, e.g., 23.
		/// An integer value for the month of the year, e.g.,
		/// 8 for August.
		public void SetDate( int year, int month, int day )
		{
			_xlDate = CalendarDateToXLDate( year, month, day, 0, 0, 0 );
		}
		
		/// 
		/// Get the calendar date (year, month, day, hour, minute, second) corresponding
		/// to this instance.
		/// 
		/// An integer value for the year, e.g., 1995.
		/// An integer value for the day of the month, e.g., 23.
		/// An integer value for the month of the year, e.g.,
		/// 8 for August.
		/// An integer value for the hour of the day, e.g. 15.
		/// An integer value for the minute, e.g. 45.
		/// An integer value for the second, e.g. 35.
		public void GetDate( out int year, out int month, out int day,
						out int hour, out int minute, out int second )
		{
			XLDateToCalendarDate( _xlDate, out year, out month, out day, out hour, out minute, out second );
		}
		/// 
		/// Set the calendar date (year, month, day, hour, minute, second) of this instance.
		/// 
		/// An integer value for the year, e.g., 1995.
		/// An integer value for the day of the month, e.g., 23.
		/// An integer value for the month of the year, e.g.,
		/// 8 for August.
		/// An integer value for the hour of the day, e.g. 15.
		/// An integer value for the minute, e.g. 45.
		/// An integer value for the second, e.g. 35.
		public void SetDate( int year, int month, int day, int hour, int minute, int second )
		{
			_xlDate = CalendarDateToXLDate( year, month, day, hour, minute, second );
		}
		
		/// 
		/// Get the day of year value (241.345 means the 241st day of the year)
		/// corresponding to this instance.
		/// 
		/// The day of the year in floating point double format.
		public double GetDayOfYear()
		{
			return XLDateToDayOfYear( _xlDate );
		}
	#endregion
	
	#region Date Conversion Methods
		// =========================================================================
		// Conversion Routines
		// =========================================================================
	
		/// 
		/// Calculate an XL Date from the specified Calendar date (year, month, day, hour, minute, second),
		/// first normalizing all input data values.
		/// 
		/// 
		/// The Calendar date is always based on the Gregorian Calendar.  Note that the Gregorian calendar is really
		/// only valid from October 15, 1582 forward.  The countries that adopted the Gregorian calendar
		/// first did so on October 4, 1582, so that the next day was October 15, 1582.  Prior to that time
		/// the Julian Calendar was used.  However, Prior to March 1, 4 AD the treatment of leap years was
		/// inconsistent, and prior to 45 BC the Julian Calendar did not exist.  The 
		/// struct projects only Gregorian dates backwards and does not deal with Julian calendar dates at all.  The
		///  method will just append a "(BC)" notation to the end of any dates
		/// prior to 1 AD, since the  struct throws an exception when formatting earlier dates.
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The integer second value (e.g., 42 for 42 seconds past the minute).
		/// 
		/// 
		/// The integer millisecond value (e.g., 374 for 374 milliseconds past the second).
		/// 
		/// The corresponding XL date, expressed in double floating point format
		public static double CalendarDateToXLDate( int year, int month, int day,
			int hour, int minute, int second, int millisecond )
		{
			// Normalize the data to allow for negative and out of range values
			// In this way, setting month to zero would be December of the previous year,
			// setting hour to 24 would be the first hour of the next day, etc.
			//double dsec = second + (double) millisecond / MillisecondsPerSecond;
			double ms = millisecond;
			NormalizeCalendarDate( ref year, ref month, ref day, ref hour, ref minute, ref second,
						ref ms );
		
			return _CalendarDateToXLDate( year, month, day, hour, minute, second, ms );
		}
		
		/// 
		/// Calculate an XL Date from the specified Calendar date (year, month, day, hour, minute, second),
		/// first normalizing all input data values.
		/// 
		/// 
		/// The Calendar date is always based on the Gregorian Calendar.  Note that the Gregorian calendar is really
		/// only valid from October 15, 1582 forward.  The countries that adopted the Gregorian calendar
		/// first did so on October 4, 1582, so that the next day was October 15, 1582.  Prior to that time
		/// the Julian Calendar was used.  However, Prior to March 1, 4 AD the treatment of leap years was
		/// inconsistent, and prior to 45 BC the Julian Calendar did not exist.  The 
		/// struct projects only Gregorian dates backwards and does not deal with Julian calendar dates at all.  The
		///  method will just append a "(BC)" notation to the end of any dates
		/// prior to 1 AD, since the  struct throws an exception when formatting earlier dates.
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The integer second value (e.g., 42 for 42 seconds past the minute).
		/// 
		/// The corresponding XL date, expressed in double floating point format
		public static double CalendarDateToXLDate( int year, int month, int day,
			int hour, int minute, int second )
		{
			// Normalize the data to allow for negative and out of range values
			// In this way, setting month to zero would be December of the previous year,
			// setting hour to 24 would be the first hour of the next day, etc.
			double ms = 0;
			NormalizeCalendarDate( ref year, ref month, ref day, ref hour, ref minute,
					ref second, ref ms );
		
			return _CalendarDateToXLDate( year, month, day, hour, minute, second, ms );
		}
		
		/// 
		/// Calculate an XL Date from the specified Calendar date (year, month, day, hour, minute, second),
		/// first normalizing all input data values.  The seconds value is a double type, allowing fractional
		/// seconds.
		/// 
		/// 
		/// The Calendar date is always based on the Gregorian Calendar.  Note that the Gregorian calendar is really
		/// only valid from October 15, 1582 forward.  The countries that adopted the Gregorian calendar
		/// first did so on October 4, 1582, so that the next day was October 15, 1582.  Prior to that time
		/// the Julian Calendar was used.  However, Prior to March 1, 4 AD the treatment of leap years was
		/// inconsistent, and prior to 45 BC the Julian Calendar did not exist.  The 
		/// struct projects only Gregorian dates backwards and does not deal with Julian calendar dates at all.  The
		///  method will just append a "(BC)" notation to the end of any dates
		/// prior to 1 AD, since the  struct throws an exception when formatting earlier dates.
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The double second value (e.g., 42.3 for 42.3 seconds past the minute).
		/// 
		/// The corresponding XL date, expressed in double floating point format
		public static double CalendarDateToXLDate( int year, int month, int day,
			int hour, int minute, double second )
		{
			// Normalize the data to allow for negative and out of range values
			// In this way, setting month to zero would be December of the previous year,
			// setting hour to 24 would be the first hour of the next day, etc.
			int sec = (int)second;
			double ms = ( second - sec ) * MillisecondsPerSecond;
			NormalizeCalendarDate( ref year, ref month, ref day, ref hour, ref minute, ref sec,
					ref ms );
		
			return _CalendarDateToXLDate( year, month, day, hour, minute, sec, ms );
		}
		
		/// 
		/// Calculate an Astronomical Julian Day number from the specified Calendar date
		/// (year, month, day, hour, minute, second), first normalizing all input data values
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The integer second value (e.g., 42 for 42 seconds past the minute).
		/// 
		/// The corresponding Astronomical Julian Day number, expressed in double
		/// floating point format
		public static double CalendarDateToJulianDay( int year, int month, int day,
			int hour, int minute, int second )
		{
			// Normalize the data to allow for negative and out of range values
			// In this way, setting month to zero would be December of the previous year,
			// setting hour to 24 would be the first hour of the next day, etc.
			double ms = 0;
			NormalizeCalendarDate( ref year, ref month, ref day, ref hour, ref minute,
				ref second, ref ms );
		
			return _CalendarDateToJulianDay( year, month, day, hour, minute, second, ms );
		}
		
		/// 
		/// Calculate an Astronomical Julian Day number from the specified Calendar date
		/// (year, month, day, hour, minute, second), first normalizing all input data values
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The integer second value (e.g., 42 for 42 seconds past the minute).
		/// 
		/// 
		/// The integer second value (e.g., 325 for 325 milliseconds past the minute).
		/// 
		/// The corresponding Astronomical Julian Day number, expressed in double
		/// floating point format
		public static double CalendarDateToJulianDay( int year, int month, int day,
			int hour, int minute, int second, int millisecond )
		{
			// Normalize the data to allow for negative and out of range values
			// In this way, setting month to zero would be December of the previous year,
			// setting hour to 24 would be the first hour of the next day, etc.
			double ms = millisecond;
			NormalizeCalendarDate( ref year, ref month, ref day, ref hour, ref minute,
						ref second, ref ms );
		
			return _CalendarDateToJulianDay( year, month, day, hour, minute, second, ms );
		}
		
		/// 
		/// Normalize a set of Calendar date values (year, month, day, hour, minute, second) to make sure
		/// that month is between 1 and 12, hour is between 0 and 23, etc.
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The integer second value (e.g., 42 for 42 seconds past the minute).
		/// 
		/// 
		/// The double millisecond value (e.g., 325.3 for 325.3 milliseconds past the second).
		/// 
		private static void NormalizeCalendarDate( ref int year, ref int month, ref int day,
											ref int hour, ref int minute, ref int second,
											ref double millisecond )
		{
			// Normalize the data to allow for negative and out of range values
			// In this way, setting month to zero would be December of the previous year,
			// setting hour to 24 would be the first hour of the next day, etc.
			// Normalize the milliseconds and carry over to seconds
			int carry = (int)Math.Floor( millisecond / MillisecondsPerSecond );
			millisecond -= carry * (int)MillisecondsPerSecond;
			second += carry;
			// Normalize the seconds and carry over to minutes
			carry = (int)Math.Floor( second / SecondsPerMinute );
			second -= carry * (int)SecondsPerMinute;
			minute += carry;
		
			// Normalize the minutes and carry over to hours
			carry = (int) Math.Floor( (double) minute / MinutesPerHour );
			minute -= carry * (int) MinutesPerHour;
			hour += carry;
		
			// Normalize the hours and carry over to days
			carry = (int) Math.Floor( (double) hour / HoursPerDay );
			hour -= carry * (int) HoursPerDay;
			day += carry;
		
			// Normalize the months and carry over to years
			carry = (int) Math.Floor( (double) month / MonthsPerYear );
			month -= carry * (int) MonthsPerYear;
			year += carry;
		}
		
		/// 
		/// Calculate an XL date from the specified Calendar date (year, month, day, hour, minute, second).
		/// This is the internal trusted version, where all values are assumed to be legitimate
		/// ( month is between 1 and 12, minute is between 0 and 59, etc. )
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The integer second value (e.g., 42 for 42 seconds past the minute).
		/// 
		/// 
		/// The double millisecond value (e.g., 325.3 for 325.3 milliseconds past the second).
		/// 
		/// The corresponding XL date, expressed in double floating point format
		private static double _CalendarDateToXLDate( int year, int month, int day, int hour,
					int minute, int second, double millisecond )
		{
			return JulianDayToXLDate( _CalendarDateToJulianDay( year, month, day, hour, minute,
						second, millisecond ) );
		}
		
		/// 
		/// Calculate an Astronomical Julian Day Number from the specified Calendar date
		/// (year, month, day, hour, minute, second).
		/// This is the internal trusted version, where all values are assumed to be legitimate
		/// ( month is between 1 and 12, minute is between 0 and 59, etc. )
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The integer second value (e.g., 42 for 42 seconds past the minute).
		/// 
		/// 
		/// The double millisecond value (e.g., 325.3 for 325.3 milliseconds past the second).
		/// 
		/// The corresponding Astronomical Julian Day number, expressed in double
		/// floating point format
		private static double _CalendarDateToJulianDay( int year, int month, int day, int hour,
					int minute, int second, double millisecond )
		{
			// Taken from http://www.srrb.noaa.gov/highlights/sunrise/program.txt
			// routine calcJD()
		
			if ( month <= 2 )
			{
				year -= 1;
				month += 12;
			}
		
			double A = Math.Floor( (double) year / 100.0 );
			double B = 2 - A + Math.Floor( A / 4.0 );
		
			return	Math.Floor( 365.25 * ( (double) year + 4716.0 ) ) +
					Math.Floor( 30.6001 * (double) ( month + 1 ) ) +
					(double) day + B - 1524.5 +
					hour  / HoursPerDay + minute / MinutesPerDay + second / SecondsPerDay +
					millisecond / MillisecondsPerDay;
		
		}
		/// 
		/// Calculate a Calendar date (year, month, day, hour, minute, second) corresponding to
		/// the specified XL date
		/// 
		/// 
		/// The XL date value in floating point double format.
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The integer second value (e.g., 42 for 42 seconds past the minute).
		/// 
		public static void XLDateToCalendarDate( double xlDate, out int year, out int month,
			out int day, out int hour, out int minute, out int second )
		{
			double jDay = XLDateToJulianDay( xlDate );
			
			JulianDayToCalendarDate( jDay, out year, out month, out day, out hour,
				out minute, out second );
		}
		
		/// 
		/// Calculate a Calendar date (year, month, day, hour, minute, second) corresponding to
		/// the specified XL date
		/// 
		/// 
		/// The XL date value in floating point double format.
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The integer second value (e.g., 42 for 42 seconds past the minute).
		/// 
		/// 
		/// The integer millisecond value (e.g., 325 for 325 milliseconds past the second).
		/// 
		public static void XLDateToCalendarDate( double xlDate, out int year, out int month,
			out int day, out int hour, out int minute, out int second, out int millisecond )
		{
			double jDay = XLDateToJulianDay( xlDate );
			
			double ms;
			JulianDayToCalendarDate( jDay, out year, out month, out day, out hour,
				out minute, out second, out ms );
			millisecond = (int)ms;
		}
		
		/// 
		/// Calculate a Calendar date (year, month, day, hour, minute, second) corresponding to
		/// the specified XL date
		/// 
		/// 
		/// The XL date value in floating point double format.
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The double second value (e.g., 42.3 for 42.3 seconds past the minute).
		/// 
		public static void XLDateToCalendarDate( double xlDate, out int year, out int month,
			out int day, out int hour, out int minute, out double second )
		{
			double jDay = XLDateToJulianDay( xlDate );
			
			JulianDayToCalendarDate( jDay, out year, out month, out day, out hour,
				out minute, out second );
		}
		
		/// 
		/// Calculate a Calendar date (year, month, day, hour, minute, second) corresponding to
		/// the Astronomical Julian Day number
		/// 
		/// 
		/// The Astronomical Julian Day number to be converted
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The integer second value (e.g., 42 for 42 seconds past the minute).
		/// 
		public static void JulianDayToCalendarDate( double jDay, out int year, out int month,
			out int day, out int hour, out int minute, out int second )
		{
			double ms = 0;
			JulianDayToCalendarDate( jDay, out year, out month,
					out day, out hour, out minute, out second, out ms );
		}
		/// 
		/// Calculate a Calendar date (year, month, day, hour, minute, second) corresponding to
		/// the Astronomical Julian Day number
		/// 
		/// 
		/// The Astronomical Julian Day number to be converted
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The double second value (e.g., 42.3 for 42.3 seconds past the minute).
		/// 
		public static void JulianDayToCalendarDate( double jDay, out int year, out int month,
			out int day, out int hour, out int minute, out double second )
		{
			int sec;
			double ms;
			JulianDayToCalendarDate( jDay, out year, out month,
					out day, out hour, out minute, out sec, out ms );
			second = sec + ms / MillisecondsPerSecond;
		}
		/// 
		/// Calculate a Calendar date (year, month, day, hour, minute, second) corresponding to
		/// the Astronomical Julian Day number
		/// 
		/// 
		/// The Astronomical Julian Day number to be converted
		/// 
		/// 
		/// The integer year value (e.g., 1994).
		/// 
		/// 
		/// The integer month value (e.g., 7 for July).
		/// 
		/// 
		/// The integer day value (e.g., 19 for the 19th day of the month).
		/// 
		/// 
		/// The integer hour value (e.g., 14 for 2:00 pm).
		/// 
		/// 
		/// The integer minute value (e.g., 35 for 35 minutes past the hour).
		/// 
		/// 
		/// The integer second value (e.g., 42 for 42 seconds past the minute).
		/// 
		/// 
		/// The  millisecond value (e.g., 342.5 for 342.5 milliseconds past
		/// the second).
		/// 
		public static void JulianDayToCalendarDate( double jDay, out int year, out int month,
			out int day, out int hour, out int minute, out int second, out double millisecond )
		{
			// add 5 ten-thousandths of a second to the day fraction to avoid roundoff errors
			jDay += 0.0005 / SecondsPerDay;
			double z = Math.Floor( jDay + 0.5);
			double f = jDay + 0.5 - z;
		
			double alpha = Math.Floor( ( z - 1867216.25 ) / 36524.25 );
			double A = z + 1.0 + alpha - Math.Floor( alpha / 4 );
			double B = A + 1524.0;
			double C = Math.Floor( ( B - 122.1 ) / 365.25 );
			double D = Math.Floor( 365.25 * C );
			double E = Math.Floor( ( B - D ) / 30.6001 );
		
			day = (int) Math.Floor( B - D - Math.Floor( 30.6001 * E ) + f );
			month = (int) ( ( E < 14.0 ) ? E - 1.0 : E - 13.0 );
			year = (int) ( ( month > 2 ) ? C - 4716 : C - 4715 );
		
			double fday =  ( jDay - 0.5 ) - Math.Floor( jDay - 0.5 );
		
			fday = ( fday - (long) fday ) * HoursPerDay;
			hour = (int) fday;
			fday = ( fday - (long) fday ) * MinutesPerHour;
			minute = (int) fday;
			fday = ( fday - (long) fday ) * SecondsPerMinute;
			second = (int) fday;
			fday = ( fday - (long) fday ) * MillisecondsPerSecond;
			millisecond = fday;
		}
		
		/// 
		/// Calculate an Astronomical Julian Day number corresponding to the specified XL date
		/// 
		/// 
		/// The XL date value in floating point double format.
		/// 
		/// The corresponding Astronomical Julian Day number, expressed in double
		/// floating point format
		public static double XLDateToJulianDay( double xlDate )
		{
			return xlDate + XLDay1;
		}
		
		/// 
		/// Calculate an XL Date corresponding to the specified Astronomical Julian Day number
		/// 
		/// 
		/// The Astronomical Julian Day number in floating point double format.
		/// 
		/// The corresponding XL Date, expressed in double
		/// floating point format
		public static double JulianDayToXLDate( double jDay )
		{
			return jDay - XLDay1;
		}
		
		/// 
		/// Calculate a decimal year value (e.g., 1994.6523) corresponding to the specified XL date
		/// 
		/// 
		/// The XL date value in floating point double format.
		/// 
		/// The corresponding decimal year value, expressed in double
		/// floating point format
		public static double XLDateToDecimalYear( double xlDate )
		{
			int year, month, day, hour, minute, second;
			
			XLDateToCalendarDate( xlDate, out year, out month, out day, out hour, out minute, out second );
			
			double jDay1 = CalendarDateToJulianDay( year, 1, 1, 0, 0, 0 );
			double jDay2 = CalendarDateToJulianDay( year + 1, 1, 1, 0, 0, 0 );
			double jDayMid = CalendarDateToJulianDay( year, month, day, hour, minute, second );
			
			
			return (double) year + ( jDayMid - jDay1 ) / ( jDay2 - jDay1 );
		}
		
		/// 
		/// Calculate a decimal year value (e.g., 1994.6523) corresponding to the specified XL date
		/// 
		/// 
		/// The decimal year value in floating point double format.
		/// 
		/// The corresponding XL Date, expressed in double
		/// floating point format
		public static double DecimalYearToXLDate( double yearDec )
		{
			int year = (int) yearDec;
			
			double jDay1 = CalendarDateToJulianDay( year, 1, 1, 0, 0, 0 );
			double jDay2 = CalendarDateToJulianDay( year + 1, 1, 1, 0, 0, 0 );
			
			return JulianDayToXLDate( ( yearDec - (double) year ) * ( jDay2 - jDay1 ) + jDay1 );
		}
		
		/// 
		/// Calculate a day-of-year value (e.g., 241.543 corresponds to the 241st day of the year)
		/// corresponding to the specified XL date
		/// 
		/// 
		/// The XL date value in floating point double format.
		/// 
		/// The corresponding day-of-year (DoY) value, expressed in double
		/// floating point format
		public static double XLDateToDayOfYear( double xlDate )
		{
			int year, month, day, hour, minute, second;
			XLDateToCalendarDate( xlDate, out year, out month, out day,
									out hour, out minute, out second );
			return XLDateToJulianDay( xlDate ) - CalendarDateToJulianDay( year, 1, 1, 0, 0, 0 ) + 1.0;
		}
		
		/// 
		/// Calculate a day-of-week value (e.g., Sun=0, Mon=1, Tue=2, etc.)
		/// corresponding to the specified XL date
		/// 
		/// 
		/// The XL date value in floating point double format.
		/// 
		/// The corresponding day-of-week (DoW) value, expressed in integer format
		public static int XLDateToDayOfWeek( double xlDate )
		{
			return (int) ( XLDateToJulianDay( xlDate ) + 1.5 ) % 7;
		}
		
		/// 
		/// Convert an XL date format to a .Net DateTime struct
		/// 
		/// 
		/// The XL date value in floating point double format.
		/// 
		/// The corresponding XL Date, expressed in double
		/// floating point format
		/// The corresponding date in the form of a .Net DateTime struct
		public static DateTime XLDateToDateTime( double xlDate )
		{
			int year, month, day, hour, minute, second;
			XLDateToCalendarDate( xlDate, out year, out month, out day,
									out hour, out minute, out second );
			return new DateTime( year, month, day, hour, minute, second );
		}
		
		/// 
		/// Convert a .Net DateTime struct to an XL Format date
		/// 
		/// 
		/// The date value in the form of a .Net DateTime struct
		/// 
		/// The corresponding XL Date, expressed in double
		/// floating point format
		public static double DateTimeToXLDate( DateTime dt )
		{
			return CalendarDateToXLDate( dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second );
		}
	#endregion
	
	#region Date Math Methods
		// =========================================================================
		// Math Routines
		// =========================================================================
		/// 
		/// Add the specified number of milliseconds (can be fractional) to the current XDate instance.
		/// 
		/// 
		/// The incremental number of milliseconds (negative or positive) in floating point double format.
		/// 
		public void AddMilliseconds( double dMilliseconds )
		{
			_xlDate += dMilliseconds / MillisecondsPerDay;
		}
		/// 
		/// Add the specified number of seconds (can be fractional) to the current XDate instance.
		/// 
		/// 
		/// The incremental number of seconds (negative or positive) in floating point double format.
		/// 
		public void AddSeconds( double dSeconds )
		{
			_xlDate += dSeconds / SecondsPerDay;
		}
		/// 
		/// Add the specified number of minutes (can be fractional) to the current XDate instance.
		/// 
		/// 
		/// The incremental number of minutes (negative or positive) in floating point double format.
		/// 
		public void AddMinutes( double dMinutes )
		{
			_xlDate += dMinutes / MinutesPerDay;
		}
		
		/// 
		/// Add the specified number of hours (can be fractional) to the current XDate instance.
		/// 
		/// 
		/// The incremental number of hours (negative or positive) in floating point double format.
		/// 
		public void AddHours( double dHours )
		{
			_xlDate += dHours / HoursPerDay;
		}
		
		/// 
		/// Add the specified number of days (can be fractional) to the current XDate instance.
		/// 
		/// 
		/// The incremental number of days (negative or positive) in floating point double format.
		/// 
		public void AddDays( double dDays )
		{
			_xlDate += dDays;
		}
		
		/// 
		/// Add the specified number of Months (can be fractional) to the current XDate instance.
		/// 
		/// 
		/// The incremental number of months (negative or positive) in floating point double format.
		/// 
		public void AddMonths( double dMonths )
		{
			int iMon = (int) dMonths;
			double monFrac = Math.Abs( dMonths - (double) iMon );
			int sMon = Math.Sign( dMonths );
			
			int year, month, day, hour, minute, second;
			
			XLDateToCalendarDate( _xlDate, out year, out month, out day, out hour, out minute, out second );
			if ( iMon != 0 )
			{
				month += iMon;
				_xlDate = CalendarDateToXLDate( year, month, day, hour, minute, second );
			}
			
			if ( sMon != 0 )
			{
				double xlDate2 = CalendarDateToXLDate( year, month+sMon, day, hour, minute, second );
				_xlDate += (xlDate2 - _xlDate) * monFrac;
			}
		}
		
		/// 
		/// Add the specified number of years (can be fractional) to the current XDate instance.
		/// 
		/// 
		/// The incremental number of years (negative or positive) in floating point double format.
		/// 
		public void AddYears( double dYears )
		{
			int iYear = (int) dYears;
			double yearFrac = Math.Abs( dYears - (double) iYear );
			int sYear = Math.Sign( dYears );
			
			int year, month, day, hour, minute, second;
			
			XLDateToCalendarDate( _xlDate, out year, out month, out day, out hour, out minute, out second );
			if ( iYear != 0 )
			{
				year += iYear;
				_xlDate = CalendarDateToXLDate( year, month, day, hour, minute, second );
			}
			
			if ( sYear != 0 )
			{
				double xlDate2 = CalendarDateToXLDate( year+sYear, month, day, hour, minute, second );
				_xlDate += (xlDate2 - _xlDate) * yearFrac;
			}
		}
	#endregion
	
	#region Operator Overload Methods
		// =========================================================================
		// Operator Overloads
		// =========================================================================
	
		/// 
		/// '-' operator overload.  When two XDates are subtracted, the number of days between dates
		/// is returned.
		/// 
		/// The left-hand-side of the '-' operator (an XDate class)
		/// The right-hand-side of the '-' operator (an XDate class)
		/// The days between dates, expressed as a floating point double
		public static double operator -( XDate lhs, XDate rhs )
		{
			return lhs.XLDate - rhs.XLDate;
		}
		
		/// 
		/// '-' operator overload.  When a double value is subtracted from an XDate, the result is a
		/// new XDate with the number of days subtracted.
		/// 
		/// The left-hand-side of the '-' operator (an XDate class)
		/// The right-hand-side of the '-' operator (a double value)
		/// An XDate with the rhs number of days subtracted
		public static XDate operator -( XDate lhs, double rhs )
		{
			lhs._xlDate -= rhs;
			return lhs;
		}
		
		/// 
		/// '+' operator overload.  When a double value is added to an XDate, the result is a
		/// new XDate with the number of days added.
		/// 
		/// The left-hand-side of the '-' operator (an XDate class)
		/// The right-hand-side of the '+' operator (a double value)
		/// An XDate with the rhs number of days added
		public static XDate operator +( XDate lhs, double rhs )
		{
			lhs._xlDate += rhs;
			return lhs;
		}
		
		/// 
		/// '++' operator overload.  Increment the date by one day.
		/// 
		/// The XDate struct on which to operate
		/// An XDate one day later than the specified date
		public static XDate operator ++( XDate xDate )
		{
			xDate._xlDate += 1.0;
			return xDate;
		}
		
		/// 
		/// '--' operator overload.  Decrement the date by one day.
		/// 
		/// The XDate struct on which to operate
		/// An XDate one day prior to the specified date
		public static XDate operator --( XDate xDate )
		{
			xDate._xlDate -= 1.0;
			return xDate;
		}
		
		/// 
		/// Implicit conversion from XDate to double (an XL Date).
		/// 
		/// The XDate struct on which to operate
		/// A double floating point value representing the XL Date
		public static implicit operator double( XDate xDate )
		{
			return xDate._xlDate;
		}
		
		/// 
		/// Implicit conversion from XDate to float (an XL Date).
		/// 
		/// The XDate struct on which to operate
		/// A double floating point value representing the XL Date
		public static implicit operator float( XDate xDate )
		{
			return (float) xDate._xlDate;
		}
		
		/// 
		/// Implicit conversion from double (an XL Date) to XDate.
		/// 
		/// The XDate struct on which to operate
		/// An XDate struct representing the specified xlDate value.
		public static implicit operator XDate( double xlDate )
		{
			return new XDate( xlDate );
		}
		
		/// 
		/// Implicit conversion from XDate to .
		/// 
		/// The XDate struct on which to operate
		/// A  struct representing the specified xDate value.
		public static implicit operator DateTime( XDate xDate )
		{
			
			return XLDateToDateTime( xDate );
		}
		
		/// 
		/// Implicit conversion from  to .
		/// 
		/// The  struct on which to operate
		/// An  struct representing the specified DateTime value.
		public static implicit operator XDate( DateTime dt )
		{
			
			return new XDate( DateTimeToXLDate( dt ) );
		}
	#endregion
		
	#region General Overrides
		// =========================================================================
		// System Stuff
		// =========================================================================
		/// 
		/// Tests whether obj is either an  structure or
		/// a double floating point value that is equal to the same date as this XDate
		/// struct instance.
		/// 
		/// The object to compare for equality with this XDate instance.
		/// This object should be either a type XDate or type double.
		/// Returns true if obj is the same date as this
		/// instance; otherwise, false
		public override bool Equals( object obj )
		{
			if ( obj is XDate )
			{
				return ((XDate) obj)._xlDate == _xlDate;
			}
			else if ( obj is double )
			{
				return ((double) obj) == _xlDate;
			}
			else
				return false;
		}
		
		/// 
		/// Returns the hash code for this  structure.  In this case, the
		/// hash code is simply the equivalent hash code for the floating point double date value.
		/// 
		/// An integer representing the hash code for this XDate value
		public override int GetHashCode()
		{
			return _xlDate.GetHashCode();
		}
	#endregion
	
	#region String Format Conversion Methods
		// =========================================================================
		// String Formatting Routines
		// =========================================================================
	
		/// 
		/// Format this XDate value using the default format string ().
		/// 
		/// 
		/// The formatting is done using the  
		/// method in order to provide full localization capability.  The DateTime struct is limited to
		/// dates from 1 AD onward.  However, all calendar dates in  and 
		/// are projected Gregorian calendar dates.  Since the Gregorian calendar was not implemented
		/// until October 4, 1582 (or later in some countries), Gregorian dates prior to that time are
		/// really dates that would have been, had the Gregorian calendar existed.  In order to avoid
		/// throwing an exception, for dates prior to 1 AD, the year will be converted to a positive
		/// year and the text "(BC)" is appended to the end of the formatted string.  Under this mode, the
		/// year sequence is 2BC, 1BC, 1AD, 2AD, etc.  There is no year zero.
		/// 
		/// 
		/// The XL date value to be formatted in floating point double format.
		/// 
		/// A string representation of the date
		public string ToString( double xlDate )
		{
			return ToString( xlDate, DefaultFormatStr );
		}
		
		/// 
		/// Format this XDate value using the default format string (see cref="DefaultFormatStr"/>).
		/// 
		/// 
		/// The formatting is done using the 
		/// 
		/// method in order to provide full localization capability.  The DateTime struct is limited to
		/// dates from 1 AD onward.  However, all calendar dates in  and
		/// 
		/// are projected Gregorian calendar dates.  Since the Gregorian calendar was not implemented
		/// until October 4, 1582 (or later in some countries), Gregorian dates prior to that time are
		/// really dates that would have been, had the Gregorian calendar existed.  In order to avoid
		/// throwing an exception, for dates prior to 1 AD, the year will be converted to a positive
		/// year and the text "(BC)" is appended to the end of the formatted string.  Under this mode, the
		/// year sequence is 2BC, 1BC, 1AD, 2AD, etc.  There is no year zero.
		/// 
		/// A string representation of the date
		public override string ToString()
		{
			return ToString( _xlDate, DefaultFormatStr );
		}
		
		/// 
		/// Format this XL Date value using the specified format string.  The format
		/// string is specified according to the  class.
		/// 
		/// 
		/// The formatting is done using the 
		/// 
		/// method in order to provide full localization capability.  The DateTime struct is limited to
		/// dates from 1 AD onward.  However, all calendar dates in  and
		/// 
		/// are projected Gregorian calendar dates.  Since the Gregorian calendar was not implemented
		/// until October 4, 1582 (or later in some countries), Gregorian dates prior to that time are
		/// really dates that would have been, had the Gregorian calendar existed.  In order to avoid
		/// throwing an exception, for dates prior to 1 AD, the year will be converted to a positive
		/// year and the text "(BC)" is appended to the end of the formatted string.  Under this mode, the
		/// year sequence is 2BC, 1BC, 1AD, 2AD, etc.  There is no year zero.
		/// 
		/// 
		/// The formatting string to be used for the date.  See
		/// 
		/// class for a list of the format types available.
		/// A string representation of the date
		public string ToString( string fmtStr )
		{
			return ToString( this.XLDate, fmtStr );
		}
		/// 
		/// Format the specified XL Date value using the specified format string.  The format
		/// string is specified according to the  class.
		/// 
		/// 
		/// The formatting is done using the 
		/// 
		/// method in order to provide full localization capability.  The DateTime struct is limited to
		/// dates from 1 AD onward.  However, all calendar dates in  and
		/// 
		/// are projected Gregorian calendar dates.  Since the Gregorian calendar was not implemented
		/// until October 4, 1582 (or later in some countries), Gregorian dates prior to that time are
		/// really dates that would have been, had the Gregorian calendar existed.  In order to avoid
		/// throwing an exception, for dates prior to 1 AD, the year will be converted to a positive
		/// year and the text "(BC)" is appended to the end of the formatted string.  Under this mode, the
		/// year sequence is 2BC, 1BC, 1AD, 2AD, etc.  There is no year zero.
		/// 
		/// 
		/// The XL date value to be formatted in floating point double format.
		/// 
		/// 
		/// The formatting string to be used for the date.  See
		/// 
		/// for a list of the format types available.
		/// A string representation of the date
		public static string ToString( double xlDate, string fmtStr )
		{
			int		year, month, day, hour, minute, second, millisecond;
			if ( !CheckValidDate( xlDate ) )
				return "Date Error";
			XLDateToCalendarDate( xlDate, out year, out month, out day, out hour, out minute,
											out second, out millisecond );
			if ( year <= 0 )
			{
				year = 1 - year;
				fmtStr = fmtStr + " (BC)";
			}
			if ( fmtStr.IndexOf("[d]") >= 0 )
			{
				fmtStr = fmtStr.Replace( "[d]", ((int) xlDate).ToString() );
				xlDate -= (int) xlDate;
			}
			if ( fmtStr.IndexOf("[h]") >= 0 || fmtStr.IndexOf("[hh]") >= 0 )
			{
				fmtStr = fmtStr.Replace( "[h]", ((int) (xlDate * 24)).ToString("d") );
				fmtStr = fmtStr.Replace( "[hh]", ((int) (xlDate * 24)).ToString("d2") );
				xlDate = ( xlDate * 24 - (int) (xlDate * 24) ) / 24.0;
			}
			if ( fmtStr.IndexOf("[m]") >= 0 || fmtStr.IndexOf("[mm]") >= 0 )
			{
				fmtStr = fmtStr.Replace( "[m]", ((int) (xlDate * 1440)).ToString("d") );
				fmtStr = fmtStr.Replace( "[mm]", ((int) (xlDate * 1440)).ToString("d2") );
				xlDate = ( xlDate * 1440 - (int) (xlDate * 1440) ) / 1440.0;
			}
			if ( fmtStr.IndexOf("[s]") >= 0 || fmtStr.IndexOf("[ss]") >= 0 )
			{
				fmtStr = fmtStr.Replace( "[s]", ((int) (xlDate * 86400)).ToString("d") );
				fmtStr = fmtStr.Replace( "[ss]", ((int) (xlDate * 86400)).ToString("d2") );
				xlDate = ( xlDate * 86400 - (int) (xlDate * 86400) ) / 86400.0;
			}
			if ( fmtStr.IndexOf("[f]") >= 0 )
				fmtStr = fmtStr.Replace( "[f]", ((int) (xlDate * 864000)).ToString("d") );
			if ( fmtStr.IndexOf("[ff]") >= 0 )
				fmtStr = fmtStr.Replace( "[ff]", ((int) (xlDate * 8640000)).ToString("d") );
			if ( fmtStr.IndexOf("[fff]") >= 0 )
				fmtStr = fmtStr.Replace( "[fff]", ((int) (xlDate * 86400000)).ToString("d") );
			if ( fmtStr.IndexOf("[ffff]") >= 0 )
				fmtStr = fmtStr.Replace( "[ffff]", ((int) (xlDate * 864000000)).ToString("d") );
			if ( fmtStr.IndexOf("[fffff]") >= 0 )
				fmtStr = fmtStr.Replace( "[fffff]", ((int) (xlDate * 8640000000)).ToString("d") );
			//DateTime dt = XLDateToDateTime( xlDate );
			if ( year > 9999 )
				year = 9999;
			DateTime dt = new DateTime( year, month, day, hour, minute, second, millisecond );
			return dt.ToString( fmtStr );
		}
/*
		/// 
		/// Format this XDate value using the specified format string
		/// 
		/// 
		/// The formatting string to be used for the date.  The following formatting elements
		/// will be replaced with the corresponding date values:
		/// 
		///    
		///       Variable
		///       Description
		///    
		///    - &mmmmmonth name (e.g., January)///
- &mmmmonth abbreviation (e.g., Apr)///
- &mmpadded month number (e.g. 04)///
- &mnon-padded month number (e.g., 4)///
- &ddpadded day number (e.g., 09)///
- &dnon-padded day number (e.g., 9)///
- &yyyy4 digit year number (e.g., 1995)///
- &yytwo digit year number (e.g., 95)///
- &hhpadded 24 hour time value (e.g., 08)///
- &hnon-padded 12 hour time value (e.g., 8)///
- &nnpadded minute value (e.g, 05)///
- &nnon-padded minute value (e.g., 5)///
- &sspadded second value (e.g., 03)///
- &snon-padded second value (e.g., 3)///
- &a"am" or "pm"///
- &wwwwday of week (e.g., Wednesday)///
- &wwwday of week abbreviation (e.g., Wed)///
/// 
		/// 
		///   "&wwww, &mmmm &dd, &yyyy &h:&nn &a" ==> "Sunday, February 12, 1956 4:23 pm"
		///   "&dd-&mmm-&yy" ==> 12-Feb-56
		/// 
		/// A string representation of the date
		public string ToString( string fmtStr )
		{
			return ToString( this.xlDate, fmtStr );
		}
		/// 
		/// Format the specified XL Date value using the specified format string
		/// 
		/// 
		/// The XL date value to be formatted in floating point double format.
		/// 
		/// 
		/// The formatting string to be used for the date.  The following formatting elements
		/// will be replaced with the corresponding date values:
		///
		///    
		///       Variable
		///       Description
		///    
		///    - &mmmmmonth name (e.g., January)///
- &mmmmonth abbreviation (e.g., Apr)///
- &mmpadded month number (e.g. 04)///
- &mnon-padded month number (e.g., 4)///
- &ddpadded day number (e.g., 09)///
- &dnon-padded day number (e.g., 9)///
- &yyyy4 digit year number (e.g., 1995)///
- &yytwo digit year number (e.g., 95)///
- &hhpadded 24 hour time value (e.g., 08)///
- &hnon-padded 12 hour time value (e.g., 8)///
- &nnpadded minute value (e.g, 05)///
- &nnon-padded minute value (e.g., 5)///
- &sspadded second value (e.g., 03)///
- &snon-padded second value (e.g., 3)///
- &a"am" or "pm"///
- &wwwwday of week (e.g., Wednesday)///
- &wwwday of week abbreviation (e.g., Wed)///
/// 
		/// 
		///   "&wwww, &mmmm &dd, &yyyy &h:&nn &a" ==> "Sunday, February 12, 1956 4:23 pm"
		///   "&dd-&mmm-&yy" ==> 12-Feb-56
		/// 
		/// A string representation of the date
		public static string ToString( double xlDate, string fmtStr )
		{
			string[] longMonth = { "January", "February", "March", "April", "May", "June",
						"July", "August", "September", "October", "November", "December" };
			string[] shortMonth = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
						"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
			string[] longDoW = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
								"Friday", "Saturday" };
			string[] shortDoW = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
						
			int year, month, day, hour, minute, second;
			XLDateToCalendarDate( xlDate, out year, out month, out day, out hour, out minute, out second );
			
			string resultStr = fmtStr.Replace( "&mmmm", longMonth[ month - 1 ] );
			resultStr = resultStr.Replace( "&mmm", shortMonth[ month - 1 ] );
			resultStr = resultStr.Replace( "&mm", month.ToString( "d2" ) );
			resultStr = resultStr.Replace( "&m", month.ToString( "d" ) );
			resultStr = resultStr.Replace( "&yyyy", year.ToString( "d" ) );
			resultStr = resultStr.Replace( "&yy", (year%100).ToString( "d2" ) );
			resultStr = resultStr.Replace( "&dd", day.ToString( "d2" ) );
			resultStr = resultStr.Replace( "&d", day.ToString( "d" ) );
			resultStr = resultStr.Replace( "&hh", hour.ToString( "d2" ) );
			resultStr = resultStr.Replace( "&h", (((hour+11)%12)+1).ToString( "d" ) );
			resultStr = resultStr.Replace( "&nn", minute.ToString( "d2" ) );
			resultStr = resultStr.Replace( "&n", minute.ToString( "d" ) );
			resultStr = resultStr.Replace( "&ss", second.ToString( "d2" ) );
			resultStr = resultStr.Replace( "&s", second.ToString( "d" ) );
			resultStr = resultStr.Replace( "&a", (hour>=12) ? "pm" : "am" );
			resultStr = resultStr.Replace( "&wwww", longDoW[ XLDateToDayOfWeek( xlDate ) ] );
			resultStr = resultStr.Replace( "&www", shortDoW[ XLDateToDayOfWeek( xlDate ) ] );
			
			
			return resultStr;
		}
*/		
	#endregion
	}
}