Skip to content

Commit 6efff7a

Browse files
committed
Merge branch 'improve-internal-structure' into develop
2 parents 2637a8e + 14f104b commit 6efff7a

File tree

13 files changed

+444
-4365
lines changed

13 files changed

+444
-4365
lines changed
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
/* ------------------------------------------------------------------------- */
2+
3+
#include <Python.h>
4+
5+
#ifndef PyVarObject_HEAD_INIT
6+
#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
7+
#endif
8+
9+
#if PY_MAJOR_VERSION < 3
10+
#define PyLong_FromLong PyInt_FromLong
11+
#endif
12+
13+
/* ------------------------------------------------------------------------- */
14+
15+
const int EPOCH_YEAR = 1970;
16+
17+
const int DAYS_PER_N_YEAR = 365;
18+
const int DAYS_PER_L_YEAR = 366;
19+
20+
const int USECS_PER_SEC = 1000000;
21+
22+
const int SECS_PER_MIN = 60;
23+
const int SECS_PER_HOUR = 60 * SECS_PER_MIN;
24+
const int SECS_PER_DAY = SECS_PER_HOUR * 24;
25+
26+
// 400-year chunks always have 146097 days (20871 weeks).
27+
const long DAYS_PER_400_YEARS = 146097L;
28+
const long SECS_PER_400_YEARS = DAYS_PER_400_YEARS * SECS_PER_DAY;
29+
30+
// The number of seconds in an aligned 100-year chunk, for those that
31+
// do not begin with a leap year and those that do respectively.
32+
const long SECS_PER_100_YEARS[2] = {
33+
(76L * DAYS_PER_N_YEAR + 24L * DAYS_PER_L_YEAR) * SECS_PER_DAY,
34+
(75L * DAYS_PER_N_YEAR + 25L * DAYS_PER_L_YEAR) * SECS_PER_DAY
35+
};
36+
37+
// The number of seconds in an aligned 4-year chunk, for those that
38+
// do not begin with a leap year and those that do respectively.
39+
const long SECS_PER_4_YEARS[2] = {
40+
(4 * DAYS_PER_N_YEAR + 0 * DAYS_PER_L_YEAR) * SECS_PER_DAY,
41+
(3 * DAYS_PER_N_YEAR + 1 * DAYS_PER_L_YEAR) * SECS_PER_DAY
42+
};
43+
44+
// The number of seconds in non-leap and leap years respectively.
45+
const int SECS_PER_YEAR[2] = {
46+
DAYS_PER_N_YEAR * SECS_PER_DAY,
47+
DAYS_PER_L_YEAR * SECS_PER_DAY
48+
};
49+
50+
const int MONTHS_PER_YEAR = 12;
51+
52+
// The month lengths in non-leap and leap years respectively.
53+
const int DAYS_PER_MONTHS[2][13] = {
54+
{-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
55+
{-1, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
56+
};
57+
58+
// The day offsets of the beginning of each (1-based) month in non-leap
59+
// and leap years respectively.
60+
// For example, in a leap year there are 335 days before December.
61+
const int MONTHS_OFFSETS[2][14] = {
62+
{-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
63+
{-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
64+
};
65+
66+
const int TM_SUNDAY = 0;
67+
const int TM_MONDAY = 1;
68+
const int TM_TUESDAY = 2;
69+
const int TM_WEDNESDAY = 3;
70+
const int TM_THURSDAY = 4;
71+
const int TM_FRIDAY = 5;
72+
const int TM_SATURDAY = 6;
73+
74+
const int TM_JANUARY = 0;
75+
const int TM_FEBRUARY = 1;
76+
const int TM_MARCH = 2;
77+
const int TM_APRIL = 3;
78+
const int TM_MAY = 4;
79+
const int TM_JUNE = 5;
80+
const int TM_JULY = 6;
81+
const int TM_AUGUST = 7;
82+
const int TM_SEPTEMBER = 8;
83+
const int TM_OCTOBER = 9;
84+
const int TM_NOVEMBER = 10;
85+
const int TM_DECEMBER = 11;
86+
87+
/* ------------------------------------------------------------------------- */
88+
89+
PyObject* local_time(PyObject *self, PyObject *args) {
90+
double unix_time;
91+
int utc_offset;
92+
int year;
93+
long microsecond;
94+
long seconds;
95+
int leap_year;
96+
long sec_per_100years;
97+
long sec_per_4years;
98+
int sec_per_year;
99+
int month;
100+
int day;
101+
int month_offset;
102+
int hour;
103+
int minute;
104+
int second;
105+
106+
if (!PyArg_ParseTuple(args, "di", &unix_time, &utc_offset)) {
107+
PyErr_SetString(
108+
PyExc_ValueError, "Invalid parameters"
109+
);
110+
return NULL;
111+
}
112+
113+
year = EPOCH_YEAR;
114+
microsecond = (long) (unix_time * 1000000) % 1000000;
115+
if (microsecond < 0) {
116+
microsecond += 1000000;
117+
}
118+
seconds = (long) unix_time;
119+
120+
// Shift to a base year that is 400-year aligned.
121+
if (seconds >= 0) {
122+
seconds -= 10957L * SECS_PER_DAY;
123+
year += 30; // == 2000;
124+
} else {
125+
seconds += (146097L - 10957L) * SECS_PER_DAY;
126+
year -= 370; // == 1600;
127+
}
128+
129+
seconds += utc_offset;
130+
131+
// Handle years in chunks of 400/100/4/1
132+
year += 400 * (seconds / SECS_PER_400_YEARS);
133+
seconds %= SECS_PER_400_YEARS;
134+
if (seconds < 0) {
135+
seconds += SECS_PER_400_YEARS;
136+
year -= 400;
137+
}
138+
139+
leap_year = 1; // 4-century aligned
140+
141+
sec_per_100years = SECS_PER_100_YEARS[leap_year];
142+
143+
while (seconds >= sec_per_100years) {
144+
seconds -= sec_per_100years;
145+
year += 100;
146+
leap_year = 0; // 1-century, non 4-century aligned
147+
sec_per_100years = SECS_PER_100_YEARS[leap_year];
148+
}
149+
150+
sec_per_4years = SECS_PER_4_YEARS[leap_year];
151+
while (seconds >= sec_per_4years) {
152+
seconds -= sec_per_4years;
153+
year += 4;
154+
leap_year = 1; // 4-year, non century aligned
155+
sec_per_4years = SECS_PER_4_YEARS[leap_year];
156+
}
157+
158+
sec_per_year = SECS_PER_YEAR[leap_year];
159+
while (seconds >= sec_per_year) {
160+
seconds -= sec_per_year;
161+
year += 1;
162+
leap_year = 0; // non 4-year aligned
163+
sec_per_year = SECS_PER_YEAR[leap_year];
164+
}
165+
166+
// Handle months and days
167+
month = TM_DECEMBER + 1;
168+
day = seconds / SECS_PER_DAY + 1;
169+
seconds %= SECS_PER_DAY;
170+
while (month != TM_JANUARY + 1) {
171+
month_offset = MONTHS_OFFSETS[leap_year][month];
172+
if (day > month_offset) {
173+
day -= month_offset;
174+
break;
175+
}
176+
177+
month -= 1;
178+
}
179+
180+
// Handle hours, minutes, seconds and microseconds
181+
hour = seconds / SECS_PER_HOUR;
182+
seconds %= SECS_PER_HOUR;
183+
minute = seconds / SECS_PER_MIN;
184+
second = seconds % SECS_PER_MIN;
185+
186+
return PyTuple_Pack(
187+
7,
188+
PyLong_FromLong(year),
189+
PyLong_FromLong(month),
190+
PyLong_FromLong(day),
191+
PyLong_FromLong(hour),
192+
PyLong_FromLong(minute),
193+
PyLong_FromLong(second),
194+
PyLong_FromLong(microsecond)
195+
);
196+
}
197+
198+
/* ------------------------------------------------------------------------- */
199+
200+
static PyMethodDef localtime_methods[] = {
201+
{
202+
"local_time",
203+
(PyCFunction) local_time,
204+
METH_VARARGS,
205+
PyDoc_STR("Returns a UNIX time as a broken down time for a particular transition type.")
206+
},
207+
{NULL}
208+
};
209+
210+
/* ------------------------------------------------------------------------- */
211+
212+
#if PY_MAJOR_VERSION >= 3
213+
static struct PyModuleDef moduledef = {
214+
PyModuleDef_HEAD_INIT,
215+
"_local_time",
216+
NULL,
217+
-1,
218+
localtime_methods,
219+
NULL,
220+
NULL,
221+
NULL,
222+
NULL,
223+
};
224+
#endif
225+
226+
static PyObject *
227+
moduleinit(void)
228+
{
229+
PyObject *module;
230+
231+
#if PY_MAJOR_VERSION >= 3
232+
module = PyModule_Create(&moduledef);
233+
#else
234+
module = Py_InitModule3("_local_time", localtime_methods, NULL);
235+
#endif
236+
237+
if (module == NULL)
238+
return NULL;
239+
240+
return module;
241+
}
242+
243+
#if PY_MAJOR_VERSION < 3
244+
PyMODINIT_FUNC init_local_time(void)
245+
{
246+
moduleinit();
247+
}
248+
#else
249+
PyMODINIT_FUNC PyInit__local_time(void)
250+
{
251+
return moduleinit();
252+
}
253+
#endif

0 commit comments

Comments
 (0)