Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 887
  • Last Modified:

COleDateTime

hi

  i have a peculiar problem while sorting date using COleDateTime in quick sort.

i have 2 dates

CString strL,strR;
strL = "01/06/2000 00:43PM"
strR = "09/05/2000 10:47AM"
COleDateTime dtL,dtR;

dtL.ParseDateTime(strL);
dtR.ParseDateTime(strR);

when i find the

COleDateTimeSpan spanElapsed = dtL - dtR;

spanElapsed is supposed to be a positive value i.e., > 0

but i get it as a negative value . what could be the problem ? how do i solve it ?

bcos of this problem the sorting is erroneous .

urgent pls help.

thnx in advance
cira.

0
cira
Asked:
cira
  • 6
  • 4
  • 3
  • +1
1 Solution
 
Roshan DavisCommented:
I think your local time setting is in dd/mm/yyyy format
0
 
ciraAuthor Commented:
yes, it is in dd/mm/yyyy format

then will that give a problem ?

what should i do ?
0
 
Roshan DavisCommented:
So you have to format the date in dd/mm/yyyy
becoz ParseDateTime uses LANG_USER_DEFAULT as default parameter.
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
ciraAuthor Commented:
the string what i gave is also in  dd/mm/yyyy format

why should i convert ,

I am not able to understand pls elaborate

thnx
cira
0
 
ciraAuthor Commented:
the string what i gave is also in  dd/mm/yyyy format

why should i convert ,

I am not able to understand pls elaborate

thnx
cira
0
 
Roshan DavisCommented:
strL = "01/06/2000 00:43PM"  <------mm/dd/yyyy

I think thatz Y u are getting negative value.
0
 
ciraAuthor Commented:
how will i compare or format for each instance ?

or is it possible to change the default parameter of parsedatetime ?
0
 
Roshan DavisCommented:
use the format: Year/Month/Day

eg:
csDateStr = "1982/08/22";


Good Luck
0
 
inoxCommented:

specify the correct LCID in the ParseDateTime( here am. english) to get it work well:

      dtL.ParseDateTime(strL,0x0409);
      dtR.ParseDateTime(strR,0x0409);
0
 
DanRollinsCommented:
hold the presses!!

You are getting a negative timespan because the first date (dtL) is older (longer ago) than the second date (dtR)!

It is working perfectly.

For instance,

1998 - 1997  (first date is newer than second date)
                   result is positive
1997 - 1998  (first date is OLDER than second date)
                   result is negative

You just need to realize this and then rewrite your comparison function accordingly!  SHow your comparison function and describe what you want the sorted list to look like.  I can help there.

-- Dan
0
 
ciraAuthor Commented:
Thanx for the reply.

The code is as follows :

int CProbeListCtrl::CmpItems(CString cstL, CString cstR, int nCol)
{
   switch (nCol) {
      //Date time column(s)
      //***********************
      case 12:
    case 13:
    case 14:
      {
         COleDateTime odtL;
         COleDateTime odtR;        
            
             odtL.ParseDateTime(cstL);
             if (odtL.m_status == COleDateTime::invalid)
             {
                   cstL = "01/01/0100 00:00AM";
                   odtL.ParseDateTime(cstL);                   
             }

         odtR.ParseDateTime(cstR);
             if (odtR.m_status == COleDateTime::invalid)
             {
                   cstR = "01/01/0100 00:00AM";
                   odtR.ParseDateTime(cstR);
             }

         COleDateTimeSpan spanElapsed = odtL - odtR;

//             int totmin = (int)spanElapsed.GetTotalSeconds();
         return((int)spanElapsed.GetTotalSeconds());
    }

      //Numbers column(s)
      //***********************
   case 0:
   case 8:
   case 9:
         return(atoi(cstL) - atoi(cstR));

      // Strings column(s)
      //***********************
      default:
         return (cstL.Compare(cstR));
   }
}
 
