Calculate Actual date

Hi Experts,

I want to calculate date from day of the year and year.

In oracle to_date function does this . Would appreciate if you can let me know how to achieve this through c++

int ddd value is day of the year e.g. 300
int year value is the year e.g. 1900

The returned date is 1/300/1900

which is incorrect it should be 10/27/1900.

I would also like to validate if the return value is a valid date or not .

Please help.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  string caldate(int year, int ddd)
{
    string dt;
    int daynum = ddd;
    int yeary = year;
    struct tm t = { 0 };
    t.tm_sec = 0;
    t.tm_min = 0;
    t.tm_hour = 0;
    t.tm_mday = daynum;
   // t.tm_yday = daynum;
    t.tm_isdst = -1;
    t.tm_mon = 0;
    t.tm_year = yeary-1900;
  time_t when = mktime(&t);
    const struct tm *norm = localtime(&when);   // Normalized time
 dt = printf("%02d/%02d/%04d\n", t.tm_mon+1, t.tm_mday, 1900 + t.tm_year);
 return dt;
Line 10: You're setting tm_mday to 300. That's not a valid value. tm_mday must be from 1 to 28-31.

Line 15: You should be checking that the conversion was successful. mktime() will return -1 if the conversion can't be done.

Line 16: the call to localtime() is undefined if the call to mktime() was not valid.

If you want to use mktime(), you going to have to convert ddd to a month numer and day number yourself.

edit:
Line 17: printf returns a length value, not a std::string.
Last edited on
You're setting tm_mday to 300. That's not a valid value
If you want to use mktime(), you going to have to convert ddd to a month numer and day number yourself.
Actually it is perfectly valid to set this value outside of range and then call mktime to normalize data. For example April 31 will become May 1st.

It is just dates before 1970 are not reliably representable in all implementations.
http://stackoverflow.com/a/14127055

Do not try to create dates before the creation of the world beginning of UNIX era. Or use Boost.Date_Time
@miiNiPaa - Thank you. I didn't know that. I checked the description of mktime on this site before posting, but it made no reference to normalizing day of year. Only that tm_yday was not used on input. Since mktime did make provision for indicating an invalid conversion, I assumed it was range checking the values in tm.
http://www.cplusplus.com/reference/ctime/mktime/
The values of the members tm_wday and tm_yday of timeptr are ignored, and the values of the other members are interpreted even if out of their valid ranges (see struct tm). For example, tm_mday may contain values above 31, which are interpreted accordingly as the days that follow the last day of the selected month.

A call to this function automatically adjusts the values of the members of timeptr if they are off-range or -in the case of tm_wday and tm_yday- if they have values that do not match the date described by the other members.
Last edited on
You could use sprintf() to put the final string into a buffer and then just return that buffer, letting the compiler convert it to a string. Since the length of the returned string has a maximum size, this is safe.

You have to worry about two nasty things: timezones and leap seconds. You're converting back to a date with localtime, which means it will put the time in the local timezone. Depending on whether it's ahead or behind GMT, you'll get different values.

Even if you used GMT, it might not work since you're setting the time to midnight. If time time in a year is off by one second, your code will think it's 23:59:59 on the day before the one you want. This is a real concern: there really are leap seconds added/subtracted to time occasionally.

Fortunately it's pretty easy to solve these problems. Convert back to a tm struct using gmtime instead of localtime, and set the original time to midday instead of midnight. By using midday, a few seconds added or subtracted will still put you in the same day:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
std::string caldate(int year, int ddd)
{
    char buf[50];
    std::string dt;

    struct tm t = { 0 };
    t.tm_hour = 12;  // mid day
    t.tm_mday = ddd;
    t.tm_year = year-1900;
    t.tm_isdst = -1;
    time_t when = mktime(&t);
    const struct tm *norm = gmtime(&when);   // Normalized time
    sprintf(buf, "%02d/%02d/%04d\n", t.tm_mon+1, t.tm_mday, 1900 + t.tm_year);
    return buf;
}

Topic archived. No new replies allowed.