686 lines
26 KiB
Python
686 lines
26 KiB
Python
##############################################################################
|
|
#
|
|
# Copyright (c) 2003 Zope Foundation and Contributors.
|
|
# All Rights Reserved.
|
|
#
|
|
# This software is subject to the provisions of the Zope Public License,
|
|
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
|
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
|
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
|
# FOR A PARTICULAR PURPOSE.
|
|
#
|
|
##############################################################################
|
|
|
|
from datetime import date, datetime, tzinfo, timedelta
|
|
import math
|
|
import platform
|
|
import os
|
|
import sys
|
|
import time
|
|
import unittest
|
|
|
|
import pytz
|
|
|
|
from DateTime.DateTime import _findLocalTimeZoneName
|
|
from DateTime import DateTime
|
|
|
|
if sys.version_info > (3, ):
|
|
import pickle
|
|
unicode = str
|
|
PY3K = True
|
|
else:
|
|
import cPickle as pickle
|
|
PY3K = False
|
|
|
|
try:
|
|
__file__
|
|
except NameError:
|
|
f = sys.argv[0]
|
|
else:
|
|
f = __file__
|
|
|
|
IS_PYPY = getattr(platform, 'python_implementation', lambda: None)() == 'PyPy'
|
|
|
|
DATADIR = os.path.dirname(os.path.abspath(f))
|
|
del f
|
|
|
|
ZERO = timedelta(0)
|
|
|
|
|
|
class FixedOffset(tzinfo):
|
|
"""Fixed offset in minutes east from UTC."""
|
|
|
|
def __init__(self, offset, name):
|
|
self.__offset = timedelta(minutes=offset)
|
|
self.__name = name
|
|
|
|
def utcoffset(self, dt):
|
|
return self.__offset
|
|
|
|
def tzname(self, dt):
|
|
return self.__name
|
|
|
|
def dst(self, dt):
|
|
return ZERO
|
|
|
|
|
|
class DateTimeTests(unittest.TestCase):
|
|
|
|
def _compare(self, dt1, dt2):
|
|
'''Compares the internal representation of dt1 with
|
|
the representation in dt2. Allows sub-millisecond variations.
|
|
Primarily for testing.'''
|
|
self.assertEqual(round(dt1._t, 3), round(dt2._t, 3))
|
|
self.assertEqual(round(dt1._d, 9), round(dt2._d, 9))
|
|
self.assertEqual(round(dt1.time, 9), round(dt2.time, 9))
|
|
self.assertEqual(dt1.millis(), dt2.millis())
|
|
self.assertEqual(dt1._micros, dt2._micros)
|
|
|
|
def testBug1203(self):
|
|
# 01:59:60 occurred in old DateTime
|
|
dt = DateTime(7200, 'GMT')
|
|
self.assertTrue(str(dt).find('60') < 0, dt)
|
|
|
|
def testDSTInEffect(self):
|
|
# Checks GMT offset for a DST date in the US/Eastern time zone
|
|
dt = DateTime(2000, 5, 9, 15, 0, 0, 'US/Eastern')
|
|
self.assertEqual(dt.toZone('GMT').hour(), 19,
|
|
(dt, dt.toZone('GMT')))
|
|
|
|
def testDSTNotInEffect(self):
|
|
# Checks GMT offset for a non-DST date in the US/Eastern time zone
|
|
dt = DateTime(2000, 11, 9, 15, 0, 0, 'US/Eastern')
|
|
self.assertEqual(dt.toZone('GMT').hour(), 20,
|
|
(dt, dt.toZone('GMT')))
|
|
|
|
def testAddPrecision(self):
|
|
# Precision of serial additions
|
|
dt = DateTime()
|
|
self.assertEqual(str(dt + 0.10 + 3.14 + 6.76 - 10), str(dt),
|
|
dt)
|
|
|
|
def testConstructor3(self):
|
|
# Constructor from date/time string
|
|
dt = DateTime()
|
|
dt1s = '%d/%d/%d %d:%d:%f %s' % (
|
|
dt.year(),
|
|
dt.month(),
|
|
dt.day(),
|
|
dt.hour(),
|
|
dt.minute(),
|
|
dt.second(),
|
|
dt.timezone())
|
|
dt1 = DateTime(dt1s)
|
|
# Compare representations as it's the
|
|
# only way to compare the dates to the same accuracy
|
|
self.assertEqual(repr(dt), repr(dt1))
|
|
|
|
def testConstructor4(self):
|
|
# Constructor from time float
|
|
dt = DateTime()
|
|
dt1 = DateTime(float(dt))
|
|
self._compare(dt, dt1)
|
|
|
|
def testConstructor5(self):
|
|
# Constructor from time float and timezone
|
|
dt = DateTime()
|
|
dt1 = DateTime(float(dt), dt.timezone())
|
|
self.assertEqual(str(dt), str(dt1), (dt, dt1))
|
|
dt1 = DateTime(float(dt), unicode(dt.timezone()))
|
|
self.assertEqual(str(dt), str(dt1), (dt, dt1))
|
|
|
|
def testConstructor6(self):
|
|
# Constructor from year and julian date
|
|
# This test must normalize the time zone, or it *will* break when
|
|
# DST changes!
|
|
dt1 = DateTime(2000, 5.500000578705)
|
|
dt = DateTime('2000/1/5 12:00:00.050 pm %s' % dt1.localZone())
|
|
self._compare(dt, dt1)
|
|
|
|
def testConstructor7(self):
|
|
# Constructor from parts
|
|
dt = DateTime()
|
|
dt1 = DateTime(
|
|
dt.year(),
|
|
dt.month(),
|
|
dt.day(),
|
|
dt.hour(),
|
|
dt.minute(),
|
|
dt.second(),
|
|
dt.timezone())
|
|
# Compare representations as it's the
|
|
# only way to compare the dates to the same accuracy
|
|
self.assertEqual(repr(dt), repr(dt1))
|
|
|
|
def testDayOfWeek(self):
|
|
# Compare to the datetime.date value to make it locale independent
|
|
expected = date(2000, 6, 16).strftime('%A')
|
|
# strftime() used to always be passed a day of week of 0
|
|
dt = DateTime('2000/6/16')
|
|
s = dt.strftime('%A')
|
|
self.assertEqual(s, expected, (dt, s))
|
|
|
|
def testOldDate(self):
|
|
# Fails when an 1800 date is displayed with negative signs
|
|
dt = DateTime('1830/5/6 12:31:46.213 pm')
|
|
dt1 = dt.toZone('GMT+6')
|
|
self.assertTrue(str(dt1).find('-') < 0, (dt, dt1))
|
|
|
|
def testSubtraction(self):
|
|
# Reconstruction of a DateTime from its parts, with subtraction
|
|
# this also tests the accuracy of addition and reconstruction
|
|
dt = DateTime()
|
|
dt1 = dt - 3.141592653
|
|
dt2 = DateTime(
|
|
dt.year(),
|
|
dt.month(),
|
|
dt.day(),
|
|
dt.hour(),
|
|
dt.minute(),
|
|
dt.second())
|
|
dt3 = dt2 - 3.141592653
|
|
self.assertEqual(dt1, dt3, (dt, dt1, dt2, dt3))
|
|
|
|
def testTZ1add(self):
|
|
# Time zone manipulation: add to a date
|
|
dt = DateTime('1997/3/8 1:45am GMT-4')
|
|
dt1 = DateTime('1997/3/9 1:45pm GMT+8')
|
|
self.assertTrue((dt + 1.0).equalTo(dt1))
|
|
|
|
def testTZ1sub(self):
|
|
# Time zone manipulation: subtract from a date
|
|
dt = DateTime('1997/3/8 1:45am GMT-4')
|
|
dt1 = DateTime('1997/3/9 1:45pm GMT+8')
|
|
self.assertTrue((dt1 - 1.0).equalTo(dt))
|
|
|
|
def testTZ1diff(self):
|
|
# Time zone manipulation: diff two dates
|
|
dt = DateTime('1997/3/8 1:45am GMT-4')
|
|
dt1 = DateTime('1997/3/9 1:45pm GMT+8')
|
|
self.assertEqual(dt1 - dt, 1.0, (dt, dt1))
|
|
|
|
def test_compare_methods(self):
|
|
# Compare two dates using several methods
|
|
dt = DateTime('1997/1/1')
|
|
dt1 = DateTime('1997/2/2')
|
|
self.assertTrue(dt1.greaterThan(dt))
|
|
self.assertTrue(dt1.greaterThanEqualTo(dt))
|
|
self.assertTrue(dt.lessThan(dt1))
|
|
self.assertTrue(dt.lessThanEqualTo(dt1))
|
|
self.assertTrue(dt.notEqualTo(dt1))
|
|
self.assertFalse(dt.equalTo(dt1))
|
|
|
|
def test_compare_methods_none(self):
|
|
# Compare a date to None
|
|
dt = DateTime('1997/1/1')
|
|
self.assertTrue(dt.greaterThan(None))
|
|
self.assertTrue(dt.greaterThanEqualTo(None))
|
|
self.assertFalse(dt.lessThan(None))
|
|
self.assertFalse(dt.lessThanEqualTo(None))
|
|
self.assertTrue(dt.notEqualTo(None))
|
|
self.assertFalse(dt.equalTo(None))
|
|
|
|
def test_pickle(self):
|
|
dt = DateTime()
|
|
data = pickle.dumps(dt, 1)
|
|
new = pickle.loads(data)
|
|
for key in DateTime.__slots__:
|
|
self.assertEqual(getattr(dt, key), getattr(new, key))
|
|
|
|
def test_pickle_with_tz(self):
|
|
dt = DateTime('2002/5/2 8:00am GMT+8')
|
|
data = pickle.dumps(dt, 1)
|
|
new = pickle.loads(data)
|
|
for key in DateTime.__slots__:
|
|
self.assertEqual(getattr(dt, key), getattr(new, key))
|
|
|
|
def test_pickle_with_numerical_tz(self):
|
|
for dt_str in ('2007/01/02 12:34:56.789 +0300',
|
|
'2007/01/02 12:34:56.789 +0430',
|
|
'2007/01/02 12:34:56.789 -1234'):
|
|
dt = DateTime(dt_str)
|
|
data = pickle.dumps(dt, 1)
|
|
new = pickle.loads(data)
|
|
for key in DateTime.__slots__:
|
|
self.assertEqual(getattr(dt, key), getattr(new, key))
|
|
|
|
def test_pickle_with_micros(self):
|
|
dt = DateTime('2002/5/2 8:00:14.123 GMT+8')
|
|
data = pickle.dumps(dt, 1)
|
|
new = pickle.loads(data)
|
|
for key in DateTime.__slots__:
|
|
self.assertEqual(getattr(dt, key), getattr(new, key))
|
|
|
|
def test_pickle_old(self):
|
|
dt = DateTime('2002/5/2 8:00am GMT+0')
|
|
data = ('(cDateTime.DateTime\nDateTime\nq\x01Noq\x02}q\x03(U\x05'
|
|
'_amonq\x04U\x03Mayq\x05U\x05_adayq\x06U\x03Thuq\x07U\x05_pmonq'
|
|
'\x08h\x05U\x05_hourq\tK\x08U\x05_fmonq\nh\x05U\x05_pdayq\x0bU'
|
|
'\x04Thu.q\x0cU\x05_fdayq\rU\x08Thursdayq\x0eU\x03_pmq\x0fU\x02amq'
|
|
'\x10U\x02_tq\x11GA\xcehy\x00\x00\x00\x00U\x07_minuteq\x12K\x00U'
|
|
'\x07_microsq\x13L1020326400000000L\nU\x02_dq\x14G@\xe2\x12j\xaa'
|
|
'\xaa\xaa\xabU\x07_secondq\x15G\x00\x00\x00\x00\x00\x00\x00\x00U'
|
|
'\x03_tzq\x16U\x05GMT+0q\x17U\x06_monthq\x18K\x05U'
|
|
'\x0f_timezone_naiveq\x19I00\nU\x04_dayq\x1aK\x02U\x05_yearq'
|
|
'\x1bM\xd2\x07U\x08_nearsecq\x1cG\x00\x00\x00\x00\x00\x00\x00'
|
|
'\x00U\x07_pmhourq\x1dK\x08U\n_dayoffsetq\x1eK\x04U\x04timeq'
|
|
'\x1fG?\xd5UUUV\x00\x00ub.')
|
|
if PY3K:
|
|
data = data.encode('latin-1')
|
|
new = pickle.loads(data)
|
|
for key in DateTime.__slots__:
|
|
self.assertEqual(getattr(dt, key), getattr(new, key))
|
|
|
|
def test_pickle_old_without_micros(self):
|
|
dt = DateTime('2002/5/2 8:00am GMT+0')
|
|
data = ('(cDateTime.DateTime\nDateTime\nq\x01Noq\x02}q\x03(U\x05'
|
|
'_amonq\x04U\x03Mayq\x05U\x05_adayq\x06U\x03Thuq\x07U\x05_pmonq'
|
|
'\x08h\x05U\x05_hourq\tK\x08U\x05_fmonq\nh\x05U\x05_pdayq\x0bU'
|
|
'\x04Thu.q\x0cU\x05_fdayq\rU\x08Thursdayq\x0eU\x03_pmq\x0fU'
|
|
'\x02amq\x10U\x02_tq\x11GA\xcehy\x00\x00\x00\x00U\x07_minuteq'
|
|
'\x12K\x00U\x02_dq\x13G@\xe2\x12j\xaa\xaa\xaa\xabU\x07_secondq'
|
|
'\x14G\x00\x00\x00\x00\x00\x00\x00\x00U\x03_tzq\x15U\x05GMT+0q'
|
|
'\x16U\x06_monthq\x17K\x05U\x0f_timezone_naiveq\x18I00\nU'
|
|
'\x04_dayq\x19K\x02U\x05_yearq\x1aM\xd2\x07U\x08_nearsecq'
|
|
'\x1bG\x00\x00\x00\x00\x00\x00\x00\x00U\x07_pmhourq\x1cK\x08U'
|
|
'\n_dayoffsetq\x1dK\x04U\x04timeq\x1eG?\xd5UUUV\x00\x00ub.')
|
|
if PY3K:
|
|
data = data.encode('latin-1')
|
|
new = pickle.loads(data)
|
|
for key in DateTime.__slots__:
|
|
self.assertEqual(getattr(dt, key), getattr(new, key))
|
|
|
|
def testTZ2(self):
|
|
# Time zone manipulation test 2
|
|
dt = DateTime()
|
|
dt1 = dt.toZone('GMT')
|
|
s = dt.second()
|
|
s1 = dt1.second()
|
|
self.assertEqual(s, s1, (dt, dt1, s, s1))
|
|
|
|
def testTZDiffDaylight(self):
|
|
# Diff dates across daylight savings dates
|
|
dt = DateTime('2000/6/8 1:45am US/Eastern')
|
|
dt1 = DateTime('2000/12/8 12:45am US/Eastern')
|
|
self.assertEqual(dt1 - dt, 183, (dt, dt1, dt1 - dt))
|
|
|
|
def testY10KDate(self):
|
|
# Comparison of a Y10K date and a Y2K date
|
|
dt = DateTime('10213/09/21')
|
|
dt1 = DateTime(2000, 1, 1)
|
|
|
|
dsec = (dt.millis() - dt1.millis()) / 1000.0
|
|
ddays = math.floor((dsec / 86400.0) + 0.5)
|
|
|
|
self.assertEqual(ddays, 3000000, ddays)
|
|
|
|
def test_tzoffset(self):
|
|
# Test time-zone given as an offset
|
|
|
|
# GMT
|
|
dt = DateTime('Tue, 10 Sep 2001 09:41:03 GMT')
|
|
self.assertEqual(dt.tzoffset(), 0)
|
|
|
|
# Timezone by name, a timezone that hasn't got daylightsaving.
|
|
dt = DateTime('Tue, 2 Mar 2001 09:41:03 GMT+3')
|
|
self.assertEqual(dt.tzoffset(), 10800)
|
|
|
|
# Timezone by name, has daylightsaving but is not in effect.
|
|
dt = DateTime('Tue, 21 Jan 2001 09:41:03 PST')
|
|
self.assertEqual(dt.tzoffset(), -28800)
|
|
|
|
# Timezone by name, with daylightsaving in effect
|
|
dt = DateTime('Tue, 24 Aug 2001 09:41:03 PST')
|
|
self.assertEqual(dt.tzoffset(), -25200)
|
|
|
|
# A negative numerical timezone
|
|
dt = DateTime('Tue, 24 Jul 2001 09:41:03 -0400')
|
|
self.assertEqual(dt.tzoffset(), -14400)
|
|
|
|
# A positive numerical timzone
|
|
dt = DateTime('Tue, 6 Dec 1966 01:41:03 +0200')
|
|
self.assertEqual(dt.tzoffset(), 7200)
|
|
|
|
# A negative numerical timezone with minutes.
|
|
dt = DateTime('Tue, 24 Jul 2001 09:41:03 -0637')
|
|
self.assertEqual(dt.tzoffset(), -23820)
|
|
|
|
# A positive numerical timezone with minutes.
|
|
dt = DateTime('Tue, 24 Jul 2001 09:41:03 +0425')
|
|
self.assertEqual(dt.tzoffset(), 15900)
|
|
|
|
def testISO8601(self):
|
|
# ISO8601 reference dates
|
|
ref0 = DateTime('2002/5/2 8:00am GMT')
|
|
ref1 = DateTime('2002/5/2 8:00am US/Eastern')
|
|
ref2 = DateTime('2006/11/6 10:30 GMT')
|
|
ref3 = DateTime('2004/06/14 14:30:15 GMT-3')
|
|
ref4 = DateTime('2006/01/01 GMT')
|
|
|
|
# Basic tests
|
|
# Though this is timezone naive and according to specification should
|
|
# be interpreted in the local timezone, to preserve backwards
|
|
# compatibility with previously expected behaviour.
|
|
isoDt = DateTime('2002-05-02T08:00:00')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
isoDt = DateTime('2002-05-02T08:00:00Z')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
isoDt = DateTime('2002-05-02T08:00:00+00:00')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
isoDt = DateTime('2002-05-02T08:00:00-04:00')
|
|
self.assertTrue(ref1.equalTo(isoDt))
|
|
isoDt = DateTime('2002-05-02 08:00:00-04:00')
|
|
self.assertTrue(ref1.equalTo(isoDt))
|
|
|
|
# Bug 1386: the colon in the timezone offset is optional
|
|
isoDt = DateTime('2002-05-02T08:00:00-0400')
|
|
self.assertTrue(ref1.equalTo(isoDt))
|
|
|
|
# Bug 2191: date reduced formats
|
|
isoDt = DateTime('2006-01-01')
|
|
self.assertTrue(ref4.equalTo(isoDt))
|
|
isoDt = DateTime('200601-01')
|
|
self.assertTrue(ref4.equalTo(isoDt))
|
|
isoDt = DateTime('20060101')
|
|
self.assertTrue(ref4.equalTo(isoDt))
|
|
isoDt = DateTime('2006-01')
|
|
self.assertTrue(ref4.equalTo(isoDt))
|
|
isoDt = DateTime('200601')
|
|
self.assertTrue(ref4.equalTo(isoDt))
|
|
isoDt = DateTime('2006')
|
|
self.assertTrue(ref4.equalTo(isoDt))
|
|
|
|
# Bug 2191: date/time separators are also optional
|
|
isoDt = DateTime('20020502T08:00:00')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
isoDt = DateTime('2002-05-02T080000')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
isoDt = DateTime('20020502T080000')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
|
|
# Bug 2191: timezones with only one digit for hour
|
|
isoDt = DateTime('20020502T080000+0')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
isoDt = DateTime('20020502 080000-4')
|
|
self.assertTrue(ref1.equalTo(isoDt))
|
|
isoDt = DateTime('20020502T080000-400')
|
|
self.assertTrue(ref1.equalTo(isoDt))
|
|
isoDt = DateTime('20020502T080000-4:00')
|
|
self.assertTrue(ref1.equalTo(isoDt))
|
|
|
|
# Bug 2191: optional seconds/minutes
|
|
isoDt = DateTime('2002-05-02T0800')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
isoDt = DateTime('2002-05-02T08')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
|
|
# Bug 2191: week format
|
|
isoDt = DateTime('2002-W18-4T0800')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
isoDt = DateTime('2002-W184T0800')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
isoDt = DateTime('2002W18-4T0800')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
isoDt = DateTime('2002W184T08')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
isoDt = DateTime('2004-W25-1T14:30:15-03:00')
|
|
self.assertTrue(ref3.equalTo(isoDt))
|
|
isoDt = DateTime('2004-W25T14:30:15-03:00')
|
|
self.assertTrue(ref3.equalTo(isoDt))
|
|
|
|
# Bug 2191: day of year format
|
|
isoDt = DateTime('2002-122T0800')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
isoDt = DateTime('2002122T0800')
|
|
self.assertTrue(ref0.equalTo(isoDt))
|
|
|
|
# Bug 2191: hours/minutes fractions
|
|
isoDt = DateTime('2006-11-06T10.5')
|
|
self.assertTrue(ref2.equalTo(isoDt))
|
|
isoDt = DateTime('2006-11-06T10,5')
|
|
self.assertTrue(ref2.equalTo(isoDt))
|
|
isoDt = DateTime('20040614T1430.25-3')
|
|
self.assertTrue(ref3.equalTo(isoDt))
|
|
isoDt = DateTime('2004-06-14T1430,25-3')
|
|
self.assertTrue(ref3.equalTo(isoDt))
|
|
isoDt = DateTime('2004-06-14T14:30.25-3')
|
|
self.assertTrue(ref3.equalTo(isoDt))
|
|
isoDt = DateTime('20040614T14:30,25-3')
|
|
self.assertTrue(ref3.equalTo(isoDt))
|
|
|
|
# ISO8601 standard format
|
|
iso8601_string = '2002-05-02T08:00:00-04:00'
|
|
iso8601DT = DateTime(iso8601_string)
|
|
self.assertEqual(iso8601_string, iso8601DT.ISO8601())
|
|
|
|
# ISO format with no timezone
|
|
isoDt = DateTime('2006-01-01 00:00:00')
|
|
self.assertTrue(ref4.equalTo(isoDt))
|
|
|
|
def testJulianWeek(self):
|
|
# Check JulianDayWeek function
|
|
fn = os.path.join(DATADIR, 'julian_testdata.txt')
|
|
with open(fn, 'r') as fd:
|
|
lines = fd.readlines()
|
|
for line in lines:
|
|
d = DateTime(line[:10])
|
|
result_from_mx = tuple(map(int, line[12:-2].split(',')))
|
|
self.assertEqual(result_from_mx[1], d.week())
|
|
|
|
def testCopyConstructor(self):
|
|
d = DateTime('2004/04/04')
|
|
self.assertEqual(DateTime(d), d)
|
|
self.assertEqual(str(DateTime(d)), str(d))
|
|
d2 = DateTime('1999/04/12 01:00:00')
|
|
self.assertEqual(DateTime(d2), d2)
|
|
self.assertEqual(str(DateTime(d2)), str(d2))
|
|
|
|
def testCopyConstructorPreservesTimezone(self):
|
|
# test for https://bugs.launchpad.net/zope2/+bug/200007
|
|
# This always worked in the local timezone, so we need at least
|
|
# two tests with different zones to be sure at least one of them
|
|
# is not local.
|
|
d = DateTime('2004/04/04')
|
|
self.assertEqual(DateTime(d).timezone(), d.timezone())
|
|
d2 = DateTime('2008/04/25 12:00:00 EST')
|
|
self.assertEqual(DateTime(d2).timezone(), d2.timezone())
|
|
self.assertEqual(str(DateTime(d2)), str(d2))
|
|
d3 = DateTime('2008/04/25 12:00:00 PST')
|
|
self.assertEqual(DateTime(d3).timezone(), d3.timezone())
|
|
self.assertEqual(str(DateTime(d3)), str(d3))
|
|
|
|
def testRFC822(self):
|
|
# rfc822 conversion
|
|
dt = DateTime('2002-05-02T08:00:00+00:00')
|
|
self.assertEqual(dt.rfc822(), 'Thu, 02 May 2002 08:00:00 +0000')
|
|
|
|
dt = DateTime('2002-05-02T08:00:00+02:00')
|
|
self.assertEqual(dt.rfc822(), 'Thu, 02 May 2002 08:00:00 +0200')
|
|
|
|
dt = DateTime('2002-05-02T08:00:00-02:00')
|
|
self.assertEqual(dt.rfc822(), 'Thu, 02 May 2002 08:00:00 -0200')
|
|
|
|
# Checking that conversion from local time is working.
|
|
dt = DateTime()
|
|
dts = dt.rfc822().split(' ')
|
|
times = dts[4].split(':')
|
|
_isDST = time.localtime(time.time())[8]
|
|
if _isDST:
|
|
offset = time.altzone
|
|
else:
|
|
offset = time.timezone
|
|
self.assertEqual(dts[0], dt.aDay() + ',')
|
|
self.assertEqual(int(dts[1]), dt.day())
|
|
self.assertEqual(dts[2], dt.aMonth())
|
|
self.assertEqual(int(dts[3]), dt.year())
|
|
self.assertEqual(int(times[0]), dt.h_24())
|
|
self.assertEqual(int(times[1]), dt.minute())
|
|
self.assertEqual(int(times[2]), int(dt.second()))
|
|
self.assertEqual(dts[5], "%+03d%02d" % divmod((-offset / 60), 60))
|
|
|
|
def testInternationalDateformat(self):
|
|
for year in (1990, 2001, 2020):
|
|
for month in (1, 12):
|
|
for day in (1, 12, 28, 31):
|
|
try:
|
|
d_us = DateTime("%d/%d/%d" % (year, month, day))
|
|
except Exception:
|
|
continue
|
|
|
|
d_int = DateTime("%d.%d.%d" % (day, month, year),
|
|
datefmt="international")
|
|
self.assertEqual(d_us, d_int)
|
|
|
|
d_int = DateTime("%d/%d/%d" % (day, month, year),
|
|
datefmt="international")
|
|
self.assertEqual(d_us, d_int)
|
|
|
|
def test_intl_format_hyphen(self):
|
|
d_jan = DateTime('2011-01-11 GMT')
|
|
d_nov = DateTime('2011-11-01 GMT')
|
|
d_us = DateTime('11-01-2011 GMT')
|
|
d_int = DateTime('11-01-2011 GMT', datefmt="international")
|
|
self.assertNotEqual(d_us, d_int)
|
|
self.assertEqual(d_us, d_nov)
|
|
self.assertEqual(d_int, d_jan)
|
|
|
|
def test_calcTimezoneName(self):
|
|
from DateTime.interfaces import TimeError
|
|
timezone_dependent_epoch = 2177452800
|
|
try:
|
|
DateTime()._calcTimezoneName(timezone_dependent_epoch, 0)
|
|
except TimeError:
|
|
self.fail('Zope Collector issue #484 (negative time bug): '
|
|
'TimeError raised')
|
|
|
|
def testStrftimeTZhandling(self):
|
|
# strftime timezone testing
|
|
# This is a test for collector issue #1127
|
|
format = '%Y-%m-%d %H:%M %Z'
|
|
dt = DateTime('Wed, 19 Nov 2003 18:32:07 -0215')
|
|
dt_string = dt.strftime(format)
|
|
dt_local = dt.toZone(_findLocalTimeZoneName(0))
|
|
dt_localstring = dt_local.strftime(format)
|
|
self.assertEqual(dt_string, dt_localstring)
|
|
|
|
def testStrftimeFarDates(self):
|
|
# Checks strftime in dates <= 1900 or >= 2038
|
|
dt = DateTime('1900/01/30')
|
|
self.assertEqual(dt.strftime('%d/%m/%Y'), '30/01/1900')
|
|
dt = DateTime('2040/01/30')
|
|
self.assertEqual(dt.strftime('%d/%m/%Y'), '30/01/2040')
|
|
|
|
def testZoneInFarDates(self):
|
|
# Checks time zone in dates <= 1900 or >= 2038
|
|
dt1 = DateTime('2040/01/30 14:33 GMT+1')
|
|
dt2 = DateTime('2040/01/30 11:33 GMT-2')
|
|
self.assertEqual(dt1.strftime('%d/%m/%Y %H:%M'),
|
|
dt2.strftime('%d/%m/%Y %H:%M'))
|
|
|
|
def testStrftimeUnicode(self):
|
|
if IS_PYPY:
|
|
# Using Non-Ascii characters for strftime doesn't work in PyPy
|
|
# https://bitbucket.org/pypy/pypy/issues/2161/pypy3-strftime-does-not-accept-unicode
|
|
return
|
|
dt = DateTime('2002-05-02T08:00:00+00:00')
|
|
uchar = b'\xc3\xa0'.decode('utf-8')
|
|
ok = dt.strftime('Le %d/%m/%Y a %Hh%M').replace('a', uchar)
|
|
ustr = b'Le %d/%m/%Y \xc3\xa0 %Hh%M'.decode('utf-8')
|
|
self.assertEqual(dt.strftime(ustr), ok)
|
|
|
|
def testTimezoneNaiveHandling(self):
|
|
# checks that we assign timezone naivity correctly
|
|
dt = DateTime('2007-10-04T08:00:00+00:00')
|
|
self.assertFalse(dt.timezoneNaive(),
|
|
'error with naivity handling in __parse_iso8601')
|
|
dt = DateTime('2007-10-04T08:00:00Z')
|
|
self.assertFalse(dt.timezoneNaive(),
|
|
'error with naivity handling in __parse_iso8601')
|
|
dt = DateTime('2007-10-04T08:00:00')
|
|
self.assertTrue(dt.timezoneNaive(),
|
|
'error with naivity handling in __parse_iso8601')
|
|
dt = DateTime('2007/10/04 15:12:33.487618 GMT+1')
|
|
self.assertFalse(dt.timezoneNaive(),
|
|
'error with naivity handling in _parse')
|
|
dt = DateTime('2007/10/04 15:12:33.487618')
|
|
self.assertTrue(dt.timezoneNaive(),
|
|
'error with naivity handling in _parse')
|
|
dt = DateTime()
|
|
self.assertFalse(dt.timezoneNaive(),
|
|
'error with naivity for current time')
|
|
s = '2007-10-04T08:00:00'
|
|
dt = DateTime(s)
|
|
self.assertEqual(s, dt.ISO8601())
|
|
s = '2007-10-04T08:00:00+00:00'
|
|
dt = DateTime(s)
|
|
self.assertEqual(s, dt.ISO8601())
|
|
|
|
def testConversions(self):
|
|
sdt0 = datetime.now() # this is a timezone naive datetime
|
|
dt0 = DateTime(sdt0)
|
|
self.assertTrue(dt0.timezoneNaive(), (sdt0, dt0))
|
|
sdt1 = datetime(2007, 10, 4, 18, 14, 42, 580, pytz.utc)
|
|
dt1 = DateTime(sdt1)
|
|
self.assertFalse(dt1.timezoneNaive(), (sdt1, dt1))
|
|
|
|
# convert back
|
|
sdt2 = dt0.asdatetime()
|
|
self.assertEqual(sdt0, sdt2)
|
|
sdt3 = dt1.utcdatetime() # this returns a timezone naive datetime
|
|
self.assertEqual(sdt1.hour, sdt3.hour)
|
|
|
|
dt4 = DateTime('2007-10-04T10:00:00+05:00')
|
|
sdt4 = datetime(2007, 10, 4, 5, 0)
|
|
self.assertEqual(dt4.utcdatetime(), sdt4)
|
|
self.assertEqual(dt4.asdatetime(), sdt4.replace(tzinfo=pytz.utc))
|
|
|
|
dt5 = DateTime('2007-10-23 10:00:00 US/Eastern')
|
|
tz = pytz.timezone('US/Eastern')
|
|
sdt5 = datetime(2007, 10, 23, 10, 0, tzinfo=tz)
|
|
dt6 = DateTime(sdt5)
|
|
self.assertEqual(dt5.asdatetime(), sdt5)
|
|
self.assertEqual(dt6.asdatetime(), sdt5)
|
|
self.assertEqual(dt5, dt6)
|
|
self.assertEqual(dt5.asdatetime().tzinfo, tz)
|
|
self.assertEqual(dt6.asdatetime().tzinfo, tz)
|
|
|
|
def testBasicTZ(self):
|
|
# psycopg2 supplies it's own tzinfo instances, with no `zone` attribute
|
|
tz = FixedOffset(60, 'GMT+1')
|
|
dt1 = datetime(2008, 8, 5, 12, 0, tzinfo=tz)
|
|
DT = DateTime(dt1)
|
|
dt2 = DT.asdatetime()
|
|
offset1 = dt1.tzinfo.utcoffset(dt1)
|
|
offset2 = dt2.tzinfo.utcoffset(dt2)
|
|
self.assertEqual(offset1, offset2)
|
|
|
|
def testEDTTimezone(self):
|
|
# should be able to parse EDT timezones: see lp:599856.
|
|
dt = DateTime("Mon, 28 Jun 2010 10:12:25 EDT")
|
|
self.assertEqual(dt.Day(), 'Monday')
|
|
self.assertEqual(dt.day(), 28)
|
|
self.assertEqual(dt.Month(), 'June')
|
|
self.assertEqual(dt.timezone(), 'GMT-4')
|
|
|
|
def testParseISO8601(self):
|
|
parsed = DateTime()._parse_iso8601('2010-10-10')
|
|
self.assertEqual(parsed, (2010, 10, 10, 0, 0, 0, 'GMT+0000'))
|
|
|
|
def test_interface(self):
|
|
from DateTime.interfaces import IDateTime
|
|
self.assertTrue(IDateTime.providedBy(DateTime()))
|
|
|
|
def test_security(self):
|
|
dt = DateTime()
|
|
self.assertEqual(dt.__roles__, None)
|
|
self.assertEqual(dt.__allow_access_to_unprotected_subobjects__, 1)
|
|
|
|
|
|
def test_suite():
|
|
import doctest
|
|
return unittest.TestSuite([
|
|
unittest.makeSuite(DateTimeTests),
|
|
doctest.DocFileSuite('DateTime.txt', package='DateTime'),
|
|
doctest.DocFileSuite('pytz.txt', package='DateTime'),
|
|
])
|