Solved

COleDateTime

Posted on 2003-10-30
18
787 Views
Last Modified: 2013-11-20
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
Comment
Question by:cira
  • 6
  • 4
  • 3
  • +1
18 Comments
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 9655770
I think your local time setting is in dd/mm/yyyy format
0
 

Author Comment

by:cira
ID: 9655860
yes, it is in dd/mm/yyyy format

then will that give a problem ?

what should i do ?
0
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 9655896
So you have to format the date in dd/mm/yyyy
becoz ParseDateTime uses LANG_USER_DEFAULT as default parameter.
0
 

Author Comment

by:cira
ID: 9656190
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
 

Author Comment

by:cira
ID: 9656191
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
 
LVL 23

Expert Comment

by:Roshan Davis
ID: 9656302
strL = "01/06/2000 00:43PM"  <------mm/dd/yyyy

I think thatz Y u are getting negative value.
0
 

Author Comment

by:cira
ID: 9656925
how will i compare or format for each instance ?

or is it possible to change the default parameter of parsedatetime ?
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 23

Expert Comment

by:Roshan Davis
ID: 9657088
use the format: Year/Month/Day

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


Good Luck
0
 
LVL 4

Expert Comment

by:inox
ID: 9657745

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

      dtL.ParseDateTime(strL,0x0409);
      dtR.ParseDateTime(strR,0x0409);
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 9664461
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
 

Author Comment

by:cira
ID: 9668912
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
 
LVL 4

Expert Comment

by:inox
ID: 9670436

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
 
LVL 49

Expert Comment

by:DanRollins
ID: 9674516
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
 

Author Comment

by:cira
ID: 9676309
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
 
LVL 49

Accepted Solution

by:
DanRollins earned 100 total points
ID: 9677173

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

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
How to calculate times for developing software? 8 60
Question regarding Copy/Paste 16 86
Unix / Linux grid computing 5 127
Folder Comparison 12 52
Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
If you use Adobe Reader X it is possible you can't open OLE PDF documents in the standard. The reason is the 'save box mode' in adobe reader X. Many people think the protected Mode of adobe reader x is only to stop the write access. But this fe…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now