Link to home
Start Free TrialLog in
Avatar of mrwad99
mrwad99Flag for United Kingdom of Great Britain and Northern Ireland

asked on

CTime: how does this work ?

Hello !

I am playing with CTime, and am having a lot of fun !  However, I cannot see why this works.

Excuse the lack of experience please :)

CReminderDlg dlg;

if (dlg.DoModal() == IDOK) {

CTime current = CTime::GetCurrentTime();

CTime date = dlg.m_date;
CTime time = dlg.m_time;

if (current >= date) {
      if (current >= time) {
            AfxMessageBox("DUE !");
      }
}

//.......
Right, basically this code displays a dialogue box that has two member variables, m_date and m_time that, via DDX, obtain the date and time a user selects from two date/time picker controls, one of which is configured to hold dates the other times.  I want a messagebox to be displayed if the current time/date is greater than the required time/date.  This works.

So, how does, in the line

if (current >= date)

MFC know to compare the *date* element of "current" with "date" ?  I have not told it to !  Or is it doing something weird like assuming the current time is 00:00:00 ?  

The same goes for the line

if (current >= time) {

- what would be in the "date" part of "time" ?  Jan 1 1970 or something ?

And overall, is this the best way to check my reminders ?  Or am I doing something wrong ?

Thanks in advance !
Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

You will find that there is a 'casting' operator as a member of the class.  This 'sees' what the type of variable is and performs a conversion automatically.

Put a breakpoint on the line and step into the code to see how it is coded.
Ah, I've just reread your question and realised they are all the same type of variable.
Put a breakpoint at one of the comparisons and look at the contents of the variables.  The integral part is the date, the fractional part is the time.
Avatar of mrwad99

ASKER

Right; will play with the debugger shortly.  

In the meantime, is what I am doing a failsafe way of comparing user specified time and date values with the current time/date ?

Thanks, getting late now GMT; be back tomorrow.
Avatar of mrwad99

ASKER

Hmm; having quickly done that breakpointing, could you clarify "integral" and "fractional" part ?  

The values I get, when running to the line

if (current >= date) {

are for m_time 1080331192 and for m_date 1080331193.

?
Erm - I think I have made a stupid comment and mixed it up with COleDateTime as to how it stores things internally..
For comparison you might be safer to extract the individual components GetYear, GetMonth, GetDay etc.

An alternative is to use COleDateTime.  The date is the integral part, the time the fractional part of how it is stored internally.

COleDateTime current = CTime::GetCurrentTime();

COleDateTime date = dlg.m_date;
COleDateTime time = dlg.m_time;


(long)date.m_dt;   //this will give you the date part for comparison
and for comparison of times you can always convert the integral part to a zero
time.m_dt - (double)(long)time.m_dt
Avatar of wayside
wayside

The CTime class stores the time as a long integer (a time_t actually), which contains the elapsed sections from 1/1/1970 or whatever the zero date is.

It also has numerous functions and operators to convert "seconds from 1/1/1970 at midnight" into more meaningful dates, and the operators let you directly compare times, so yes using ">=" will always be OK to check for if one time is later than another.

If you need dates before 1970 you should use the COleDateTime class.
Avatar of mrwad99

ASKER

Right, a couple of more things to say about this...

1) When I run the code through the debugger (MSVC++) to immediately after the line

CTime current = CTime::GetCurrentTime();

the variable 'current' is listed, obviously; the value of which is {time = 1080400845}.  It also has a little + next to it, like char* strings and structures do.  Clicking this cross reveals something called 'm_time' which has the value 1080400845.  What is this ?  I looked at the MSDN docs and there is no member of CTime called m_time listed !

2) wayside:

>> so yes using ">=" will always be OK to check for if one time is later than another.

Thanks for that, but it still does not explain how in my comparison in the original question knows how to compare the time part of the current date with the required time, and the date part of the current time with the required time.  Could you elaborate ?

Also, AndyAinscow do you agree with what has been said regarding the safety of using >= ?  I did actually consider comparing all of the fractional parts like you say with GetDay(), GetYear()...but wanted a 'quick and easy' (hehe) way and figured that their must be one, so by chance tried my code in the original question.  Clearly I was amazed that it worked hence was sceptical as to its validity so asked this question...

TIA !
ASKER CERTIFIED SOLUTION
Avatar of wayside
wayside

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mrwad99

ASKER

OK.  This is my current (relevant) code:

CReminderDlg is a dialog that contains two date-time picker controls.  The one set to display times has id IDC_TIMEPICKERand the one set to display dates has id IDC_DATEPICKER.

I link these to CTime member variables via DDX:

void CReminderDlg::DoDataExchange(CDataExchange* pDX)
{
      CDialog::DoDataExchange(pDX);
      //{{AFX_DATA_MAP(CReminderDlg)
      DDX_DateTimeCtrl(pDX, IDC_DATEPICKER, m_date);
      DDX_DateTimeCtrl(pDX, IDC_TIMEPICKER, m_time);
      //}}AFX_DATA_MAP
}

m_date and m_time are public, hence from my calling code I can obtain them directly:

CReminderDlg dlg;
      
if (dlg.DoModal() == IDOK) {

      CTime current = CTime::GetCurrentTime();
            
      CTime date = dlg.m_date;
      CTime time = dlg.m_time;

Now I know that the comparison code I posted previously is flawed; it does not return correct results.  So, I took up on what you said; constructing a new CTime object of my own:

CTime current = CTime::GetCurrentTime();


CTime comparison(date.GetYear(), date.GetMonth(), date.GetDay(),
            time.GetHour(), time.GetMinute(), time.GetSecond());

if (current >= comparison)
      AfxMessageBox("Due.");

And this is apparently now working as required.  However, it would be interesting to discover before I close this question how

date.GetYear() and time.GetYear() both return exactly the same values.  Is it because inside a date time picker silently obtains the time *and* date from the user, where if the control is configured to display dates it just takes the *current* time ?  This is apparently what is happening from tests I have run.  It would be nice to have this documented though.

If you can see anything wrong with what I am doing wayside please let me know otherwise I will close this question after you comment on the previous paragraph; if you can.

TIA !
Try the following
3 vars, one with 1.1.2000 17:00, one with 1.1.2000, 09:00 and the third with 2.1.2000 12:00.
the first two - same day, different times.  I bet a simple comparison says the second is less than the first (even thought same day) and I bet the third is later than the first even though the time is earlier.
You are safer with checking the individual components.
Avatar of mrwad99

ASKER

Yeah that is correct.  In fact that is exactly the behaviour I want.

1.1.2000 17:00 *is later* than 1.1.2000, 09:00.  This is what I would need my app to pick up on.  

So if the alert was due to be fired 1.1.2000, 09:00 and the current time was 1.1.2000 17:00, the messagebox would be displayed. Correct !  If things were the other way around, then since it is not yet 17.00, only 9.00, the alert would not be fired.  Correct again.

It has no matter to me whether they are on the same day or not, it is the overall time difference that I am interested in.

* Or am I missing something very crucial here ? *

I am not sure if this relates to the first part of my last comment talking about the construction of a CTime via the individual elements, or the latter part in the values obtained from date-time picker controls being the same regardless of if it was displaying a time or date.  Can you clarify ?
> date.GetYear() and time.GetYear() both return exactly the same
> values.  Is it because inside a date time picker silently obtains the time
> *and* date from the user, where if the control is configured to display
> dates it just takes the *current* time ?  This is apparently what is
> happening from tests I have run.  It would be nice to have this
 >documented though.

When the control is set to "time", only the time portion will change; when it is set to "date", only the date portion changes.

So for example, if you had a date and time of "3/28/2004 1:35:11 PM" (which translates to a CTime::m_time value of 1080498911) and you set both your m_time and m_date variables to this value, when you change the date in m_date the hour, minutes and seconds will not change, and when you change the time in m_time, the day, month, and year will not change. That's why you need to combine the fields from both to get the correct date and time.

So if I change the date to "3/27/2004" the value will be 86400 less than it was initially (the number of seconds in one day); in fact the value will always change in a multiple of 86400, because the smallest change you can make is one day. If I change the time to "1:36:11", the value will increase by 60, the number of seconds in one minute; for m_time, the value will never change by more than 86400 because you can't change the day.

> If you can see anything wrong with what I am doing

Your code looks fine.


Avatar of mrwad99

ASKER

Thanks a lot for the help here all.  It is much appreciated :)