BOOL CProbeListCtrl::SortTextItems( int nCol, BOOL bAscending,      int low /*= 0*/, int high /*= -1*/ )
{

      if( nCol >= ((CHeaderCtrl*)GetDlgItem(0))->GetItemCount() )
            return FALSE;

      if( high == -1 ) high = GetItemCount() - 1;

      int lo = low;
      int hi = high;
      CString midItem;

      if( hi <= lo ) return FALSE;
      
      midItem = GetItemText( (lo+hi)/2, nCol );

      // loop through the list until indices cross
      while( lo <= hi )
      {
            // rowText will hold all column text for one row
            CStringArray rowText;

            // find the first element that is greater than or equal to
            // the partition element starting from the left Index.
            if( bAscending )
            {
                  while( ( lo < high ) && ( CmpItems( GetItemText(lo, nCol) , midItem, nCol) < 0 ) )
                        ++lo;                  
            }
            else
            {            
                  while( ( lo < high ) && ( CmpItems( GetItemText(lo, nCol) , midItem, nCol) > 0 ) )
                        ++lo;                  
            }

            // find an element that is smaller than or equal to
            // the partition element starting from the right Index.
            if( bAscending )
            {
                  while( ( hi > low ) && ( CmpItems(GetItemText(hi, nCol) , midItem, nCol ) > 0 ) )
                        --hi;            
            }
            else
            {
                  while( ( hi > low ) && ( CmpItems(GetItemText(hi, nCol) , midItem, nCol ) < 0 ) )
                        --hi;            
            }
            // if the indexes have not crossed, swap
            // and if the items are not equal
            if( lo <= hi )
            {
                  // swap only if the items are not equal
            
                  if( CmpItems (GetItemText(lo, nCol) , GetItemText(hi, nCol), nCol  ) != 0)
                  {
                        // swap the rows
                        LV_ITEM lvitemlo, lvitemhi;
                        int nColCount =
                              ((CHeaderCtrl*)GetDlgItem(0))->GetItemCount();
                        rowText.SetSize( nColCount );
                        int i;
                        for( i=0; i<nColCount; i++)
                              rowText[i] = GetItemText(lo, i);
                        lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
                        lvitemlo.iItem = lo;
                        lvitemlo.iSubItem = 0;
                        lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED |
                                    LVIS_FOCUSED |  LVIS_SELECTED |
                                    LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;

                        lvitemhi = lvitemlo;
                        lvitemhi.iItem = hi;

                        GetItem( &lvitemlo );
                        GetItem( &lvitemhi );

                        for( i=0; i<nColCount; i++)
                              SetItemText(lo, i, GetItemText(hi, i));

                        lvitemhi.iItem = lo;
                        SetItem( &lvitemhi );

                        for( i=0; i<nColCount; i++)
                              SetItemText(hi, i, rowText[i]);

                        lvitemlo.iItem = hi;
                        SetItem( &lvitemlo );
                  }
                        
                  ++lo;
                  --hi;
            }
      }

      // If the right index has not reached the left side of array
      // must now sort the left partition.
      if( low < hi )
            SortTextItems( nCol, bAscending , low, hi);

      // If the left index has not reached the right side of array
      // must now sort the right partition.
      if( lo < high )
            SortTextItems( nCol, bAscending , lo, high );

      return TRUE;
}
0
 
inoxCommented:

ParseDateTime uses
LCID lcid = LANG_USER_DEFAULT
If not specified. If this doesn't match it will not work.
If DateTime-format in the string is inmutable the corresponding LCID should be supplied
0
 
DanRollinsCommented:
I can't analyze your sorting routine because of it's complexity.  I don't have a dataset to test it and I don't know what your goal is (it it clearly not a simple sort).  Furthermore, it calls itself recursively which opens a whole can of worms.  It's hard to imagine that you need such a complicated function.  If you describe your goal, as I requested, it would help.

That said...
I verified that Your comparison routine works correctly:

