Rev 2426: Fix formatting of timezones in bundles and merge directives. in http://sourcefrog.net/bzr/gmtime
Martin Pool
mbp at sourcefrog.net
Thu Apr 19 08:17:17 BST 2007
At http://sourcefrog.net/bzr/gmtime
------------------------------------------------------------
revno: 2426
revision-id: mbp at sourcefrog.net-20070419071716-tcuv5i38vhci6fuf
parent: pqm at pqm.ubuntu.com-20070417080415-5vn25svmf95ki88z
committer: Martin Pool <mbp at sourcefrog.net>
branch nick: gmtime
timestamp: Thu 2007-04-19 17:17:16 +1000
message:
Fix formatting of timezones in bundles and merge directives.
Always give epoch time in utc.
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/tests/test_merge_directive.py test_merge_directive-20070228184838-ja62280spt1g7f4x-2
bzrlib/tests/test_timestamp.py test_timestamp.py-20070306153932-r3ejn242c20asagv-1
bzrlib/timestamp.py timestamp.py-20070306142322-ttbb9oulf3jotljd-1
=== modified file 'NEWS'
--- a/NEWS 2007-04-17 07:09:43 +0000
+++ b/NEWS 2007-04-19 07:17:16 +0000
@@ -83,6 +83,12 @@
* FTP now works even when the FTP server does not support atomic rename.
(Aaron Bentley, #89436)
+ * Correct handling in bundles and merge directives of timezones with
+ that are not an integer number of hours offset from UTC. Always
+ represent the epoch time in UTC to avoid problems with formatting
+ earlier times on win32. (Martin Pool, Alexander Belchenko, John
+ Arbash Meinel)
+
TESTING:
* Added ``bzrlib.strace.strace`` which will strace a single callable and
=== modified file 'bzrlib/tests/test_merge_directive.py'
--- a/bzrlib/tests/test_merge_directive.py 2007-04-01 04:06:14 +0000
+++ b/bzrlib/tests/test_merge_directive.py 2007-04-19 07:17:16 +0000
@@ -68,8 +68,8 @@
class TestMergeDirective(tests.TestCase):
def test_merge_source(self):
- time = 500.0
- timezone = 5
+ time = 500000.0
+ timezone = 5 * 3600
self.assertRaises(errors.NoMergeSource, merge_directive.MergeDirective,
'example:', 'sha', time, timezone, 'http://example.com')
self.assertRaises(errors.NoMergeSource, merge_directive.MergeDirective,
@@ -87,7 +87,7 @@
def test_require_patch(self):
time = 500.0
- timezone = 5
+ timezone = 120
self.assertRaises(errors.PatchMissing, merge_directive.MergeDirective,
'example:', 'sha', time, timezone, 'http://example.com',
patch_type='bundle')
@@ -97,8 +97,8 @@
self.assertEqual(md.patch, '')
def test_serialization(self):
- time = 501
- timezone = 72
+ time = 453
+ timezone = 120
md = merge_directive.MergeDirective('example:', 'sha', time, timezone,
'http://example.com', patch='booga', patch_type='bundle')
self.assertEqualDiff(OUTPUT1, ''.join(md.to_lines()))
@@ -108,6 +108,7 @@
self.assertEqualDiff(OUTPUT2, ''.join(md.to_lines()))
def test_deserialize_junk(self):
+ time = 501
self.assertRaises(errors.NotAMergeDirective,
merge_directive.MergeDirective.from_lines, 'lala')
@@ -121,15 +122,15 @@
self.assertEqual('sha', md.testament_sha1)
self.assertEqual('http://example.com', md.target_branch)
self.assertEqual('http://example.org', md.source_branch)
- self.assertEqual(501, md.time)
- self.assertEqual(72, md.timezone)
+ self.assertEqual(453, md.time)
+ self.assertEqual(120, md.timezone)
self.assertEqual('booga', md.patch)
self.assertEqual('diff', md.patch_type)
self.assertEqual('Hi mom!', md.message)
def test_roundtrip(self):
- time = 501
- timezone = 72
+ time = 500000
+ timezone = 7.5 * 3600
md = merge_directive.MergeDirective('example:', 'sha', time, timezone,
'http://example.com', source_branch="http://example.org",
patch='booga', patch_type='diff')
@@ -204,7 +205,7 @@
def test_generate_patch(self):
tree_a, tree_b, branch_c = self.make_trees()
md2 = merge_directive.MergeDirective.from_objects(
- tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
+ tree_a.branch.repository, 'rev2a', 500, 120, tree_b.branch.base,
patch_type='diff', public_branch=tree_a.branch.base)
self.assertNotContainsRe(md2.patch, 'Bazaar revision bundle')
self.assertContainsRe(md2.patch, '\\+content_c')
@@ -246,7 +247,7 @@
def test_message(self):
tree_a, tree_b, branch_c = self.make_trees()
md3 = merge_directive.MergeDirective.from_objects(
- tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
+ tree_a.branch.repository, 'rev2a', 500, 120, tree_b.branch.base,
patch_type=None, public_branch=branch_c.base,
message='Merge message')
md3.to_lines()
@@ -256,7 +257,7 @@
def test_generate_bundle(self):
tree_a, tree_b, branch_c = self.make_trees()
md1 = merge_directive.MergeDirective.from_objects(
- tree_a.branch.repository, 'rev2a', 500, 144, tree_b.branch.base,
+ tree_a.branch.repository, 'rev2a', 500, 120, tree_b.branch.base,
public_branch=branch_c.base)
self.assertContainsRe(md1.patch, 'Bazaar revision bundle')
self.assertContainsRe(md1.patch, '\\+content_c')
@@ -265,8 +266,8 @@
self.assertNotContainsRe(md1.patch, '\\+content_a')
def test_signing(self):
- time = 501
- timezone = 72
+ time = 453
+ timezone = 7200
class FakeBranch(object):
def get_config(self):
return self
@@ -288,7 +289,7 @@
def test_email(self):
tree_a, tree_b, branch_c = self.make_trees()
md = merge_directive.MergeDirective.from_objects(
- tree_a.branch.repository, 'rev2a', 500, 36, tree_b.branch.base,
+ tree_a.branch.repository, 'rev2a', 476, 60, tree_b.branch.base,
patch_type=None, public_branch=tree_a.branch.base)
message = md.to_email('pqm at example.com', tree_a.branch)
self.assertContainsRe(message.as_string(), EMAIL1)
=== modified file 'bzrlib/tests/test_timestamp.py'
--- a/bzrlib/tests/test_timestamp.py 2007-03-07 20:14:06 +0000
+++ b/bzrlib/tests/test_timestamp.py 2007-04-19 07:17:16 +0000
@@ -22,23 +22,33 @@
class TestPatchHeader(tests.TestCase):
def test_format_patch_date(self):
+ # epoch is always in utc
self.assertEqual('1970-01-01 00:00:00 +0000',
timestamp.format_patch_date(0))
- self.assertEqual('1970-01-01 05:00:00 +0500',
+ self.assertEqual('1970-01-01 00:00:00 +0000',
timestamp.format_patch_date(0, 5 * 3600))
- self.assertEqual('1969-12-31 19:00:00 -0500',
- timestamp.format_patch_date(0, -5 * 3600))
- self.assertEqual('1969-12-31 19:00:00 -0500',
- timestamp.format_patch_date(0, -5 * 3600))
+ self.assertEqual('1970-01-01 00:00:00 +0000',
+ timestamp.format_patch_date(0, -5 * 3600))
+ # regular timestamp with typical timezone
self.assertEqual('2007-03-06 10:04:19 -0500',
timestamp.format_patch_date(1173193459, -5 * 3600))
+ # the timezone part is HHMM
+ self.assertEqual('2007-03-06 09:34:19 -0530',
+ timestamp.format_patch_date(1173193459, -5.5 * 3600))
+ # timezones can be offset by single minutes (but no less)
+ self.assertEqual('2007-03-06 15:05:19 +0001',
+ timestamp.format_patch_date(1173193459, +1 * 60))
def test_parse_patch_date(self):
self.assertEqual((0, 0),
timestamp.parse_patch_date('1970-01-01 00:00:00 +0000'))
+ # even though we don't emit pre-epoch dates, we can parse them
self.assertEqual((0, -5 * 3600),
timestamp.parse_patch_date('1969-12-31 19:00:00 -0500'))
self.assertEqual((0, +5 * 3600),
timestamp.parse_patch_date('1970-01-01 05:00:00 +0500'))
self.assertEqual((1173193459, -5 * 3600),
timestamp.parse_patch_date('2007-03-06 10:04:19 -0500'))
+ # offset of three minutes
+ self.assertEqual((1173193459, +3 * 60),
+ timestamp.parse_patch_date('2007-03-06 15:07:19 +0003'))
=== modified file 'bzrlib/timestamp.py'
--- a/bzrlib/timestamp.py 2007-03-09 22:41:47 +0000
+++ b/bzrlib/timestamp.py 2007-04-19 07:17:16 +0000
@@ -127,10 +127,20 @@
Inverse of parse_patch_date.
"""
- assert offset % 36 == 0
+ assert offset % 60 == 0, \
+ "can't represent timezone %s offset by fractional minutes" % offset
+ # so that we don't need to do calculations on pre-epoch times,
+ # which doesn't work with win32 python gmtime, we always
+ # give the epoch in utc
+ if secs == 0:
+ offset = 0
+ if secs + offset < 0:
+ from warnings import warn
+ warn("gmtime of negative time (%s, %s) may not work on Windows" %
+ (secs, offset))
tm = time.gmtime(secs+offset)
time_str = time.strftime('%Y-%m-%d %H:%M:%S', tm)
- return '%s %+05d' % (time_str, offset/36)
+ return '%s %+03d%02d' % (time_str, offset/3600, abs(offset/60) % 60)
def parse_patch_date(date_str):
@@ -139,8 +149,11 @@
Inverse of format_patch_date.
"""
secs_str = date_str[:-6]
- offset_str = date_str[-6:]
- offset = int(offset_str) * 36
+ offset_str = date_str[-5:]
+ assert len(offset_str) == 5, \
+ "invalid timezone %r" % offset_str
+ offset_hours, offset_mins = offset_str[:3], offset_str[3:]
+ offset = int(offset_hours) * 3600 + int(offset_mins) * 60
tm_time = time.strptime(secs_str, '%Y-%m-%d %H:%M:%S')
# adjust seconds according to offset before converting to POSIX
# timestamp, to avoid edge problems
More information about the bazaar-commits
mailing list