Commit 844918e8 authored by Julien Muchembled's avatar Julien Muchembled

Fix DateUtils.atTheEndOfPeriod and an infinite loop in some timezones

Contrary to Europe/Paris, Zope performs automatic DST calculation in US/Eastern
timezone, which caused infinite loop in Alarm.getNextPeriodicalDate.

Reenable testOpenOrder.testPeriodicityDateList (still failing though),
and create a testOpenOrder.testPeriodicityDateListUniversal to show that it
works with UTC times.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@31657 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 30712e8e
......@@ -35,7 +35,7 @@ from Products.ERP5Type.XMLObject import XMLObject
from Acquisition import aq_base
from DateTime import DateTime
from Products.ERP5Type.Message import Message
from Products.ERP5Type.DateUtils import addToDate
from Products.ERP5Type.DateUtils import addToDate, atTheEndOfPeriod
from Products.ERP5Security.ERP5UserManager import SUPER_USER
from AccessControl.SecurityManagement import getSecurityManager, \
setSecurityManager, newSecurityManager
......@@ -158,40 +158,23 @@ class PeriodicityMixin:
or (periodicity_stop_date is not None \
and next_start_date >= periodicity_stop_date):
return None
else:
# Make sure the old date is not too far away
day_count = int(current_date - next_start_date)
next_start_date = next_start_date + day_count
previous_date = next_start_date
next_start_date = addToDate(next_start_date, minute=1)
next_start_date = max(addToDate(next_start_date, minute=1), current_date)
while 1:
validate_minute = self._validateMinute(next_start_date, previous_date)
validate_hour = self._validateHour(next_start_date)
validate_day = self._validateDay(next_start_date)
validate_week = self._validateWeek(next_start_date)
validate_month = self._validateMonth(next_start_date)
if (next_start_date >= current_date \
and validate_minute and validate_hour and validate_day \
and validate_week and validate_month):
break
else:
if not(validate_minute):
if not self._validateMonth(next_start_date):
next_start_date = atTheEndOfPeriod(next_start_date, 'month')
elif not (self._validateDay(next_start_date) and
self._validateWeek(next_start_date)):
next_start_date = atTheEndOfPeriod(next_start_date, 'day')
elif not self._validateMinute(next_start_date, previous_date):
next_start_date = addToDate(next_start_date, minute=1)
else:
if not(validate_hour):
elif not self._validateHour(next_start_date):
next_start_date = addToDate(next_start_date, hour=1)
else:
if not(validate_day and validate_week and validate_month):
# We have to reset hours and minutes in order to make sure
# we will start at the beginning of the next day
next_start_date = DateTime(next_start_date.Date() + ' 00:00:00 %s' % next_start_date.timezone())
next_start_date = addToDate(next_start_date, day=1)
else:
# Everything is right, but the date is still not bigger
# than the current date, so we must continue
next_start_date = addToDate(next_start_date, minute=1)
return next_start_date
parts = list(next_start_date.parts())
parts[5] = previous_date.second() # XXX keep old behaviour
return DateTime(*parts)
# XXX May be we should create a Date class for following methods ???
security.declareProtected(Permissions.AccessContentsInformation, 'getWeekDayList')
......
......@@ -172,59 +172,64 @@ class TestOpenOrder(ERP5TypeTestCase):
transaction.commit()
self.tic()
def testPeriodicityDateList(self):
def testPeriodicityDateList(self, timezone=None):
"""
Make sure that periodicity line can generate correct schedule.
"""
self.fail('Test disabled because it freezes')
#self.fail('Test disabled because it freezes')
def D(yr, mo, dy, hr=0, mn=0, sc=0):
return DateTime(yr, mo, dy, hr, mn, sc, timezone)
# This across Summer time period, if server's timezone uses it.
self.assertEqual(self.portal.sale_trade_condition_module.main_trade_condition.internet_connection_periodicity_line.getDatePeriodList(
DateTime(2008,1,15), DateTime(2008,12,1)),
[(DateTime(2008,2,1,0,1), DateTime(2008,2,29)),
(DateTime(2008,3,1,0,1), DateTime(2008,3,31)),
(DateTime(2008,4,1,0,1), DateTime(2008,4,30)),
(DateTime(2008,5,1,0,1), DateTime(2008,5,31)),
(DateTime(2008,6,1,0,1), DateTime(2008,6,30)),
(DateTime(2008,7,1,0,1), DateTime(2008,7,31)),
(DateTime(2008,8,1,0,1), DateTime(2008,8,31)),
(DateTime(2008,9,1,0,1), DateTime(2008,9,30)),
(DateTime(2008,10,1,0,1), DateTime(2008,10,31)),
(DateTime(2008,11,1,0,1), DateTime(2008,11,30)),
D(2008,1,15), D(2008,12,1)),
[(D(2008,2,1,0,1), DateTime(2008,2,29)),
(D(2008,3,1,0,1), DateTime(2008,3,31)),
(D(2008,4,1,0,1), DateTime(2008,4,30)),
(D(2008,5,1,0,1), DateTime(2008,5,31)),
(D(2008,6,1,0,1), DateTime(2008,6,30)),
(D(2008,7,1,0,1), DateTime(2008,7,31)),
(D(2008,8,1,0,1), DateTime(2008,8,31)),
(D(2008,9,1,0,1), DateTime(2008,9,30)),
(D(2008,10,1,0,1), DateTime(2008,10,31)),
(D(2008,11,1,0,1), DateTime(2008,11,30)),
])
self.assertEqual(self.portal.sale_trade_condition_module.main_trade_condition.bread_periodicity_line.getDatePeriodList(
DateTime(2008,2,26), DateTime(2008,3,5)),
[(DateTime(2008,2,26,6,0), DateTime(2008,2,26,6,0)),
(DateTime(2008,2,26,12,0), DateTime(2008,2,26,12,0)),
(DateTime(2008,2,27,6,0), DateTime(2008,2,27,6,0)),
(DateTime(2008,2,27,12,0), DateTime(2008,2,27,12,0)),
(DateTime(2008,2,28,6,0), DateTime(2008,2,28,6,0)),
(DateTime(2008,2,28,12,0), DateTime(2008,2,28,12,0)),
(DateTime(2008,2,29,6,0), DateTime(2008,2,29,6,0)),
(DateTime(2008,2,29,12,0), DateTime(2008,2,29,12,0)),
(DateTime(2008,3,1,6,0), DateTime(2008,3,1,6,0)),
(DateTime(2008,3,1,12,0), DateTime(2008,3,1,12,0)),
(DateTime(2008,3,3,6,0), DateTime(2008,3,3,6,0)),
(DateTime(2008,3,3,12,0), DateTime(2008,3,3,12,0)),
(DateTime(2008,3,4,6,0), DateTime(2008,3,4,6,0)),
(DateTime(2008,3,4,12,0), DateTime(2008,3,4,12,0)),
D(2008,2,26), D(2008,3,5)),
[(D(2008,2,26,6,0), D(2008,2,26,6,0)),
(D(2008,2,26,12,0), D(2008,2,26,12,0)),
(D(2008,2,27,6,0), D(2008,2,27,6,0)),
(D(2008,2,27,12,0), D(2008,2,27,12,0)),
(D(2008,2,28,6,0), D(2008,2,28,6,0)),
(D(2008,2,28,12,0), D(2008,2,28,12,0)),
(D(2008,2,29,6,0), D(2008,2,29,6,0)),
(D(2008,2,29,12,0), D(2008,2,29,12,0)),
(D(2008,3,1,6,0), D(2008,3,1,6,0)),
(D(2008,3,1,12,0), D(2008,3,1,12,0)),
(D(2008,3,3,6,0), D(2008,3,3,6,0)),
(D(2008,3,3,12,0), D(2008,3,3,12,0)),
(D(2008,3,4,6,0), D(2008,3,4,6,0)),
(D(2008,3,4,12,0), D(2008,3,4,12,0)),
])
self.assertEqual(self.portal.sale_trade_condition_module.main_trade_condition.water_periodicity_line.getDatePeriodList(
DateTime(2008,2,16), DateTime(2008,4,15)),
[(DateTime(2008,2,18,10,0), DateTime(2008,3,3,10,0)),
(DateTime(2008,3,3,10,0), DateTime(2008,3,17,10,0)),
(DateTime(2008,3,17,10,0), DateTime(2008,3,31,10,0)),
(DateTime(2008,3,31,10,0), DateTime(2008,4,14,10,0)),
(DateTime(2008,4,14,10,0), DateTime(2008,4,28,10,0)),
D(2008,2,16), D(2008,4,15)),
[(D(2008,2,18,10,0), D(2008,3,3,10,0)),
(D(2008,3,3,10,0), D(2008,3,17,10,0)),
(D(2008,3,17,10,0), D(2008,3,31,10,0)),
(D(2008,3,31,10,0), D(2008,4,14,10,0)),
(D(2008,4,14,10,0), D(2008,4,28,10,0)),
])
self.assertEqual(self.portal.sale_trade_condition_module.main_trade_condition.training_periodicity_line.getDatePeriodList(
DateTime(2008,2,16), DateTime(2008,3,6)),
[(DateTime(2008,2,18,10,0), DateTime(2008,2,19,10,0)),
(DateTime(2008,2,25,10,0), DateTime(2008,2,26,10,0)),
(DateTime(2008,3,3,10,0), DateTime(2008,3,4,10,0)),
D(2008,2,16), D(2008,3,6)),
[(D(2008,2,18,10,0), D(2008,2,19,10,0)),
(D(2008,2,25,10,0), D(2008,2,26,10,0)),
(D(2008,3,3,10,0), D(2008,3,4,10,0)),
])
def testPeriodicityDateListUniversal(self):
self.testPeriodicityDateList('Universal')
def testOpenOrderRule(self):
"""
Make sure that Open Order Rule can generate simulation movements by
......
......@@ -506,21 +506,16 @@ def atTheEndOfPeriod(date, period):
If timezone is Universal, strftime('%Z') return empty string
and TimeZone is replaced by local zone,
so date formating is manualy rendered.
XXXSunday is hardcoded
"""
if period == 'year':
end = addToDate(DateTime('%s/01/01 00:00:00 %s' % (date.year(), date.timezone())), **{period:1})
elif period == 'month':
end = addToDate(DateTime('%s/%s/01 00:00:00 %s' % (date.year(), zfill(date.month(), 2), date.timezone())), **{period:1})
elif period == 'day':
end = addToDate(DateTime('%s/%s/%s 00:00:00 %s' % (date.year(), zfill(date.month(), 2), zfill(date.day(), 2), date.timezone())), **{period:1})
end = addToDate(date.earliestTime(), hour=36).earliestTime()
elif period == 'week':
day_of_week = date.strftime('%A')
end = DateTime('%s/%s/%s 00:00:00 %s' % (date.year(), zfill(date.month(), 2), zfill(date.day(), 2), date.timezone()))
while day_of_week != 'Sunday':
end = addToDate(end, day=1)
day_of_week = end.strftime('%A')
end = addToDate(end, day=1)
end = atTheEndOfPeriod(date, 'day')
end = addToDate(end, day=(1-end.dow()) % 7)
else:
raise NotImplementedError, 'Period "%s" not Handled yet' % period
return end
......@@ -167,6 +167,24 @@ class TestDateUtils(unittest.TestCase):
self.assertEqual(atTheEndOfPeriod(date, 'month').pCommonZ(), 'Feb. 1, 2008 12:00 am Universal')
self.assertEqual(atTheEndOfPeriod(date, 'week').pCommonZ(), 'Jan. 7, 2008 12:00 am Universal')
self.assertEqual(atTheEndOfPeriod(date, 'day').pCommonZ(), 'Jan. 2, 2008 12:00 am Universal')
# Switch to summer time
self.assertEqual('Apr. 6, 2008 12:00 am US/Eastern',
atTheEndOfPeriod(DateTime('2008/04/05 23:59:59 US/Eastern'), 'day').pCommonZ())
self.assertEqual('Apr. 7, 2008 12:00 am US/Eastern',
atTheEndOfPeriod(DateTime('2008/04/06 00:00:00 US/Eastern'), 'day').pCommonZ())
self.assertEqual('Apr. 7, 2008 12:00 am US/Eastern',
atTheEndOfPeriod(DateTime('2008/04/06 23:59:59 US/Eastern'), 'day').pCommonZ())
self.assertEqual('May 1, 2008 12:00 am US/Eastern',
atTheEndOfPeriod(DateTime('2008/04/01 US/Eastern'), 'month').pCommonZ())
# Switch to winter time
self.assertEqual('Oct. 26, 2008 12:00 am US/Eastern',
atTheEndOfPeriod(DateTime('2008/10/25 23:59:59 US/Eastern'), 'day').pCommonZ())
self.assertEqual('Oct. 27, 2008 12:00 am US/Eastern',
atTheEndOfPeriod(DateTime('2008/10/26 00:00:00 US/Eastern'), 'day').pCommonZ())
self.assertEqual('Oct. 27, 2008 12:00 am US/Eastern',
atTheEndOfPeriod(DateTime('2008/10/26 23:59:59 US/Eastern'), 'day').pCommonZ())
self.assertEqual('Nov. 1, 2008 12:00 am US/Eastern',
atTheEndOfPeriod(DateTime('2008/10/01 US/Eastern'), 'month').pCommonZ())
def test_suite():
suite = unittest.TestSuite()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment