2

I know, this particular kind of thing has been answered a number of times, but I think, my question here is more to do with general C++ stuff than ctime() or date/time conversion. I just happened to try it out with this. So, here is the code:

#include <iostream>
#include <ctime>

using std::cout;
using std::endl;
using std::string;

void strTime( int iM, int iD, int iY )
{
    time_t rwTime;
    time( &rwTime );            // current epoch time

    // 1st set:: using tmInfo_11
    struct tm *tmInfo_11; 
    tmInfo_11 = localtime( &rwTime );
    tmInfo_11->tm_mon = iM - 1;
    tmInfo_11->tm_mday = iD; 
    tmInfo_11->tm_year = iY - 1900;
    mktime( tmInfo_11 );
    cout << "tmInfo_11 RESULt: " << tmInfo_11->tm_wday << endl;

    // 2nd set:: using tmInfo_22 //
    struct tm tmInfo_22; 
    tmInfo_22 = *localtime( &rwTime );
    tmInfo_22.tm_mon = iM - 1;
    tmInfo_22.tm_mday = iD; 
    tmInfo_22.tm_year = iY - 1900;
    mktime( &tmInfo_22 );
    cout << "tmInfo_22 RESULt: " << tmInfo_22.tm_wday << endl;
}

int main()
{
    int iMM=12, iDD=9, iYY=2009;
    strTime( iMM, iDD, iYY );
}

and my question is: What's the difference between these 2 sets of code? Either way, I can achieve the same thing. The notable difference is the first 2-lines from the each set and I have to admit that I didn't understand all of it. So, can anyone kindly explain it to me please? Also, dose one have any advantage(s)/disadvantage(s) over other? Cheers!!


Just for the sake of completeness, this the code I ended up with, which gives me the desired result. So, basically it's for the future reference:
#include <iostream>
#include <fstream>
#include <ctime>

using std::cout;
using std::endl;
using std::string;

tm testTime( int iM, int iD, int iY );

int main()
{
    char tmBuff[20];
    int iMM=12, iDD=9, iYY=2009;

    tm myDate = testTime( iMM, iDD, iYY );
    strftime( tmBuff, sizeof(tmBuff), "%a, %b %d, %Y", &myDate );
    cout << "TESt PRINt TIMe: " << tmBuff << endl;
}

tm testTime( int iM, int iD, int iY ) 
{
    time_t rwTime; 

    struct tm tmTime;
    tmTime = *localtime( &rwTime );

    tmTime.tm_mon = iM - 1;
    tmTime.tm_mday = iD; 
    tmTime.tm_year = iY - 1900;
    mktime( &tmTime );
    return tmTime;
}

NOTE that it does require the *localtime( &rwTime ) to be specified (even though tmTime is getting overwritten afterwards) otherwise the Year(%Y) in the strftime() doesn't work. Thanks to all for helping. Cheers!!

MacUsers
  • 2,091
  • 3
  • 35
  • 56
  • The first chunk works on a struct that has been allocated by localtime. The second chunk works on a local struct that has been assigned the value of the struct allocated by localtime. But this seems so basic that I must have misunderstood your question. – HonkyTonk Apr 19 '12 at 14:02
  • @HonkyTonk: Thanks! I still trying to understand a few basics. Cheers!! – MacUsers Apr 19 '12 at 14:31

3 Answers3

3

The second variant copies the data of the tm structure to your own structure, while the first just uses the pointer to the (static) structure in localtime.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

It's the first two lines of both sections that are key. localtime() creates it's output in a static buffer and if you just take a pointer to what it produces - as in the first section - and then call it again, you may find it overwrites what your first pointer points to.

The second example is slightly better as you're effectively copying the whole object although in a multithreaded environment there's still a chance that this could end up with a corruption.

Much better to use localtime_r() which allows you to pass the buffer as a parameter so you don't get this issue.

Component 10
  • 10,247
  • 7
  • 47
  • 64
  • Do you mean like this: `tm tmBuff; struct tm tmInfo = *localtime_r( &rwTime, &tmBuff );`? – MacUsers Apr 19 '12 at 14:26
  • Yes - the returned pointer is the same as the second parameter. In your example, `tmBuff` and `tmInfo` will be equivalent, but not the same object. I generally don't bother with assigning the return unless utilising it directly. – Component 10 Apr 19 '12 at 16:08
1

Both versions are valid code, but I got several remarks on this:

In the first version you work on a data structure which you don't own. tmInfo_11 points to memory which is provided and managed by localtime(). This may lead to unwanted side effects when your code grows. So I'd consider it bad style.

The second version is good style, but runs probably slower, because the data structure will copied. But you have to run it really, really often to see a considerable difference.

In the second version I assume you can omit the call to localtime(), because you overwrite the result anyway, except for time entries which you obviously don't use. In the first version you cannot omit localtime(), because you need the pointer to its memory which you use.

You said you haven't understood the differences between the two versions. So I would recommend to revisit the lesson about pointers and when they are valid and when not in a good textbook, again.

bjhend
  • 1,538
  • 11
  • 25
  • Thanks for the explanation; just started C++ so a lot of things to catch up with. You were right, `localtime()` is not required for the 2nd variant; I didn't realized that. But, instead of using `void()`, how can I return `curTime`, so it can be used from some where else like this: `strftime( tmBuff,10,"%b, %I:%M%p", &tmInfo_22 );`? Cheers!! – MacUsers Apr 19 '12 at 18:49
  • @MacUsers You'd need to define a buffer (`char buffer[11]`) and pass it to `strftime`. After that you can convert the result: `std::string t(buffer)` which you can safely return. Don't forget to check the return value of `strftime`. And, be aware that `tmInfo_22` is on the stack, so it becomes invalid when the function returns. – bjhend Apr 19 '12 at 19:17
  • that's what I'm doing so far: `char tmBuff[10]; strftime( tmBuff,sizeof(tmBuff),"%b, %I:%M%p", &tmInfo_22 );` but it's all inside the `strTime()` function. Wondering how to do the same elsewhere i.e. outside of strTime() as well, for different `strftime()`specifiers as required. Cheers!! – MacUsers Apr 19 '12 at 19:26
  • @MacUsers You can also return the value of `tmInfo_22`. In that case it will be copied into the return value. It's only illegal to return a pointer to `tmInfo_22` as that becomes invalid. – bjhend Apr 19 '12 at 19:37
  • So, what's the best way of reprocessing `tmInfo_22` out side of that particular function. If I just simply return `tmInfo_22`, I get this error: `cannot convert ‘tm’ to ‘int’ in return`. Do you think you can show me a few lines of sample code, perhaps? Cheers!! – MacUsers Apr 19 '12 at 20:21
  • @MacUsers - You have to declare your `strTime` to return `tm` instead of `void` and the caller has to assign the result into a variable of type `tm` as well. – bjhend Apr 19 '12 at 22:33
  • Do you mean `time_t` e.g. `time_t strTime( int iM, int iD, int iY )` instead of `tm`? Either way I'm not able to achieve the desired result. I must have been doing something wrong. Cheers!! Cheers!! – MacUsers Apr 20 '12 at 00:03
  • @MacUsers - You know how to return an `int` from a function? Just replace `int` by `tm` and it should work. If not consider asking a new question about that. – bjhend Apr 20 '12 at 09:14
  • nope! it's not working that way; I already tried that. thanks anyway for your help. cheers!! – MacUsers Apr 20 '12 at 11:58