Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Simple(x) Date & Time Math Parser

0.00/5 (No votes)
22 Apr 2004 1  
Date and time class from the SimplexParser freeware.

Introduction

In fact, it is not difficult to find a C/C++ date & time class for our main purposes. One of the best is surely P J Naughter's DTime. To bring the functionality for a Date & Time Mathematical Parser, we need additional methods to this or a special class for those purposes. SimplexParser has such a class, so I am decided to set it up to the CodeProject site.

Sample Operations

The parser interprets editor's code like:

Result = Startdatetime + 40 hours + 12 min + 1 year

in the form:

Result = C<[21.04.2004 | 16:19:18] + h[40] + m[12] + Y[1]
Result = 23.04.2005 08:31:18

or as span:

Result = 366.925 days or +366d 22h 12m 0s

or as:

Julian Date: Result = 2453483.855069

and so on...

whereby C< stands for Start Clock, D< for Start Date and T< for Start Time. Or:

Result = Startdate - Enddate
Result = C<[21.04.2004 | 16:19:18] - C>[20.03.2003 | 06:19:15]
Result = +398d 10h 0m 3s

whereby C> stands for End Clock, D> for End Date and T> for End Time. The syntax was introduced in the early days of development and simplifies the parser's error input check. The output is in the normal form like +366d 22h 12m 0s (day, hour, minute and sec.) or 21.04.2004 16:19:18 or 04/21/2004.

Julian Day Algorithm

The parser's date & time class is based on the Julian Day system. The Julian Day is the number of days since noon on January 1, -4712, i.e., January 1, 4713 BC. It was proposed by J. J. Scaliger in 1583, so the name for this system derived from Julius Scaliger (not Julius Caesar). Scaliger defined Day One as a day when three calendrical cycles converged. The first cycle was the 28 year period over which the Julian calendar repeats days of the week (the so-called solar number). After 28 years, all the dates fall on the same days of the week, so one need only buy 28 calendars. (Note that since the Gregorian calendar was adopted, the calendar now takes 400 years to repeat.) The second was the 19 year golden number cycle over which phases of the moon almost land on the same dates of the year. The third cycle was the 15 year ancient Roman tax cycle of Emperor Constantine (the so-called indiction). Scaliger picked January 1, 4713 BC on the Julian calendar as Day One. The three cycles coincide every 7980 years. For more information, please see: this or this.

CJulianDay class

The following code shows the main methods from the CJulianDay class. Some of the method names are well known from other codes:

//...


class CJulianDay 
{
public:
  CJulianDay();
  virtual ~CJulianDay();

// Member Functions

public:
  // Gives Julian Date back

  bool Enter(CString& strBaseDate, CString& 
       strBaseTime, CString strInput, double& dJulian);
  double CalcJulianDayTime(CString& strBaseDate, 
       CString& strBaseTime, CString strInput, bool bSignPlus = true);
  double GetJulianDayTime(CString strBaseDate, CString strBaseTime);

  CString WeekNumber(int Jul);
  CString DayNumber(int Jul);
  CString WeekDay(int Jul);

  //...


  bool IsLeapYear(int nYear);
  int DaysInMonth(int nMonth, BOOL bLeapYear);

  double HmsToDec(CString strTime);
  CString DecToHms(double dDec, bool bF);

protected:
  double DatToJul(CString strDate);
  CString JulToDat(double Jul);

  bool ValidDate(int nYear, int nMonth, int nDay);
  bool IsValidDate(CString strDate, int& nDay, 
                   int& nMonth, int& nYear);

  double EvaluateNumberOfDays(CString strInput);
  int EvaluateNumberOfYears(CString strDate, CString strInput);
  int EvaluateNumberOfMonth(CString strDate, CString strInput);
  int EvaluateNumberOfWeeks(CString strInput);
  void AddYear(CString& strDate, int nAddYear);
  void AddMonth(CString& strDate, int nAddMonths);
};

//...

Using the code

You can use this code as shown next:

//...


case IDM_VERNALEQUINOX:
{
  double m = ((double) date.GetYear() - 2000.0) / 1000.0;
  double ve = 2451623.80984 + 365242.37404 * m + 
              0.05169 * m * m - 0.00411 * m * m * m - 
              0.00057 * m * m * m * m ;

  CJulianDay Julian;
  CString strDate, strTime;
  Julian.Enter(strDate, strTime, _T(""), ve);
  strResult = strDate + _T(" ") + strTime;

break;
}

//...

or

//...


CJulianDay Julian;
result.dJulianDay = Julian.CalcJulianDayTime(m_strBaseDate, 
                         m_strBaseTime, result.Command, true);

//...

I hope that the code is reasonably obvious how to use, so that we can go to the actual parser class CDateParser.

CDateParser class

//...


typedef struct _tagResultStruct
{
  CLTimeSpan tmSpan;
  LONG value;
  CString SubString;
  CString Command;
  double dJulianDay;
} stDateParser;


class CDateParser 
{
protected:
  //Implementation

  CString m_strFormula;
  CString m_strFunction;
  CString m_strErrortext;
  double m_dFunctionConstant[ANZFUNKTKONST];
  CStringArray m_strStandardFunction;

  stDateParser Expression(int& nPosition, CString& strCharacter);
  stDateParser Factor(int& nPosition, CString& strCharacter);
  double Char_n(int& nPosition, CString& strCharacter);
  CString GetNextToken(CString& strSrc, const CString strDelim);

private:
  CJulianDay m_Julian;
  CString m_strBaseDate;
  CString m_strBaseTime;
  CString m_strAssociateDate;
  CString m_strAssociateTime;

public:
  int StripFormula(CString& strFormula);
  CString GetFormula();
  void SetFormula(CString Formula);
  void SetFunctConst(int index, double val);

  CDateParser();
  virtual ~CDateParser();

//Interface

  stDateParser Calculation(CString strFormula, 
     int& ErrorPosition, CString& Errortext, 
     BOOL strip = true);
};

//...

Use this class in the following manner:

//...


CDateParser DateParser;
stDateParser retValue = DateParser.Calculation(m_strFormulainput, 
                                    nErrorPosition, strErrortext);

try
{
  if (nErrorPosition == 0)
  {
    if (strErrortext.IsEmpty())
    {
      if (m_nSpanSet == 1) // Span

      {
        int days = retValue.tmSpan.GetTotalDays();
        int hours = retValue.tmSpan.GetHours();
        int minutes = retValue.tmSpan.GetMinutes();
        int seconds = retValue.tmSpan.GetSeconds();

        //...


//...

whereby you can use the other public member functions for clean input, and for example, P J Naughter's DTime class CLTimeSpan for getting back days, hours, etc. The demo project shows you that.

Certainly, I know that we can make for the demo project a better dialog for all the possibilities. But, maybe later...

History

  • 1.0 (18 April 2004) -Initial release.

Acknowledgement

This would not have been possible without all the authors making their code freely available! So, thanks for that, SimplexParser will be available as freeware for all the time.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here