Add ANS1_UTCTIME.get_datetime function

Pavel Shramov <[email protected]> Tue, 24 Mar 2009 15:54:42 +0300
Newsgroups gmane.comp.python.cryptography
Message-ID <[email protected]>
--RnlQjJ0d97Da+TV1
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

OpenSSL ASN1_UTCTIME_print (and other time printing functions) produce
output not suitable for parsing with strptime:
 * Month name are not locale-dependant so python strptime fail to
   recognize them (e.g. in gtk applications)
 * Timezone is either missing or ' GMT' (with space)

Proposed patch adds get_datetime function that returns python
datetime.datetime structure with correct timezone. If this function
looks suitable I'll add tests.
                Pavel

P.S. Error messages are not perfect so they must be changed.

--RnlQjJ0d97Da+TV1
Content-Type: text/x-diff; charset=us-ascii
Content-Disposition: attachment; filename="get_datetime.patch"

commit b1ab53bf03f23de190c4929ab8827aba393e1136
Author: Pavel Shramov <[email protected]>
Date:   Tue Mar 24 15:43:19 2009 +0300

    Added ASN1_UTCTIME.get_datetime function
    
    OpenSSL ASN1_UTCTIME_print don't honour locale and adds timezone in
    format not suitable for strptime function (either '' or ' GMT') so
    this get_datetime function seem to be quite useful.

diff --git a/M2Crypto/ASN1.py b/M2Crypto/ASN1.py
index c291255..926f842 100644
--- a/M2Crypto/ASN1.py
+++ b/M2Crypto/ASN1.py
@@ -10,6 +10,8 @@ Copyright (C) 2005 OSAF. All Rights Reserved.
 import BIO
 import m2
 
+import time, datetime
+
 MBSTRING_FLAG = 0x1000
 MBSTRING_ASC  = MBSTRING_FLAG | 1
 MBSTRING_BMP  = MBSTRING_FLAG | 2
@@ -72,6 +74,19 @@ class ASN1_Object:
     def _ptr(self):
         return self.asn1obj
 
+class _UTC(datetime.tzinfo):
+    def tzname(self, dt):
+        return "UTC"
+    
+    def dst(self, dt):
+        return datetime.timedelta(0)
+    
+    def utcoffset(self, dt):
+        return datetime.timedelta(0)
+
+    def __repr__(self):
+        return "<Timezone: %s>" % self.tzname(None)
+UTC = _UTC()
 
 class ASN1_UTCTIME:
     m2_asn1_utctime_free = m2.asn1_utctime_free
@@ -113,3 +128,21 @@ class ASN1_UTCTIME:
         assert m2.asn1_utctime_type_check(self.asn1_utctime), "'asn1_utctime' type error'"
         return m2.asn1_utctime_set( self.asn1_utctime, time )
 
+    def get_datetime(self):
+        _months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
+        date = str(self)
+
+        timezone = None
+        if ' ' not in date:
+            raise ValueError("Invalid date: %s" % ssl_date)
+        month, rest = date.split(' ', 1)
+        if month not in _months:
+            raise ValueError("Invalid date %s: Invalid month: %s" % (ssl_date, m))
+        if rest.endswith(' GMT'):
+            timezone = UTC
+            rest = rest[:-4]
+        tm = list(time.strptime(rest, "%d %H:%M:%S %Y"))[:6]
+        tm[1] = _months.index(month) + 1
+        tm.append(0)
+        tm.append(timezone)
+        return datetime.datetime(*tm)

--RnlQjJ0d97Da+TV1--