Solved

CTime: how does this work ?

Posted on 2004-03-26
14
4,146 Views
Last Modified: 2013-11-20
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 !
0
Comment
Question by:mrwad99
  • 6
  • 5
  • 3
14 Comments
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
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.
0
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
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.
0
 
LVL 19

Author Comment

by:mrwad99
Comment Utility
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.
0
 
LVL 19

Author Comment

by:mrwad99
Comment Utility
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.

?
0
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
Erm - I think I have made a stupid comment and mixed it up with COleDateTime as to how it stores things internally..
0
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
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
0
 
LVL 14

Expert Comment

by:wayside
Comment Utility
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.
0
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 
LVL 19

Author Comment

by:mrwad99
Comment Utility
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 !
0
 
LVL 14

Accepted Solution

by:
wayside earned 100 total points
Comment Utility
CTime is defined as

class CTime
{
private:
      time_t m_time;
public:

// Constructors
      static CTime PASCAL GetCurrentTime();

      CTime();
      CTime(time_t time);
      CTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec,
            int nDST = -1);
... about 20 more functions
};

The only data it contains is a long (m_time) that holds the time in seconds elapsed from 1/1/1970 at 00:00.  There is no "time part" and no "date part". That is what you see in the debugger when you click the '+'. You see the value of m_time without clicking the '+' because the m_time member is what is defined to be shown for CTime in your autoexp.dat file.

I don't know what your dialog variables "m_date" and "m_time" are, but I'm guessing your intent is to combine a date and time into one CTime. You can perhaps do this using a constructor like

CTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec,int nDST = -1);

For example

CTime current = CTime::GetCurrentTime();
CTime timeFromDlg(m_nYear, m_nMonth, m_nDay, m_nHour, m_nMinute, m_nSecond);

if (timeFromDlg >= current)
...

What you are doing using two comparisons probably isn't what you want, but it's hard to be sure without knowing more about your code and dialog.

Hope this helps...
0
 
LVL 19

Author Comment

by:mrwad99
Comment Utility
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 !
0
 
LVL 44

Expert Comment

by:AndyAinscow
Comment Utility
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.
0
 
LVL 19

Author Comment

by:mrwad99
Comment Utility
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 ?
0
 
LVL 14

Expert Comment

by:wayside
Comment Utility
> 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.


0
 
LVL 19

Author Comment

by:mrwad99
Comment Utility
Thanks a lot for the help here all.  It is much appreciated :)
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Here is how to use MFC's automatic Radio Button handling in your dialog boxes and forms.  Beginner programmers usually start with a OnClick handler for each radio button and that's just not the right way to go.  MFC has a very cool system for handli…
Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
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.
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

772 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

12 Experts available now in Live!

Get 1:1 Help Now