Ticket #4547: datefmt-r5696.diff
| File datefmt-r5696.diff, 8.8 KB (added by cboos, 5 years ago) |
|---|
-
trac/util/tests/datefmt.py
17 17 import datetime 18 18 import unittest 19 19 20 from trac.util .datefmt import get_timezone20 from trac.util import datefmt 21 21 22 22 try: 23 23 import pytz … … 26 26 else: 27 27 class PytzTestCase(unittest.TestCase): 28 28 def test_pytz_conversion(self): 29 tz = get_timezone('GMT +3:00')29 tz = datefmt.get_timezone('GMT +3:00') 30 30 self.assertEqual(datetime.timedelta(hours=3), 31 31 tz.utcoffset(None)) 32 32 33 33 def test_posix_conversion(self): 34 tz = get_timezone('Etc/GMT-4')34 tz = datefmt.get_timezone('Etc/GMT-4') 35 35 self.assertEqual(datetime.timedelta(hours=4), 36 36 tz.utcoffset(None)) 37 37 self.assertEqual('GMT +4:00', tz.zone) 38 38 39 39 def test_unicode_input(self): 40 tz = get_timezone(u'Etc/GMT-4')40 tz = datefmt.get_timezone(u'Etc/GMT-4') 41 41 self.assertEqual(datetime.timedelta(hours=4), 42 42 tz.utcoffset(None)) 43 43 self.assertEqual('GMT +4:00', tz.zone) 44 44 45 class DateFormatTestCase(unittest.TestCase): 46 47 def test_to_datetime(self): 48 expected = datetime.datetime(1970,1,1,1,0,23,0,datefmt.localtz) 49 self.assertEqual(datefmt.to_datetime(23), expected) 50 self.assertEqual(datefmt.to_datetime(23L), expected) 51 self.assertEqual(datefmt.to_datetime(23.0), expected) 52 53 def test_to_datetime_tz(self): 54 tz = datefmt.timezone('GMT +1:00') 55 expected = datetime.datetime(1970,1,1,1,0,23,0,tz) 56 self.assertEqual(datefmt.to_datetime(23, tz), expected) 57 self.assertEqual(datefmt.to_datetime(23L, tz), expected) 58 self.assertEqual(datefmt.to_datetime(23.0, tz), expected) 59 60 def test_format_datetime(self): 61 t = datetime.datetime(1970,1,1,1,0,23,0,datefmt.utc) 62 expected = '1970-01-01T01:00:23Z+0000' 63 self.assertEqual(datefmt.format_datetime(t, '%Y-%m-%dT%H:%M:%SZ%z', 64 datefmt.utc), expected) 65 self.assertEqual(datefmt.format_datetime(t, 'iso8601', 66 datefmt.utc), expected) 67 68 def test_format_datetime(self): 69 t = datetime.datetime(1970,1,1,1,0,23,0,datefmt.utc) 70 expected = '1970-01-01T01:00:23Z+0000' 71 self.assertEqual(datefmt.format_datetime(t, '%Y-%m-%dT%H:%M:%SZ%z', 72 datefmt.utc), expected) 73 self.assertEqual(datefmt.format_datetime(t, 'iso8601', 74 datefmt.utc), expected) 75 76 45 77 def suite(): 46 78 suite = unittest.TestSuite() 47 79 if PytzTestCase: 48 80 suite.addTest(unittest.makeSuite(PytzTestCase, 'test')) 49 81 else: 50 82 print "SKIP: utils/tests/datefmt.py (no pytz installed)" 83 suite.addTest(unittest.makeSuite(DateFormatTestCase)) 51 84 return suite 52 85 53 86 if __name__ == '__main__': -
trac/util/datefmt.py
28 28 29 29 # Date/time utilities 30 30 31 # -- conversion 32 33 def to_datetime(t, tzinfo=None): 34 """Convert `t` into a `datetime` object, using the following rules: 35 36 - If `t` is already a `datetime` object, it is simply returned. 37 - If `t` is None, the current time will be used. 38 - If `t` is a number, it is interpreted as a timestamp. If no `tzinfo` 39 is given, the local timezone will be used for the conversion. 40 41 Any other input will trigger a `TypeError`. 42 """ 43 if t is None: 44 return datetime.now(localtz) 45 elif isinstance(t, datetime): 46 return t 47 elif isinstance(t, (int,long,float)): 48 return datetime.fromtimestamp(t, tzinfo or localtz) 49 raise TypeError('expecting datetime, int, long, float, or None; got %s' % 50 type(t)) 51 52 def to_timestamp(dt): 53 """Return the corresponding POSIX timestamp""" 54 if dt: 55 diff = dt - _epoc 56 return diff.days * 86400 + diff.seconds 57 else: 58 return 0 59 60 61 # -- formatting 62 31 63 def pretty_timedelta(time1, time2=None, resolution=None): 32 """Calculate time delta (inaccurately, only for decorative purposes ;-) for 33 prettyprinting. If time1 is None, the current time is used.""" 34 if not time1: time1 = datetime.now(utc) 35 if not time2: time2 = datetime.now(utc) 64 """Calculate time delta between two `datetime` objects. 65 (the result is somewhat imprecise, only use for prettyprinting). 66 67 If either `time1` or `time2` is None, the current time will be used 68 instead. 69 """ 70 time1 = to_datetime(time1) 71 time2 = to_datetime(time2) 36 72 if time1 > time2: 37 73 time2, time1 = time1, time2 38 74 units = ((3600 * 24 * 365, 'year', 'years'), … … 53 89 r = int(round(r)) 54 90 return '%d %s' % (r, r == 1 and unit or unit_plural) 55 91 return '' 92 93 def format_datetime(t=None, format='%x %X', tzinfo=None): 94 """Format the `datetime` object `t` into an `unicode` string 56 95 57 def format_datetime(t=None, format='%x %X', tzinfo=None): 58 if not tzinfo: 59 tzinfo = localtz 60 if t is None: 61 t = datetime.now(utc) 62 if isinstance(t, (int,long)): 63 t = datetime.fromtimestamp(t, tzinfo) 96 If `t` is None, the current time will be used. 97 98 The formatting will be done using the given `format`, which consist 99 of conventional `strftime` keys. In addition the format can be 'iso8601' 100 to specify the international date format. 101 102 `tzinfo` will default to the local timezone if left to `None`. 103 """ 104 t = to_datetime(t, tzinfo).astimezone(tzinfo or localtz) 64 105 if format.lower() == 'iso8601': 65 106 format = '%Y-%m-%dT%H:%M:%SZ%z' 66 t = t.astimezone(tzinfo)67 107 text = t.strftime(format) 68 108 encoding = locale.getpreferredencoding() or sys.getdefaultencoding() 69 109 if sys.platform != 'win32': … … 72 112 return unicode(text, encoding, 'replace') 73 113 74 114 def format_date(t=None, format='%x', tzinfo=None): 115 """Convenience method for formatting the date part of a `datetime` object. 116 See `format_datetime` for more details. 117 """ 75 118 if format == 'iso8601': 76 119 format = '%Y-%m-%d' 77 120 return format_datetime(t, format, tzinfo=tzinfo) 78 121 79 122 def format_time(t=None, format='%X', tzinfo=None): 123 """Convenience method for formatting the time part of a `datetime` object. 124 See `format_datetime` for more details. 125 """ 80 126 if format == 'iso8601': 81 127 format = '%H:%M:%SZ%z' 82 128 return format_datetime(t, format, tzinfo=tzinfo) 83 129 84 130 def get_date_format_hint(): 131 """Present the default format used by `format_date` in a human readable 132 form. 133 This is a format that will be recognized by `parse_date` when reading a 134 date. 135 """ 85 136 t = datetime(1999, 10, 29, tzinfo=utc) 86 137 tmpl = format_date(t, tzinfo=utc) 87 138 return tmpl.replace('1999', 'YYYY', 1).replace('99', 'YY', 1) \ 88 139 .replace('10', 'MM', 1).replace('29', 'DD', 1) 89 140 90 141 def get_datetime_format_hint(): 142 """Present the default format used by `format_datetime` in a human readable 143 form. 144 This is a format that will be recognized by `parse_date` when reading a 145 date. 146 """ 91 147 t = datetime(1999, 10, 29, 23, 59, 58, tzinfo=utc) 92 148 tmpl = format_datetime(t, tzinfo=utc) 93 149 return tmpl.replace('1999', 'YYYY', 1).replace('99', 'YY', 1) \ … … 96 152 .replace('59', 'mm', 1).replace('58', 'ss', 1) 97 153 98 154 def http_date(t=None): 99 """Format t as a rfc822 timestamp""" 100 if t is None: 101 t = datetime.now(utc) 102 t = t.astimezone(utc) 155 """Format `datetime` object `t` as a rfc822 timestamp""" 156 t = to_datetime(t).astimezone(utc) 103 157 weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] 104 158 months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 105 159 'Oct', 'Nov', 'Dec'] … … 107 161 weekdays[t.weekday()], t.day, months[t.month - 1], t.year, 108 162 t.hour, t.minute, t.second) 109 163 164 165 # -- parsing 166 110 167 _ISO_8601_RE = re.compile(r'(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d))?)?' # date 111 168 r'(?:T(\d\d)(?::?(\d\d)(?::?(\d\d))?)?)?' # time 112 169 r'(Z(?:([-+])?(\d\d):?(\d\d)?)?)?$' # timezone … … 157 214 'Invalid Date') 158 215 return datetime(*(tm[0:6] + (0, tzinfo))) 159 216 160 def to_timestamp(dt):161 """Return the corresponding POSIX timestamp"""162 if dt:163 diff = dt - _epoc164 return diff.days * 86400 + diff.seconds165 else:166 return 0167 217 218 # -- timezone utilities 168 219 169 220 class FixedOffset(tzinfo): 170 221 """Fixed offset in minutes east from UTC."""
