Skip to content

Implement get_day_of_year, tests #19555

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pandas/_libs/tslibs/ccalendar.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ cdef int dayofweek(int y, int m, int m) nogil
cdef bint is_leapyear(int64_t year) nogil
cpdef int32_t get_days_in_month(int year, Py_ssize_t month) nogil
cpdef int32_t get_week_of_year(int year, int month, int day) nogil
cpdef int32_t get_day_of_year(int year, int month, int day) nogil
43 changes: 36 additions & 7 deletions pandas/_libs/tslibs/ccalendar.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -142,17 +142,13 @@ cpdef int32_t get_week_of_year(int year, int month, int day) nogil:
Assumes the inputs describe a valid date.
"""
cdef:
bint isleap, isleap_prev
int32_t mo_off
bint isleap
int32_t doy, dow
int woy

isleap = is_leapyear(year)
isleap_prev = is_leapyear(year - 1)

mo_off = _month_offset[isleap * 13 + month - 1]

doy = mo_off + day
doy = get_day_of_year(year, month, day)
dow = dayofweek(year, month, day)

# estimate
Expand All @@ -162,7 +158,7 @@ cpdef int32_t get_week_of_year(int year, int month, int day) nogil:

# verify
if woy < 0:
if (woy > -2) or (woy == -2 and isleap_prev):
if (woy > -2) or (woy == -2 and is_leapyear(year - 1)):
woy = 53
else:
woy = 52
Expand All @@ -171,3 +167,36 @@ cpdef int32_t get_week_of_year(int year, int month, int day) nogil:
woy = 1

return woy


@cython.wraparound(False)
@cython.boundscheck(False)
cpdef int32_t get_day_of_year(int year, int month, int day) nogil:
"""Return the ordinal day-of-year for the given day.

Parameters
----------
year : int
month : int
day : int

Returns
-------
day_of_year : int32_t

