/* * Converts a datetimestruct in UTC to a datetimestruct in local time, * also returning the timezone offset applied. * * Returns 0 on success, -1 on failure. */ static int convert_datetimestruct_utc_to_local(pandas_datetimestruct *out_dts_local, const pandas_datetimestruct *dts_utc, int *out_timezone_offset) { NPY_TIME_T rawtime = 0, localrawtime; struct tm tm_; npy_int64 year_correction = 0; /* Make a copy of the input 'dts' to modify */ *out_dts_local = *dts_utc; /* HACK: Use a year < 2038 for later years for small time_t */ if (sizeof(NPY_TIME_T) == 4 && out_dts_local->year >= 2038) { if (is_leapyear(out_dts_local->year)) { /* 2036 is a leap year */ year_correction = out_dts_local->year - 2036; out_dts_local->year -= year_correction; } else { /* 2037 is not a leap year */ year_correction = out_dts_local->year - 2037; out_dts_local->year -= year_correction; } } /* * Convert everything in 'dts' to a time_t, to minutes precision. * This is POSIX time, which skips leap-seconds, but because * we drop the seconds value from the pandas_datetimestruct, everything * is ok for this operation. */ rawtime = (time_t)get_datetimestruct_days(out_dts_local) * 24 * 60 * 60; rawtime += dts_utc->hour * 60 * 60; rawtime += dts_utc->min * 60; /* localtime converts a 'time_t' into a local 'struct tm' */ if (get_localtime(&rawtime, &tm_) < 0) { return -1; } /* Copy back all the values except seconds */ out_dts_local->min = tm_.tm_min; out_dts_local->hour = tm_.tm_hour; out_dts_local->day = tm_.tm_mday; out_dts_local->month = tm_.tm_mon + 1; out_dts_local->year = tm_.tm_year + 1900; /* Extract the timezone offset that was applied */ rawtime /= 60; localrawtime = (time_t)get_datetimestruct_days(out_dts_local) * 24 * 60; localrawtime += out_dts_local->hour * 60; localrawtime += out_dts_local->min; *out_timezone_offset = localrawtime - rawtime; /* Reapply the year 2038 year correction HACK */ out_dts_local->year += year_correction; return 0; }
/* * Converts a datetime from a datetimestruct to a datetime based * on some metadata. The date is assumed to be valid. * * TODO: If meta->num is really big, there could be overflow * * Returns 0 on success, -1 on failure. */ int convert_datetimestruct_to_datetime(pandas_datetime_metadata *meta, const pandas_datetimestruct *dts, npy_datetime *out) { npy_datetime ret; PANDAS_DATETIMEUNIT base = meta->base; if (base == PANDAS_FR_Y) { /* Truncate to the year */ ret = dts->year - 1970; } else if (base == PANDAS_FR_M) { /* Truncate to the month */ ret = 12 * (dts->year - 1970) + (dts->month - 1); } else { /* Otherwise calculate the number of days to start */ npy_int64 days = get_datetimestruct_days(dts); switch (base) { case PANDAS_FR_W: /* Truncate to weeks */ if (days >= 0) { ret = days / 7; } else { ret = (days - 6) / 7; } break; case PANDAS_FR_D: ret = days; break; case PANDAS_FR_h: ret = days * 24 + dts->hour; break; case PANDAS_FR_m: ret = (days * 24 + dts->hour) * 60 + dts->min; break; case PANDAS_FR_s: ret = ((days * 24 + dts->hour) * 60 + dts->min) * 60 + dts->sec; break; case PANDAS_FR_ms: ret = (((days * 24 + dts->hour) * 60 + dts->min) * 60 + dts->sec) * 1000 + dts->us / 1000; break; case PANDAS_FR_us: ret = (((days * 24 + dts->hour) * 60 + dts->min) * 60 + dts->sec) * 1000000 + dts->us; break; case PANDAS_FR_ns: ret = ((((days * 24 + dts->hour) * 60 + dts->min) * 60 + dts->sec) * 1000000 + dts->us) * 1000 + dts->ps / 1000; break; case PANDAS_FR_ps: ret = ((((days * 24 + dts->hour) * 60 + dts->min) * 60 + dts->sec) * 1000000 + dts->us) * 1000000 + dts->ps; break; case PANDAS_FR_fs: /* only 2.6 hours */ ret = (((((days * 24 + dts->hour) * 60 + dts->min) * 60 + dts->sec) * 1000000 + dts->us) * 1000000 + dts->ps) * 1000 + dts->as / 1000; break; case PANDAS_FR_as: /* only 9.2 secs */ ret = (((((days * 24 + dts->hour) * 60 + dts->min) * 60 + dts->sec) * 1000000 + dts->us) * 1000000 + dts->ps) * 1000000 + dts->as; break; default: /* Something got corrupted */ PyErr_SetString( PyExc_ValueError, "NumPy datetime metadata with corrupt unit value"); return -1; } } /* Divide by the multiplier */ if (meta->num > 1) { if (ret >= 0) { ret /= meta->num; } else { ret = (ret - meta->num + 1) / meta->num; } } *out = ret; return 0; }