aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier Tilloy <olivier@tilloy.net>2011-08-03 08:57:19 +0200
committerOlivier Tilloy <olivier@tilloy.net>2011-08-03 08:57:19 +0200
commit5d6fc27aa0dee1d9793b027a1215cc4c124cc7c9 (patch)
tree8d92a703a619824b51a4e3f22e698e7b91247088
parentf8122b779610113b3c568ca9320dedf682c109a6 (diff)
parent3436574cc3cfa3a19931ae87a3d5cd160462ac51 (diff)
downloadpyexiv2-5d6fc27aa0dee1d9793b027a1215cc4c124cc7c9.tar.gz
Fix timezone formatting when writing IPTC and XMP tags.
This introduces an optional dependency on python-tz in unit tests. Original patch by Petri Damstén, thanks Petri!
-rw-r--r--doc/developers.rst5
-rw-r--r--src/pyexiv2/iptc.py6
-rw-r--r--src/pyexiv2/xmp.py13
-rw-r--r--test/iptc.py15
-rw-r--r--test/xmp.py21
5 files changed, 53 insertions, 7 deletions
diff --git a/doc/developers.rst b/doc/developers.rst
index 03131a6..c6eb15c 100644
--- a/doc/developers.rst
+++ b/doc/developers.rst
@@ -52,6 +52,11 @@ A typical list of packages to install on a Debian/Ubuntu system is::
python-all-dev libboost-python-dev libexiv2-dev scons
+Some unit tests have a dependency on
+`python-tz <http://pytz.sourceforge.net/>`_.
+This dependency is optional: the corresponding tests will be skipped if it is
+not present on the system.
+
Additionally, if you want to cross-compile pyexiv2 for Windows and generate a
Windows installer, you will need the following dependencies:
diff --git a/src/pyexiv2/iptc.py b/src/pyexiv2/iptc.py
index 7a768fd..f2a360d 100644
--- a/src/pyexiv2/iptc.py
+++ b/src/pyexiv2/iptc.py
@@ -351,9 +351,9 @@ class IptcTag(ListenerInterface):
# string expected by exiv2's TimeValue::read(string) should be
# formatted using pattern '%H:%M:%S±%H:%M'.
r = value.strftime('%H:%M:%S')
- if value.tzinfo is not None and \
- not (value.tzinfo.hours == 0 and value.tzinfo.minutes == 0):
- r += value.strftime('%Z')
+ if value.tzinfo is not None:
+ s = value.strftime('%z') # of the form ±%H%M
+ r += s[:3] + ':' + s[3:]
else:
r += '+00:00'
return r
diff --git a/src/pyexiv2/xmp.py b/src/pyexiv2/xmp.py
index 469af98..7240527 100644
--- a/src/pyexiv2/xmp.py
+++ b/src/pyexiv2/xmp.py
@@ -388,18 +388,23 @@ class XmpTag(object):
elif type == 'Date':
if isinstance(value, datetime.datetime):
+ if value.tzinfo is None or value.utcoffset() == datetime.timedelta(0):
+ tz = 'Z'
+ else:
+ tz = value.strftime('%z') # of the form ±%H%M
+ tz = tz[:3] + ':' + tz[3:]
if value.hour == 0 and value.minute == 0 and \
value.second == 0 and value.microsecond == 0 and \
- (value.tzinfo is None or value.tzinfo == FixedOffset()):
+ (value.tzinfo is None or value.utcoffset() == datetime.timedelta(0)):
return value.strftime('%Y-%m-%d')
elif value.second == 0 and value.microsecond == 0:
- return value.strftime('%Y-%m-%dT%H:%M%Z')
+ return value.strftime('%Y-%m-%dT%H:%M') + tz
elif value.microsecond == 0:
- return value.strftime('%Y-%m-%dT%H:%M:%S%Z')
+ return value.strftime('%Y-%m-%dT%H:%M:%S') + tz
else:
r = value.strftime('%Y-%m-%dT%H:%M:%S.')
r += str(int(value.microsecond) / 1E6)[2:]
- r += value.strftime('%Z')
+ r += tz
return r
elif isinstance(value, datetime.date):
return value.isoformat()
diff --git a/test/iptc.py b/test/iptc.py
index 9cf198e..ec631cb 100644
--- a/test/iptc.py
+++ b/test/iptc.py
@@ -32,6 +32,12 @@ from pyexiv2.utils import FixedOffset
import datetime
import warnings
+# Optional dependency on python-tz, more tests can be run if it is installed
+try:
+ import pytz
+except ImportError:
+ pytz = None
+
class TestIptcTag(unittest.TestCase):
@@ -160,6 +166,15 @@ class TestIptcTag(unittest.TestCase):
# Invalid values
self.failUnlessRaises(IptcValueError, tag._convert_to_string, 'invalid')
+ @unittest.skipIf(pytz is None, 'install python-tz to run this test')
+ def test_convert_to_string_time_with_real_timezones(self):
+ tag = IptcTag('Iptc.Envelope.TimeSent')
+ self.assertEqual(tag.type, 'Time')
+ t = pytz.timezone('UTC').localize(datetime.datetime(2011, 2, 2, 10, 52, 4))
+ self.assertEqual(tag._convert_to_string(t), '10:52:04+00:00')
+ t = pytz.timezone('CET').localize(datetime.datetime(2011, 2, 2, 10, 52, 4))
+ self.assertEqual(tag._convert_to_string(t), '10:52:04+01:00')
+
def test_convert_to_python_undefined(self):
# Valid values
tag = IptcTag('Iptc.Application2.Preview')
diff --git a/test/xmp.py b/test/xmp.py
index f3fa4c3..532f1e2 100644
--- a/test/xmp.py
+++ b/test/xmp.py
@@ -34,6 +34,12 @@ from pyexiv2.metadata import ImageMetadata
import datetime
from testutils import EMPTY_JPG_DATA
+# Optional dependency on python-tz, more tests can be run if it is installed
+try:
+ import pytz
+except ImportError:
+ pytz = None
+
class TestXmpTag(unittest.TestCase):
@@ -130,18 +136,24 @@ class TestXmpTag(unittest.TestCase):
'2009-02-04')
self.assertEqual(tag._convert_to_string(datetime.datetime(1999, 10, 13), 'Date'),
'1999-10-13')
+ self.assertEqual(tag._convert_to_string(datetime.datetime(1999, 10, 13, 5, 3), 'Date'),
+ '1999-10-13T05:03Z')
self.assertEqual(tag._convert_to_string(datetime.datetime(1999, 10, 13, 5, 3, tzinfo=FixedOffset()), 'Date'),
'1999-10-13T05:03Z')
self.assertEqual(tag._convert_to_string(datetime.datetime(1999, 10, 13, 5, 3, tzinfo=FixedOffset('+', 5, 30)), 'Date'),
'1999-10-13T05:03+05:30')
self.assertEqual(tag._convert_to_string(datetime.datetime(1999, 10, 13, 5, 3, tzinfo=FixedOffset('-', 11, 30)), 'Date'),
'1999-10-13T05:03-11:30')
+ self.assertEqual(tag._convert_to_string(datetime.datetime(1999, 10, 13, 5, 3, 27), 'Date'),
+ '1999-10-13T05:03:27Z')
self.assertEqual(tag._convert_to_string(datetime.datetime(1999, 10, 13, 5, 3, 27, tzinfo=FixedOffset()), 'Date'),
'1999-10-13T05:03:27Z')
self.assertEqual(tag._convert_to_string(datetime.datetime(1999, 10, 13, 5, 3, 27, tzinfo=FixedOffset('+', 5, 30)), 'Date'),
'1999-10-13T05:03:27+05:30')
self.assertEqual(tag._convert_to_string(datetime.datetime(1999, 10, 13, 5, 3, 27, tzinfo=FixedOffset('-', 11, 30)), 'Date'),
'1999-10-13T05:03:27-11:30')
+ self.assertEqual(tag._convert_to_string(datetime.datetime(1999, 10, 13, 5, 3, 27, 124300), 'Date'),
+ '1999-10-13T05:03:27.1243Z')
self.assertEqual(tag._convert_to_string(datetime.datetime(1999, 10, 13, 5, 3, 27, 124300, tzinfo=FixedOffset()), 'Date'),
'1999-10-13T05:03:27.1243Z')
self.assertEqual(tag._convert_to_string(datetime.datetime(1999, 10, 13, 5, 3, 27, 124300, tzinfo=FixedOffset('+', 5, 30)), 'Date'),
@@ -152,6 +164,15 @@ class TestXmpTag(unittest.TestCase):
self.failUnlessRaises(XmpValueError, tag._convert_to_string, 'invalid', 'Date')
self.failUnlessRaises(XmpValueError, tag._convert_to_string, None, 'Date')
+ @unittest.skipIf(pytz is None, 'install python-tz to run this test')
+ def test_convert_to_string_date_with_real_timezones(self):
+ tag = XmpTag('Xmp.xmp.CreateDate')
+ self.assertEqual(tag.type, 'Date')
+ t = pytz.timezone('UTC').localize(datetime.datetime(2011, 2, 2, 10, 52, 4))
+ self.assertEqual(tag._convert_to_string(t, 'Date'), '2011-02-02T10:52:04Z')
+ t = pytz.timezone('CET').localize(datetime.datetime(2011, 2, 2, 10, 52, 4))
+ self.assertEqual(tag._convert_to_string(t, 'Date'), '2011-02-02T10:52:04+01:00')
+
def test_convert_to_python_integer(self):
# Valid values
tag = XmpTag('Xmp.xmpMM.SaveID')