Notes
-----
Assumes the inputs describe a valid date.
"""
cdef:
bint isleap
int32_t mo_off
int32_t doy, dow
int woy

isleap = is_leapyear(year)

mo_off = _month_offset[isleap * 13 + month - 1]

day_of_year = mo_off + day
return day_of_year
13 changes: 2 additions & 11 deletions pandas/_libs/tslibs/fields.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ cnp.import_array()


from ccalendar cimport (get_days_in_month, is_leapyear, dayofweek,
get_week_of_year)
get_week_of_year, get_day_of_year)
from np_datetime cimport (pandas_datetimestruct, pandas_timedeltastruct,
dt64_to_dtstruct, td64_to_tdstruct)
from nattype cimport NPY_NAT
Expand Down Expand Up @@ -374,15 +374,7 @@ def get_date_field(ndarray[int64_t] dtindex, object field):
cdef:
Py_ssize_t i, count = 0
ndarray[int32_t] out
ndarray[int32_t, ndim=2] _month_offset
int isleap, isleap_prev
pandas_datetimestruct dts
int mo_off, doy, dow

_month_offset = np.array(
[[0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365],
[0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]],
dtype=np.int32 )

count = len(dtindex)
out = np.empty(count, dtype='i4')
Expand Down Expand Up @@ -482,8 +474,7 @@ def get_date_field(ndarray[int64_t] dtindex, object field):
continue

dt64_to_dtstruct(dtindex[i], &dts)
isleap = is_leapyear(dts.year)
out[i] = _month_offset[isleap, dts.month -1] + dts.day
out[i] = get_day_of_year(dts.year, dts.month, dts.day)
return out

elif field == 'dow':
Expand Down
5 changes: 3 additions & 2 deletions pandas/_libs/tslibs/period.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ from cpython.datetime cimport PyDateTime_Check, PyDateTime_IMPORT
PyDateTime_IMPORT

from np_datetime cimport (pandas_datetimestruct, dtstruct_to_dt64,
dt64_to_dtstruct, is_leapyear)
dt64_to_dtstruct)

cimport util
from util cimport is_period_object, is_string_object, INT32_MIN
Expand All @@ -34,11 +34,12 @@ from timezones cimport is_utc, is_tzlocal, get_utcoffset, get_dst_info
from timedeltas cimport delta_to_nanoseconds

from ccalendar import MONTH_NUMBERS
from ccalendar cimport is_leapyear
from frequencies cimport (get_freq_code, get_base_alias,
get_to_timestamp_base, get_freq_str,
get_rule_month)
from parsing import parse_time_string, NAT_SENTINEL
from resolution import resolution, Resolution
from resolution import Resolution
from nattype import nat_strings, NaT, iNaT
from nattype cimport _nat_scalar_rules, NPY_NAT

Expand Down
20 changes: 4 additions & 16 deletions pandas/_libs/tslibs/timestamps.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ from nattype import NaT
from nattype cimport NPY_NAT
from np_datetime import OutOfBoundsDatetime
from np_datetime cimport (reverse_ops, cmp_scalar, check_dts_bounds,
pandas_datetimestruct, dt64_to_dtstruct,
is_leapyear)
pandas_datetimestruct, dt64_to_dtstruct)
from timedeltas import Timedelta
from timedeltas cimport delta_to_nanoseconds
from timezones cimport (
Expand Down Expand Up @@ -291,14 +290,6 @@ cdef class _Timestamp(datetime):
val = tz_convert_single(self.value, 'UTC', self.tz)
return val

cpdef int _get_field(self, field):
cdef:
int64_t val
ndarray[int32_t] out
val = self._maybe_convert_value_to_local()
out = get_date_field(np.array([val], dtype=np.int64), field)
return int(out[0])

cpdef bint _get_start_end_field(self, str field):
cdef:
int64_t val
Expand Down Expand Up @@ -695,14 +686,11 @@ class Timestamp(_Timestamp):

@property
def dayofyear(self):
return self._get_field('doy')
return ccalendar.get_day_of_year(self.year, self.month, self.day)

@property
def week(self):
if self.freq is None:
# fastpath for non-business
return ccalendar.get_week_of_year(self.year, self.month, self.day)
return self._get_field('woy')
return ccalendar.get_week_of_year(self.year, self.month, self.day)

weekofyear = week

Expand Down Expand Up @@ -764,7 +752,7 @@ class Timestamp(_Timestamp):

@property
def is_leap_year(self):
return bool(is_leapyear(self.year))
return bool(ccalendar.is_leapyear(self.year))

def tz_localize(self, tz, ambiguous='raise', errors='raise'):
"""
Expand Down
4 changes: 2 additions & 2 deletions pandas/core/indexes/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
from pandas._libs import (lib, index as libindex, tslib as libts,
join as libjoin, Timestamp)
from pandas._libs.tslibs import (timezones, conversion, fields, parsing,
period as libperiod)
resolution as libresolution)

# -------- some conversion wrapper functions

Expand Down Expand Up @@ -1795,7 +1795,7 @@ def is_normalized(self):

@cache_readonly
def _resolution(self):
return libperiod.resolution(self.asi8, self.tz)
return libresolution.resolution(self.asi8, self.tz)

def insert(self, loc, item):
"""
Expand Down
Empty file added pandas/tests/tslibs/__init__.py
Empty file.
18 changes: 18 additions & 0 deletions pandas/tests/tslibs/test_ccalendar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from datetime import datetime

import numpy as np

from pandas._libs.tslibs import ccalendar


def test_get_day_of_year():
assert ccalendar.get_day_of_year(2001, 3, 1) == 60
assert ccalendar.get_day_of_year(2004, 3, 1) == 61
assert ccalendar.get_day_of_year(1907, 12, 31) == 365
assert ccalendar.get_day_of_year(2004, 12, 31) == 366

dt = datetime.fromordinal(1 + np.random.randint(365 * 4000))
result = ccalendar.get_day_of_year(dt.year, dt.month, dt.day)
expected = (dt - dt.replace(month=1, day=1)).days + 1
assert result == expected
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,7 @@ def pxd(name):
'pyxfile': '_libs/tslibs/period',
'pxdfiles': ['_libs/src/util',
'_libs/missing',
'_libs/tslibs/ccalendar',
'_libs/tslibs/timedeltas',
'_libs/tslibs/timezones',
'_libs/tslibs/nattype'],
Expand Down