@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.
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.
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: