summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2016-04-20 09:00:25 +0200
committerSebastian Thiel <byronimo@gmail.com>2016-04-20 09:00:25 +0200
commitd04aeaa17e628f13d1a590a32ae96bc7d35775b5 (patch)
tree36ea8e5dd06b5e8c671e39a2185675042787ef38
parentfcb6e8832a94776d670095935a7da579a111c028 (diff)
parentf77f9775277a100c7809698c75cb0855b07b884d (diff)
downloadgitpython-d04aeaa17e628f13d1a590a32ae96bc7d35775b5.tar.gz
Merge pull request #414 from nvie/support-full-datetimes-on-commits
Add support for getting "aware" datetime info
-rw-r--r--git/objects/commit.py11
-rw-r--r--git/objects/util.py30
-rw-r--r--git/test/test_commit.py11
3 files changed, 50 insertions, 2 deletions
diff --git a/git/objects/commit.py b/git/objects/commit.py
index d067b718..dc722f97 100644
--- a/git/objects/commit.py
+++ b/git/objects/commit.py
@@ -21,7 +21,8 @@ from .util import (
Serializable,
parse_date,
altz_to_utctz_str,
- parse_actor_and_date
+ parse_actor_and_date,
+ from_timestamp,
)
from git.compat import text_type
@@ -145,6 +146,14 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
# END handle attrs
@property
+ def authored_datetime(self):
+ return from_timestamp(self.authored_date, self.author_tz_offset)
+
+ @property
+ def committed_datetime(self):
+ return from_timestamp(self.committed_date, self.committer_tz_offset)
+
+ @property
def summary(self):
""":return: First line of the commit message"""
return self.message.split('\n', 1)[0]
diff --git a/git/objects/util.py b/git/objects/util.py
index 8fd92a0a..cbb9fe3c 100644
--- a/git/objects/util.py
+++ b/git/objects/util.py
@@ -15,10 +15,13 @@ from collections import deque as Deque
from string import digits
import time
import calendar
+from datetime import datetime, timedelta, tzinfo
__all__ = ('get_object_type_by_name', 'parse_date', 'parse_actor_and_date',
'ProcessStreamAdapter', 'Traversable', 'altz_to_utctz_str', 'utctz_to_altz',
- 'verify_utctz', 'Actor')
+ 'verify_utctz', 'Actor', 'tzoffset', 'utc')
+
+ZERO = timedelta(0)
#{ Functions
@@ -97,6 +100,31 @@ def verify_utctz(offset):
return offset
+class tzoffset(tzinfo):
+ def __init__(self, secs_west_of_utc, name=None):
+ self._offset = timedelta(seconds=-secs_west_of_utc)
+ self._name = name or 'fixed'
+
+ def utcoffset(self, dt):
+ return self._offset
+
+ def tzname(self, dt):
+ return self._name
+
+ def dst(self, dt):
+ return ZERO
+
+
+utc = tzoffset(0, 'UTC')
+
+
+def from_timestamp(timestamp, tz_offset):
+ """Converts a timestamp + tz_offset into an aware datetime instance."""
+ utc_dt = datetime.fromtimestamp(timestamp, utc)
+ local_dt = utc_dt.astimezone(tzoffset(tz_offset))
+ return local_dt
+
+
def parse_date(string_date):
"""
Parse the given date as one of the following
diff --git a/git/test/test_commit.py b/git/test/test_commit.py
index 3e958edf..23b7154a 100644
--- a/git/test/test_commit.py
+++ b/git/test/test_commit.py
@@ -32,6 +32,8 @@ import time
import sys
import re
import os
+from datetime import datetime
+from git.objects.util import tzoffset, utc
def assert_commit_serialization(rwrepo, commit_id, print_performance_info=False):
@@ -343,3 +345,12 @@ JzJMZDRLQLFvnzqZuCjE
cstream = BytesIO()
cmt._serialize(cstream)
assert not re.search(r"^gpgsig ", cstream.getvalue().decode('ascii'), re.MULTILINE)
+
+ def test_datetimes(self):
+ commit = self.rorepo.commit('4251bd5')
+ assert commit.authored_date == 1255018625
+ assert commit.committed_date == 1255026171
+ assert commit.authored_datetime == datetime(2009, 10, 8, 18, 17, 5, tzinfo=tzoffset(-7200)), commit.authored_datetime # noqa
+ assert commit.authored_datetime == datetime(2009, 10, 8, 16, 17, 5, tzinfo=utc), commit.authored_datetime
+ assert commit.committed_datetime == datetime(2009, 10, 8, 20, 22, 51, tzinfo=tzoffset(-7200))
+ assert commit.committed_datetime == datetime(2009, 10, 8, 18, 22, 51, tzinfo=utc), commit.committed_datetime