diff --git a/pandas/src/period.c b/pandas/src/period.c index ee3a50f98b8c9..5a744de4c3f7b 100644 --- a/pandas/src/period.c +++ b/pandas/src/period.c @@ -1127,8 +1127,16 @@ npy_int64 get_period_ordinal(int year, int month, int day, { goto onError; } - weeks = days / 7; - return (npy_int64)(days - weeks * 2) - BDAY_OFFSET; + // calculate the current week assuming sunday as last day of a week + weeks = (days - BASE_WEEK_TO_DAY_OFFSET) / DAYS_PER_WEEK; + // calculate the current weekday (in range 1 .. 7) + delta = (days - BASE_WEEK_TO_DAY_OFFSET) % DAYS_PER_WEEK + 1; + // return the number of business days in full weeks plus the business days in the last - possible partial - week + return (npy_int64)(weeks * BUSINESS_DAYS_PER_WEEK) + + (delta <= BUSINESS_DAYS_PER_WEEK + ? delta + : BUSINESS_DAYS_PER_WEEK + 1) + - BDAY_OFFSET; } if (freq_group == FR_WK) diff --git a/pandas/src/period.h b/pandas/src/period.h index e8537680e27e7..55c3722ebaae7 100644 --- a/pandas/src/period.h +++ b/pandas/src/period.h @@ -38,6 +38,9 @@ #define ORD_OFFSET 719163LL // days until 1970-01-01 #define BDAY_OFFSET 513689LL // days until 1970-01-01 #define WEEK_OFFSET 102737LL +#define BASE_WEEK_TO_DAY_OFFSET 1 // difference between day 0 and end of week in days +#define DAYS_PER_WEEK 7 +#define BUSINESS_DAYS_PER_WEEK 5 #define HIGHFREQ_ORIG 0 // ORD_OFFSET * 86400LL // days until 1970-01-01 #define FR_ANN 1000 /* Annual */ diff --git a/pandas/tseries/tests/test_period.py b/pandas/tseries/tests/test_period.py index 55963b01d2779..0fc7101a99856 100644 --- a/pandas/tseries/tests/test_period.py +++ b/pandas/tseries/tests/test_period.py @@ -115,6 +115,10 @@ def test_period_constructor(self): # Biz day construction, roll forward if non-weekday i1 = Period('3/10/12', freq='B') + i2 = Period('3/10/12', freq='D') + self.assertEquals(i1, i2.asfreq('B')) + i2 = Period('3/11/12', freq='D') + self.assertEquals(i1, i2.asfreq('B')) i2 = Period('3/12/12', freq='D') self.assertEquals(i1, i2.asfreq('B')) @@ -292,7 +296,7 @@ def test_start_time(self): p = Period('2012', freq=f) self.assertEquals(p.start_time, xp) self.assertEquals(Period('2012', freq='B').start_time, - datetime(2011, 12, 30)) + datetime(2012, 1, 2)) self.assertEquals(Period('2012', freq='W').start_time, datetime(2011, 12, 26)) @@ -321,7 +325,7 @@ def _ex(*args): p = Period('2012', freq='H') self.assertEquals(p.end_time, xp) - xp = _ex(2012, 1, 2) + xp = _ex(2012, 1, 3) self.assertEquals(Period('2012', freq='B').end_time, xp) xp = _ex(2012, 1, 2) diff --git a/pandas/tseries/tests/test_tslib.py b/pandas/tseries/tests/test_tslib.py index 20138cb8b1eb8..cfc93a22c454b 100644 --- a/pandas/tseries/tests/test_tslib.py +++ b/pandas/tseries/tests/test_tslib.py @@ -8,7 +8,7 @@ from pandas.core.api import Timestamp -from pandas.tslib import period_asfreq +from pandas.tslib import period_asfreq, period_ordinal from pandas.tseries.frequencies import get_freq @@ -254,6 +254,36 @@ def test_intraday_conversion_factors(self): self.assertEqual(period_asfreq(1, get_freq('U'), get_freq('N'), False), 1000) + def test_period_ordinal_start_values(self): + # information for 1.1.1970 + self.assertEqual(0, period_ordinal(1970, 1, 1, 0, 0, 0, 0, 0, get_freq('Y'))) + self.assertEqual(0, period_ordinal(1970, 1, 1, 0, 0, 0, 0, 0, get_freq('M'))) + self.assertEqual(1, period_ordinal(1970, 1, 1, 0, 0, 0, 0, 0, get_freq('W'))) + self.assertEqual(0, period_ordinal(1970, 1, 1, 0, 0, 0, 0, 0, get_freq('D'))) + self.assertEqual(0, period_ordinal(1970, 1, 1, 0, 0, 0, 0, 0, get_freq('B'))) + + def test_period_ordinal_week(self): + self.assertEqual(1, period_ordinal(1970, 1, 4, 0, 0, 0, 0, 0, get_freq('W'))) + self.assertEqual(2, period_ordinal(1970, 1, 5, 0, 0, 0, 0, 0, get_freq('W'))) + + self.assertEqual(2284, period_ordinal(2013, 10, 6, 0, 0, 0, 0, 0, get_freq('W'))) + self.assertEqual(2285, period_ordinal(2013, 10, 7, 0, 0, 0, 0, 0, get_freq('W'))) + + def test_period_ordinal_business_day(self): + # Thursday + self.assertEqual(11415, period_ordinal(2013, 10, 3, 0, 0, 0, 0, 0, get_freq('B'))) + # Friday + self.assertEqual(11416, period_ordinal(2013, 10, 4, 0, 0, 0, 0, 0, get_freq('B'))) + # Saturday + self.assertEqual(11417, period_ordinal(2013, 10, 5, 0, 0, 0, 0, 0, get_freq('B'))) + # Sunday + self.assertEqual(11417, period_ordinal(2013, 10, 6, 0, 0, 0, 0, 0, get_freq('B'))) + # Monday + self.assertEqual(11417, period_ordinal(2013, 10, 7, 0, 0, 0, 0, 0, get_freq('B'))) + # Tuesday + self.assertEqual(11418, period_ordinal(2013, 10, 8, 0, 0, 0, 0, 0, get_freq('B'))) + + if __name__ == '__main__': nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'], exit=False)