From db51f7f103bbbd6c91c8f47d75b3482ef8939691 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 17 Dec 2023 15:32:20 +0100 Subject: Adding upstream version 3.0.0. Signed-off-by: Daniel Baumann --- pendulum/_extensions/_helpers.c | 931 ---------------------------------------- 1 file changed, 931 deletions(-) delete mode 100644 pendulum/_extensions/_helpers.c (limited to 'pendulum/_extensions/_helpers.c') diff --git a/pendulum/_extensions/_helpers.c b/pendulum/_extensions/_helpers.c deleted file mode 100644 index a3114d9..0000000 --- a/pendulum/_extensions/_helpers.c +++ /dev/null @@ -1,931 +0,0 @@ -/* ------------------------------------------------------------------------- */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* ------------------------------------------------------------------------- */ - -#define EPOCH_YEAR 1970 - -#define DAYS_PER_N_YEAR 365 -#define DAYS_PER_L_YEAR 366 - -#define USECS_PER_SEC 1000000 - -#define SECS_PER_MIN 60 -#define SECS_PER_HOUR (60 * SECS_PER_MIN) -#define SECS_PER_DAY (SECS_PER_HOUR * 24) - -// 400-year chunks always have 146097 days (20871 weeks). -#define DAYS_PER_400_YEARS 146097L -#define SECS_PER_400_YEARS ((int64_t)DAYS_PER_400_YEARS * (int64_t)SECS_PER_DAY) - -// The number of seconds in an aligned 100-year chunk, for those that -// do not begin with a leap year and those that do respectively. -const int64_t SECS_PER_100_YEARS[2] = { - (uint64_t)(76L * DAYS_PER_N_YEAR + 24L * DAYS_PER_L_YEAR) * SECS_PER_DAY, - (uint64_t)(75L * DAYS_PER_N_YEAR + 25L * DAYS_PER_L_YEAR) * SECS_PER_DAY}; - -// The number of seconds in an aligned 4-year chunk, for those that -// do not begin with a leap year and those that do respectively. -const int32_t SECS_PER_4_YEARS[2] = { - (4 * DAYS_PER_N_YEAR + 0 * DAYS_PER_L_YEAR) * SECS_PER_DAY, - (3 * DAYS_PER_N_YEAR + 1 * DAYS_PER_L_YEAR) * SECS_PER_DAY}; - -// The number of seconds in non-leap and leap years respectively. -const int32_t SECS_PER_YEAR[2] = { - DAYS_PER_N_YEAR * SECS_PER_DAY, - DAYS_PER_L_YEAR *SECS_PER_DAY}; - -#define MONTHS_PER_YEAR 12 - -// The month lengths in non-leap and leap years respectively. -const int32_t DAYS_PER_MONTHS[2][13] = { - {-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, - {-1, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; - -// The day offsets of the beginning of each (1-based) month in non-leap -// and leap years respectively. -// For example, in a leap year there are 335 days before December. -const int32_t MONTHS_OFFSETS[2][14] = { - {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, - {-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}}; - -const int DAY_OF_WEEK_TABLE[12] = { - 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; - -#define TM_SUNDAY 0 -#define TM_MONDAY 1 -#define TM_TUESDAY 2 -#define TM_WEDNESDAY 3 -#define TM_THURSDAY 4 -#define TM_FRIDAY 5 -#define TM_SATURDAY 6 - -#define TM_JANUARY 0 -#define TM_FEBRUARY 1 -#define TM_MARCH 2 -#define TM_APRIL 3 -#define TM_MAY 4 -#define TM_JUNE 5 -#define TM_JULY 6 -#define TM_AUGUST 7 -#define TM_SEPTEMBER 8 -#define TM_OCTOBER 9 -#define TM_NOVEMBER 10 -#define TM_DECEMBER 11 - -/* ------------------------------------------------------------------------- */ - -int _p(int y) -{ - return y + y / 4 - y / 100 + y / 400; -} - -int _is_leap(int year) -{ - return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); -} - -int _is_long_year(int year) -{ - return (_p(year) % 7 == 4) || (_p(year - 1) % 7 == 3); -} - -int _week_day(int year, int month, int day) -{ - int y; - int w; - - y = year - (month < 3); - - w = (_p(y) + DAY_OF_WEEK_TABLE[month - 1] + day) % 7; - - if (!w) - { - w = 7; - } - - return w; -} - -int _days_in_year(int year) -{ - if (_is_leap(year)) - { - return DAYS_PER_L_YEAR; - } - - return DAYS_PER_N_YEAR; -} - -int _day_number(int year, int month, int day) -{ - month = (month + 9) % 12; - year = year - month / 10; - - return ( - 365 * year + year / 4 - year / 100 + year / 400 + (month * 306 + 5) / 10 + (day - 1)); -} - -int _get_offset(PyObject *dt) -{ - PyObject *tzinfo; - PyObject *offset; - - tzinfo = ((PyDateTime_DateTime *)(dt))->tzinfo; - - if (tzinfo != Py_None) - { - offset = PyObject_CallMethod(tzinfo, "utcoffset", "O", dt); - - return PyDateTime_DELTA_GET_DAYS(offset) * SECS_PER_DAY + PyDateTime_DELTA_GET_SECONDS(offset); - } - - return 0; -} - -int _has_tzinfo(PyObject *dt) -{ - return ((_PyDateTime_BaseTZInfo *)(dt))->hastzinfo; -} - -char *_get_tz_name(PyObject *dt) -{ - PyObject *tzinfo; - char *tz = ""; - - tzinfo = ((PyDateTime_DateTime *)(dt))->tzinfo; - - if (tzinfo != Py_None) - { - if (PyObject_HasAttrString(tzinfo, "key")) - { - // zoneinfo timezone - tz = (char *)PyUnicode_AsUTF8( - PyObject_GetAttrString(tzinfo, "name")); - } - else if (PyObject_HasAttrString(tzinfo, "name")) - { - // Pendulum timezone - tz = (char *)PyUnicode_AsUTF8( - PyObject_GetAttrString(tzinfo, "name")); - } - else if (PyObject_HasAttrString(tzinfo, "zone")) - { - // pytz timezone - tz = (char *)PyUnicode_AsUTF8( - PyObject_GetAttrString(tzinfo, "zone")); - } - } - - return tz; -} - -/* ------------------------ Custom Types ------------------------------- */ - -/* - * class Diff(): - */ -typedef struct -{ - PyObject_HEAD int years; - int months; - int days; - int hours; - int minutes; - int seconds; - int microseconds; - int total_days; -} Diff; - -/* - * def __init__(self, years, months, days, hours, minutes, seconds, microseconds, total_days): - * self.years = years - * # ... -*/ -static int Diff_init(Diff *self, PyObject *args, PyObject *kwargs) -{ - int years; - int months; - int days; - int hours; - int minutes; - int seconds; - int microseconds; - int total_days; - - if (!PyArg_ParseTuple(args, "iiiiiii", &years, &months, &days, &hours, &minutes, &seconds, µseconds, &total_days)) - return -1; - - self->years = years; - self->months = months; - self->days = days; - self->hours = hours; - self->minutes = minutes; - self->seconds = seconds; - self->microseconds = microseconds; - self->total_days = total_days; - - return 0; -} - -/* - * def __repr__(self): - * return '{} years {} months {} days {} hours {} minutes {} seconds {} microseconds'.format( - * self.years, self.months, self.days, self.minutes, self.hours, self.seconds, self.microseconds - * ) - */ -static PyObject *Diff_repr(Diff *self) -{ - return PyUnicode_FromFormat( - "%d years %d months %d days %d hours %d minutes %d seconds %d microseconds", - self->years, - self->months, - self->days, - self->hours, - self->minutes, - self->seconds, - self->microseconds); -} - -/* - * Instantiate new Diff_type object - * Skip overhead of calling PyObject_New and PyObject_Init. - * Directly allocate object. - */ -static PyObject *new_diff_ex(int years, int months, int days, int hours, int minutes, int seconds, int microseconds, int total_days, PyTypeObject *type) -{ - Diff *self = (Diff *)(type->tp_alloc(type, 0)); - - if (self != NULL) - { - self->years = years; - self->months = months; - self->days = days; - self->hours = hours; - self->minutes = minutes; - self->seconds = seconds; - self->microseconds = microseconds; - self->total_days = total_days; - } - - return (PyObject *)self; -} - -/* - * Class member / class attributes - */ -static PyMemberDef Diff_members[] = { - {"years", T_INT, offsetof(Diff, years), 0, "years in diff"}, - {"months", T_INT, offsetof(Diff, months), 0, "months in diff"}, - {"days", T_INT, offsetof(Diff, days), 0, "days in diff"}, - {"hours", T_INT, offsetof(Diff, hours), 0, "hours in diff"}, - {"minutes", T_INT, offsetof(Diff, minutes), 0, "minutes in diff"}, - {"seconds", T_INT, offsetof(Diff, seconds), 0, "seconds in diff"}, - {"microseconds", T_INT, offsetof(Diff, microseconds), 0, "microseconds in diff"}, - {"total_days", T_INT, offsetof(Diff, total_days), 0, "total days in diff"}, - {NULL}}; - -static PyTypeObject Diff_type = { - PyVarObject_HEAD_INIT(NULL, 0) "PreciseDiff", /* tp_name */ - sizeof(Diff), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)Diff_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - (reprfunc)Diff_repr, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - "Precise difference between two datetime objects", /* tp_doc */ -}; - -#define new_diff(years, months, days, hours, minutes, seconds, microseconds, total_days) new_diff_ex(years, months, days, hours, minutes, seconds, microseconds, total_days, &Diff_type) - -/* -------------------------- Functions --------------------------*/ - -PyObject *is_leap(PyObject *self, PyObject *args) -{ - PyObject *leap; - int year; - - if (!PyArg_ParseTuple(args, "i", &year)) - { - PyErr_SetString( - PyExc_ValueError, "Invalid parameters"); - return NULL; - } - - leap = PyBool_FromLong(_is_leap(year)); - - return leap; -} - -PyObject *is_long_year(PyObject *self, PyObject *args) -{ - PyObject *is_long; - int year; - - if (!PyArg_ParseTuple(args, "i", &year)) - { - PyErr_SetString( - PyExc_ValueError, "Invalid parameters"); - return NULL; - } - - is_long = PyBool_FromLong(_is_long_year(year)); - - return is_long; -} - -PyObject *week_day(PyObject *self, PyObject *args) -{ - PyObject *wd; - int year; - int month; - int day; - - if (!PyArg_ParseTuple(args, "iii", &year, &month, &day)) - { - PyErr_SetString( - PyExc_ValueError, "Invalid parameters"); - return NULL; - } - - wd = PyLong_FromLong(_week_day(year, month, day)); - - return wd; -} - -PyObject *days_in_year(PyObject *self, PyObject *args) -{ - PyObject *ndays; - int year; - - if (!PyArg_ParseTuple(args, "i", &year)) - { - PyErr_SetString( - PyExc_ValueError, "Invalid parameters"); - return NULL; - } - - ndays = PyLong_FromLong(_days_in_year(year)); - - return ndays; -} - -PyObject *timestamp(PyObject *self, PyObject *args) -{ - int64_t result; - PyObject *dt; - - if (!PyArg_ParseTuple(args, "O", &dt)) - { - PyErr_SetString( - PyExc_ValueError, "Invalid parameters"); - return NULL; - } - - int year = (double)PyDateTime_GET_YEAR(dt); - int month = PyDateTime_GET_MONTH(dt); - int day = PyDateTime_GET_DAY(dt); - int hour = PyDateTime_DATE_GET_HOUR(dt); - int minute = PyDateTime_DATE_GET_MINUTE(dt); - int second = PyDateTime_DATE_GET_SECOND(dt); - - result = (year - 1970) * 365 + MONTHS_OFFSETS[0][month]; - result += (int)floor((double)(year - 1968) / 4); - result -= (year - 1900) / 100; - result += (year - 1600) / 400; - - if (_is_leap(year) && month < 3) - { - result -= 1; - } - - result += day - 1; - result *= 24; - result += hour; - result *= 60; - result += minute; - result *= 60; - result += second; - - return PyLong_FromSsize_t(result); -} - -PyObject *local_time(PyObject *self, PyObject *args) -{ - double unix_time; - int32_t utc_offset; - int32_t year; - int32_t microsecond; - int64_t seconds; - int32_t leap_year; - int64_t sec_per_100years; - int64_t sec_per_4years; - int32_t sec_per_year; - int32_t month; - int32_t day; - int32_t month_offset; - int32_t hour; - int32_t minute; - int32_t second; - - if (!PyArg_ParseTuple(args, "dii", &unix_time, &utc_offset, µsecond)) - { - PyErr_SetString( - PyExc_ValueError, "Invalid parameters"); - return NULL; - } - - year = EPOCH_YEAR; - seconds = (int64_t)floor(unix_time); - - // Shift to a base year that is 400-year aligned. - if (seconds >= 0) - { - seconds -= 10957L * SECS_PER_DAY; - year += 30; // == 2000; - } - else - { - seconds += (int64_t)(146097L - 10957L) * SECS_PER_DAY; - year -= 370; // == 1600; - } - - seconds += utc_offset; - - // Handle years in chunks of 400/100/4/1 - year += 400 * (seconds / SECS_PER_400_YEARS); - seconds %= SECS_PER_400_YEARS; - if (seconds < 0) - { - seconds += SECS_PER_400_YEARS; - year -= 400; - } - - leap_year = 1; // 4-century aligned - - sec_per_100years = SECS_PER_100_YEARS[leap_year]; - - while (seconds >= sec_per_100years) - { - seconds -= sec_per_100years; - year += 100; - leap_year = 0; // 1-century, non 4-century aligned - sec_per_100years = SECS_PER_100_YEARS[leap_year]; - } - - sec_per_4years = SECS_PER_4_YEARS[leap_year]; - while (seconds >= sec_per_4years) - { - seconds -= sec_per_4years; - year += 4; - leap_year = 1; // 4-year, non century aligned - sec_per_4years = SECS_PER_4_YEARS[leap_year]; - } - - sec_per_year = SECS_PER_YEAR[leap_year]; - while (seconds >= sec_per_year) - { - seconds -= sec_per_year; - year += 1; - leap_year = 0; // non 4-year aligned - sec_per_year = SECS_PER_YEAR[leap_year]; - } - - // Handle months and days - month = TM_DECEMBER + 1; - day = seconds / SECS_PER_DAY + 1; - seconds %= SECS_PER_DAY; - while (month != TM_JANUARY + 1) - { - month_offset = MONTHS_OFFSETS[leap_year][month]; - if (day > month_offset) - { - day -= month_offset; - break; - } - - month -= 1; - } - - // Handle hours, minutes and seconds - hour = seconds / SECS_PER_HOUR; - seconds %= SECS_PER_HOUR; - minute = seconds / SECS_PER_MIN; - second = seconds % SECS_PER_MIN; - - return Py_BuildValue("NNNNNNN", - PyLong_FromLong(year), - PyLong_FromLong(month), - PyLong_FromLong(day), - PyLong_FromLong(hour), - PyLong_FromLong(minute), - PyLong_FromLong(second), - PyLong_FromLong(microsecond)); -} - -// Calculate a precise difference between two datetimes. -PyObject *precise_diff(PyObject *self, PyObject *args) -{ - PyObject *dt1; - PyObject *dt2; - - if (!PyArg_ParseTuple(args, "OO", &dt1, &dt2)) - { - PyErr_SetString( - PyExc_ValueError, "Invalid parameters"); - return NULL; - } - - int year_diff = 0; - int month_diff = 0; - int day_diff = 0; - int hour_diff = 0; - int minute_diff = 0; - int second_diff = 0; - int microsecond_diff = 0; - int sign = 1; - int year; - int month; - int leap; - int days_in_last_month; - int days_in_month; - int dt1_year = PyDateTime_GET_YEAR(dt1); - int dt2_year = PyDateTime_GET_YEAR(dt2); - int dt1_month = PyDateTime_GET_MONTH(dt1); - int dt2_month = PyDateTime_GET_MONTH(dt2); - int dt1_day = PyDateTime_GET_DAY(dt1); - int dt2_day = PyDateTime_GET_DAY(dt2); - int dt1_hour = 0; - int dt2_hour = 0; - int dt1_minute = 0; - int dt2_minute = 0; - int dt1_second = 0; - int dt2_second = 0; - int dt1_microsecond = 0; - int dt2_microsecond = 0; - int dt1_total_seconds = 0; - int dt2_total_seconds = 0; - int dt1_offset = 0; - int dt2_offset = 0; - int dt1_is_datetime = PyDateTime_Check(dt1); - int dt2_is_datetime = PyDateTime_Check(dt2); - char *tz1 = ""; - char *tz2 = ""; - int in_same_tz = 0; - int total_days = (_day_number(dt2_year, dt2_month, dt2_day) - _day_number(dt1_year, dt1_month, dt1_day)); - - // If both dates are datetimes, we check - // If we are in the same timezone - if (dt1_is_datetime && dt2_is_datetime) - { - if (_has_tzinfo(dt1)) - { - tz1 = _get_tz_name(dt1); - dt1_offset = _get_offset(dt1); - } - - if (_has_tzinfo(dt2)) - { - tz2 = _get_tz_name(dt2); - dt2_offset = _get_offset(dt2); - } - - in_same_tz = tz1 == tz2 && strncmp(tz1, "", 1); - } - - // If we have datetimes (and not only dates) - // we get the information we need - if (dt1_is_datetime) - { - dt1_hour = PyDateTime_DATE_GET_HOUR(dt1); - dt1_minute = PyDateTime_DATE_GET_MINUTE(dt1); - dt1_second = PyDateTime_DATE_GET_SECOND(dt1); - dt1_microsecond = PyDateTime_DATE_GET_MICROSECOND(dt1); - - if ((!in_same_tz && dt1_offset != 0) || total_days == 0) - { - dt1_hour -= dt1_offset / SECS_PER_HOUR; - dt1_offset %= SECS_PER_HOUR; - dt1_minute -= dt1_offset / SECS_PER_MIN; - dt1_offset %= SECS_PER_MIN; - dt1_second -= dt1_offset; - - if (dt1_second < 0) - { - dt1_second += 60; - dt1_minute -= 1; - } - else if (dt1_second > 60) - { - dt1_second -= 60; - dt1_minute += 1; - } - - if (dt1_minute < 0) - { - dt1_minute += 60; - dt1_hour -= 1; - } - else if (dt1_minute > 60) - { - dt1_minute -= 60; - dt1_hour += 1; - } - - if (dt1_hour < 0) - { - dt1_hour += 24; - dt1_day -= 1; - } - else if (dt1_hour > 24) - { - dt1_hour -= 24; - dt1_day += 1; - } - } - - dt1_total_seconds = (dt1_hour * SECS_PER_HOUR + dt1_minute * SECS_PER_MIN + dt1_second); - } - - if (dt2_is_datetime) - { - dt2_hour = PyDateTime_DATE_GET_HOUR(dt2); - dt2_minute = PyDateTime_DATE_GET_MINUTE(dt2); - dt2_second = PyDateTime_DATE_GET_SECOND(dt2); - dt2_microsecond = PyDateTime_DATE_GET_MICROSECOND(dt2); - - if ((!in_same_tz && dt2_offset != 0) || total_days == 0) - { - dt2_hour -= dt2_offset / SECS_PER_HOUR; - dt2_offset %= SECS_PER_HOUR; - dt2_minute -= dt2_offset / SECS_PER_MIN; - dt2_offset %= SECS_PER_MIN; - dt2_second -= dt2_offset; - - if (dt2_second < 0) - { - dt2_second += 60; - dt2_minute -= 1; - } - else if (dt2_second > 60) - { - dt2_second -= 60; - dt2_minute += 1; - } - - if (dt2_minute < 0) - { - dt2_minute += 60; - dt2_hour -= 1; - } - else if (dt2_minute > 60) - { - dt2_minute -= 60; - dt2_hour += 1; - } - - if (dt2_hour < 0) - { - dt2_hour += 24; - dt2_day -= 1; - } - else if (dt2_hour > 24) - { - dt2_hour -= 24; - dt2_day += 1; - } - } - - dt2_total_seconds = (dt2_hour * SECS_PER_HOUR + dt2_minute * SECS_PER_MIN + dt2_second); - } - - // Direct comparison between two datetimes does not work - // so we need to check by properties - int dt1_gt_dt2 = (dt1_year > dt2_year || (dt1_year == dt2_year && dt1_month > dt2_month) || (dt1_year == dt2_year && dt1_month == dt2_month && dt1_day > dt2_day) || (dt1_year == dt2_year && dt1_month == dt2_month && dt1_day == dt2_day && dt1_total_seconds > dt2_total_seconds) || (dt1_year == dt2_year && dt1_month == dt2_month && dt1_day == dt2_day && dt1_total_seconds == dt2_total_seconds && dt1_microsecond > dt2_microsecond)); - - if (dt1_gt_dt2) - { - PyObject *temp; - temp = dt1; - dt1 = dt2; - dt2 = temp; - sign = -1; - - // Retrieving properties - dt1_year = PyDateTime_GET_YEAR(dt1); - dt2_year = PyDateTime_GET_YEAR(dt2); - dt1_month = PyDateTime_GET_MONTH(dt1); - dt2_month = PyDateTime_GET_MONTH(dt2); - dt1_day = PyDateTime_GET_DAY(dt1); - dt2_day = PyDateTime_GET_DAY(dt2); - - if (dt2_is_datetime) - { - dt1_hour = PyDateTime_DATE_GET_HOUR(dt1); - dt1_minute = PyDateTime_DATE_GET_MINUTE(dt1); - dt1_second = PyDateTime_DATE_GET_SECOND(dt1); - dt1_microsecond = PyDateTime_DATE_GET_MICROSECOND(dt1); - } - - if (dt1_is_datetime) - { - dt2_hour = PyDateTime_DATE_GET_HOUR(dt2); - dt2_minute = PyDateTime_DATE_GET_MINUTE(dt2); - dt2_second = PyDateTime_DATE_GET_SECOND(dt2); - dt2_microsecond = PyDateTime_DATE_GET_MICROSECOND(dt2); - } - - total_days = (_day_number(dt2_year, dt2_month, dt2_day) - _day_number(dt1_year, dt1_month, dt1_day)); - } - - year_diff = dt2_year - dt1_year; - month_diff = dt2_month - dt1_month; - day_diff = dt2_day - dt1_day; - hour_diff = dt2_hour - dt1_hour; - minute_diff = dt2_minute - dt1_minute; - second_diff = dt2_second - dt1_second; - microsecond_diff = dt2_microsecond - dt1_microsecond; - - if (microsecond_diff < 0) - { - microsecond_diff += 1e6; - second_diff -= 1; - } - - if (second_diff < 0) - { - second_diff += 60; - minute_diff -= 1; - } - - if (minute_diff < 0) - { - minute_diff += 60; - hour_diff -= 1; - } - - if (hour_diff < 0) - { - hour_diff += 24; - day_diff -= 1; - } - - if (day_diff < 0) - { - // If we have a difference in days, - // we have to check if they represent months - year = dt2_year; - month = dt2_month; - - if (month == 1) - { - month = 12; - year -= 1; - } - else - { - month -= 1; - } - - leap = _is_leap(year); - - days_in_last_month = DAYS_PER_MONTHS[leap][month]; - days_in_month = DAYS_PER_MONTHS[_is_leap(dt2_year)][dt2_month]; - - if (day_diff < days_in_month - days_in_last_month) - { - // We don't have a full month, we calculate days - if (days_in_last_month < dt1_day) - { - day_diff += dt1_day; - } - else - { - day_diff += days_in_last_month; - } - } - else if (day_diff == days_in_month - days_in_last_month) - { - // We have exactly a full month - // We remove the days difference - // and add one to the months difference - day_diff = 0; - month_diff += 1; - } - else - { - // We have a full month - day_diff += days_in_last_month; - } - - month_diff -= 1; - } - - if (month_diff < 0) - { - month_diff += 12; - year_diff -= 1; - } - - return new_diff( - year_diff * sign, - month_diff * sign, - day_diff * sign, - hour_diff * sign, - minute_diff * sign, - second_diff * sign, - microsecond_diff * sign, - total_days * sign); -} - -/* ------------------------------------------------------------------------- */ - -static PyMethodDef helpers_methods[] = { - {"is_leap", - (PyCFunction)is_leap, - METH_VARARGS, - PyDoc_STR("Checks if a year is a leap year.")}, - {"is_long_year", - (PyCFunction)is_long_year, - METH_VARARGS, - PyDoc_STR("Checks if a year is a long year.")}, - {"week_day", - (PyCFunction)week_day, - METH_VARARGS, - PyDoc_STR("Returns the weekday number.")}, - {"days_in_year", - (PyCFunction)days_in_year, - METH_VARARGS, - PyDoc_STR("Returns the number of days in the given year.")}, - {"timestamp", - (PyCFunction)timestamp, - METH_VARARGS, - PyDoc_STR("Returns the timestamp of the given datetime.")}, - {"local_time", - (PyCFunction)local_time, - METH_VARARGS, - PyDoc_STR("Returns a UNIX time as a broken down time for a particular transition type.")}, - {"precise_diff", - (PyCFunction)precise_diff, - METH_VARARGS, - PyDoc_STR("Calculate a precise difference between two datetimes.")}, - {NULL}}; - -/* ------------------------------------------------------------------------- */ - -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_helpers", - NULL, - -1, - helpers_methods, - NULL, - NULL, - NULL, - NULL, -}; - -PyMODINIT_FUNC -PyInit__helpers(void) -{ - PyObject *module; - - PyDateTime_IMPORT; - - module = PyModule_Create(&moduledef); - - if (module == NULL) - return NULL; - - // Diff declaration - Diff_type.tp_new = PyType_GenericNew; - Diff_type.tp_members = Diff_members; - Diff_type.tp_init = (initproc)Diff_init; - - if (PyType_Ready(&Diff_type) < 0) - return NULL; - - PyModule_AddObject(module, "PreciseDiff", (PyObject *)&Diff_type); - - return module; -} -- cgit v1.2.3