For those wondering how to do this in the future, here is the solution I ended up with.
Pass the datetime64 as an int64 from Python:
dt = np.datetime64(datetime.utcnow())
my_C_func(dt.astype(np.int64))
The decoding in C is derived from the source of gmtime(). This code assumes that the datetime is in microseconds which you can determine by checking the dtype (thanks @hpaulj). start
is the datetime64 coming from Python.
inline int
is_leapyear(uint64_t year)
{
return (year & 0x3) == 0 && /* year % 4 == 0 */
((year % 100) != 0 ||
(year % 400) == 0);
}
#define YEARSIZE(year) (is_leapyear(year) ? 366u : 365u)
...
uint64_t us_per_day = 1000ull * 1000ull * 60ull * 60ull * 24ull;
register uint64_t dayclock = start % us_per_day;
register uint64_t dayno = start / us_per_day;
uint64_t year = 1970ull;
uint64_t us = dayclock % 1000000ull;
uint64_t sec = (dayclock / 1000000ull) % 60ull;
uint64_t minute = (dayclock % 3600000000ull) / 60000000ull;
uint64_t hour = dayclock / 3600000000ull;
while (dayno >= YEARSIZE(year))
{
dayno -= YEARSIZE(year);
year++;
}
uint64_t day = dayno + 1;
If you don't need anything more accurate than seconds you could simply do this:
uint64_t other_start = start / 1000000ull;
struct tm* ptm;
ptm = gmtime((time_t*)&other_start);
printf("\tGMTIME VERSION:\n");
printf("\tyear: %d\n", ptm->tm_year);
printf("\tday: %d\n", ptm->tm_yday);
printf("\thours: %d\n", ptm->tm_hour);
printf("\tminutes: %d\n", ptm->tm_min);
printf("\tsec: %d\n", ptm->tm_sec);
Of course the us portion can then be obtained separately:
uint64_t us = source % 1000000ull;