void CompareAndShowResult( CString cstL, CString cstR )
{
      int nRet= CmpItems( cstL, cstR, 12 );

      CString sCmp= "EQUAL TO";
      if (nRet < 0 ) sCmp= "LESS THAN (longer ago than)";
      if (nRet > 0 ) sCmp= "GREATER THAN (more recent than)";

      CString sMsg; sMsg.Format("date %s is %s %s",
            (LPCSTR)cstL,
            (LPCSTR)sCmp,
            (LPCSTR)cstR
      );
      AfxMessageBox( sMsg );
}

void CD18Dlg::OnButton1()
{
      CString sL, sR;

      sL="01/01/2000"; sR="01/01/2000"; CompareAndShowResult(sL,sR);
      sL="01/01/2000"; sR="02/01/2000"; CompareAndShowResult(sL,sR);
      sL="02/01/2000"; sR="01/01/2000"; CompareAndShowResult(sL,sR);
      sL="01/01/2000"; sR="01/02/2000"; CompareAndShowResult(sL,sR);
      sL="01/02/2000"; sR="01/01/2000"; CompareAndShowResult(sL,sR);

      sL="01/01/2000"; sR="01/01/2001"; CompareAndShowResult(sL,sR);
      sL="01/01/2001"; sR="01/01/2000"; CompareAndShowResult(sL,sR);

}
0
 
ciraAuthor Commented:
thanx for the effort taken.

Actually my application has a list control with different columns each with string,number and date items. I have to sort the columns in ascending & descending on header click.

it works fine for string & number items but for date it gives a small problem as this .

Consider this data set for date :

26/08/2003 03:26PM
15/11/2000 11:20AM
21/08/1995 03:46PM
09/05/2000 10:47AM
01/06/2000 00:43PM
NULL
NULL

onAscending the output i get is :

21/08/1995 03:46PM
01/06/2000 00:43PM
09/05/2000 10:47AM
15/11/2000 11:20AM
26/08/2003 03:26PM
NULL
NULL

onDescending the output i get is :

NULL
NULL
26/08/2003 03:26PM
15/11/2000 11:20AM
09/05/2000 10:47AM
01/06/2000 00:43PM
21/08/1995 03:46PM

0
 
DanRollinsCommented:

OK, it is now clear that your dates are in dd/mm/yyyy format.  That means you need to use the LCID parmeter in the ParseDate function:

      WORD nParsingLCID= MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_UK ); // format is dd/mm/yyyy
      odtL.ParseDateTime(sItem1, 0, nParsingLCID);

=-=-=-=-=-=-=-=-=-=-=-=-=-=
As to the sorting, you should use the SortItems() member function of the CListCtrl object.  It is just a little bit tricky, but once you understand how it works, it's pretty straightforward (even though the documentation is confusing).

You create a callback fn that gets called repeatedly during the sorting.  Each call passes in the 'ItemData' of two list items.   The *best* way to use this is to set the ItemData to be a pointer to some in-memory representation of your list data.  However, in the following code, I just set it to be a unique number -- the *original* index of the items in the list.

Then in the comparison callback, I can use CListCtrl::FindItem() to locate that item (recall that its position [index] in the list is likely to change after each sort) and that lets me look up the text for any column using CListCtrl::GetItemText().

The other trick is to pass in a structure full of info to the callback.  That way, you can know which column to sort and which direction.

Here is the complete test harness:

typedef struct {
     CListCtrl* m_pListCtl;
     int        m_nClmNum;
     BOOL       m_fAscending;
} MYSORTINFO;


