If your timestamps is within the date range 1901 to 2099 you can take advantage of the fact that every fourth year is leap-year (this can be further extended to include dates within 1900 since it's not a leap year).
I derived this code from a date c library I'm working on with the difference in this code I'm using the "shifted-month" approach as in Zeller's congruence.
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
void
dt_to_ymd(unsigned int n, int *yp, int *mp, int *dp) {
unsigned int z, c;
int y, m, d;
assert(n <= 73107); /* 2100-02-28 */
z = n + 307; /* 1 + 306 (306 days between March 1 and December 31) */
y = (4 * z) / 1461;
c = z - (1461 * y - 1) / 4; /* day of the year [1, 366] */
m = (5 * c + 456) / 153; /* month of the year [1, 12] */
d = c - (153 * m - 457) / 5; /* day of the month [1, 31] */
if (m > 12)
y++, m -= 12;
if (yp) *yp = y + 1899;
if (mp) *mp = m;
if (dp) *dp = d;
}
const struct test {
int year;
int month;
int day;
uint64_t timestamp;
} tests[] = {
{ 1900, 1, 1, 0 },
{ 1970, 1, 1, 2208988800 },
{ 1972, 1, 1, 2272060800 },
{ 1999, 12, 31, 3155587200 },
{ 2013, 7, 4, 3581884800 },
{ 2100, 2, 28, 6316444800 },
};
int
main() {
int i, ntests;
ntests = sizeof(tests) / sizeof(*tests);
for (i = 0; i < ntests; i++) {
const struct test t = tests[i];
{
unsigned int n;
int y, m, d;
n = t.timestamp / 86400;
dt_to_ymd(n, &y, &m, &d);
if (t.year != y || t.month != m || t.day != d) {
printf("dt_to_ymd(%u)\n", n);
printf(" got: %.4d-%.2d-%.2d\n", y, m, d);
printf(" exp: %.4d-%.2d-%.2d\n", t.year, t.month, t.day);
}
}
}
return 0;
}