static int CALLBACK
MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
      MYSORTINFO* pInfo= (MYSORTINFO*)lParamSort;
      int nClmNum= pInfo->m_nClmNum;
      BOOL fSortLoToHi = pInfo->m_fAscending;

      // we know the value of the item data from the lParam, but we need the index
        //  and FindItem can return that... assuming the ItemData is unique for each item
      LVFINDINFO rFI;
      rFI.flags=  LVFI_PARAM;
      rFI.lParam= lParam1; int nListIdx1= pInfo->m_pListCtl->FindItem( &rFI );
      rFI.lParam= lParam2; int nListIdx2= pInfo->m_pListCtl->FindItem( &rFI );

      // format is dd/mm/yyyy
      WORD nParsingLCID= MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_UK );

      CString sItem1= pInfo->m_pListCtl->GetItemText(nListIdx1, nClmNum);
      CString sItem2= pInfo->m_pListCtl->GetItemText(nListIdx2, nClmNum);

      switch ( nClmNum ) {
            case 1:                // comparing dates
            { COleDateTime odt1, odt2;        
                  odt1.ParseDateTime(sItem1, 0, nParsingLCID);
                  if (odt1.m_status == COleDateTime::invalid) {
                        odt1.ParseDateTime( "01/01/0100 00:00AM", 0, nParsingLCID);
                  }
                  odt2.ParseDateTime(sItem2, 0, nParsingLCID);
                  if (odt2.m_status == COleDateTime::invalid) {
                        odt2.ParseDateTime( "01/01/0100 00:00AM", 0, nParsingLCID);
                  }
                  // int nMonth1= odt1.GetMonth(); // eyeball check for debugging
                  if ( fSortLoToHi ) {
                        if (odt1 < odt2 ) return( -1 ); // the lower one goes on top
                        if (odt1 > odt2 ) return( 1 );
                        return( 0 ); // equal
                  }
                  else {  // sorting HighToLow
                        if (odt1 < odt2 ) return( 1 );
                        if (odt1 > odt2 ) return( -1 );
                        return( 0 );
                  }
            }
            case 0: // other columns that need sorting are string
            default:
                  if ( fSortLoToHi )       return strcmp( sItem1, sItem2);
                  else                     return -strcmp( sItem1, sItem2);
      }
      return 0; // should never get here
}

void CD18Dlg::OnButton1()
{
      MYSORTINFO rSI;
      rSI.m_fAscending= FALSE;
      rSI.m_nClmNum= 0;
      rSI.m_pListCtl= &m_ctlList;

      m_ctlList.SortItems( MyCompareProc, (LPARAM)&rSI );
}
//----------------------------- fill the list with some data for testing
void CD18Dlg::OnButton2()
{
      m_ctlList.InsertColumn( 0, "clm 1", LVCFMT_LEFT, 50 );
      m_ctlList.InsertColumn( 1, "clm 2", LVCFMT_LEFT, 130 );
      m_ctlList.InsertColumn( 1, "clm 3", LVCFMT_LEFT, 130 );

      m_ctlList.InsertItem(0,"aaa", 0 );
      m_ctlList.InsertItem(1,"bbb", 0 );
      m_ctlList.InsertItem(2,"ccc", 0 );
      m_ctlList.InsertItem(3,"ddd", 0 );
      m_ctlList.InsertItem(4,"zzz", 0 );
      m_ctlList.InsertItem(5,"fff", 0 );
      m_ctlList.InsertItem(6,"ggg", 0 );

      m_ctlList.SetItemText( 0, 1,"26/08/2003 03:26PM" );
      m_ctlList.SetItemText( 1, 1,"15/11/2000 11:20AM" );
      m_ctlList.SetItemText( 2, 1,"09/05/2000 10:47AM" );
      m_ctlList.SetItemText( 3, 1,"01/06/2000 00:43PM" );
      m_ctlList.SetItemText( 4, 1,"21/08/1995 03:46PM" );
      m_ctlList.SetItemText( 5, 1,"" );
      m_ctlList.SetItemText( 6, 1,"" );

      // need to SetItemData to a unique number, used in sorting
      for (int j=0; j<7; j++ ) {
            m_ctlList.SetItemData( j, j );
      }
}

=-=-=-=-=-=-=-=-=-=-=-
By using the built-in sorting capability of the CListCtrl, you can remove your SortTextItems() function altogether.  That simplifies your program and avoids a lot of possible errors.

That should fix you up!

-- Dan
0

Featured Post

New feature and membership benefit!

New feature! Upgrade and increase expert visibility of your issues with Priority Questions.

  • 6
  • 4
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now