[tor-commits] [ooni-probe/master] Add RFC3339 to git repo
art at torproject.org
art at torproject.org
Tue Jul 10 03:59:03 UTC 2012
commit e2c1757f2ddc503b38964e89e069db52173950de
Author: Arturo Filastò <hellais at torproject.org>
Date: Tue Jul 10 05:58:02 2012 +0200
Add RFC3339 to git repo
---
ooni/lib/Makefile | 22 ++--
ooni/lib/rfc3339.py | 283 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 294 insertions(+), 11 deletions(-)
diff --git a/ooni/lib/Makefile b/ooni/lib/Makefile
index a498a35..4cfbee3 100644
--- a/ooni/lib/Makefile
+++ b/ooni/lib/Makefile
@@ -1,4 +1,4 @@
-all: txtorcon txtraceroute txscapy rfc3339
+all: txtorcon txtraceroute
txtraceroute:
echo "Processing dependency txtraceroute..."
@@ -12,15 +12,15 @@ txtorcon:
mv txtorcon.git/txtorcon txtorcon
rm -rf txtorcon.git
-txscapy:
- echo "Processing dependency txscapy"
- git clone https://github.com/hellais/txscapy.git txscapy.git
- mv txscapy.git/txscapy.py txscapy.py
- rm -rf txscapy.git
+#txscapy:
+# echo "Processing dependency txscapy"
+# git clone https://github.com/hellais/txscapy.git txscapy.git
+# mv txscapy.git/txscapy.py txscapy.py
+# rm -rf txscapy.git
-rfc3339:
- echo "Processing RFC3339 dependency"
- hg clone https://bitbucket.org/henry/rfc3339 rfc3339
- mv rfc3339/rfc3339.py rfc3339.py
- rf -rf rfc3339
+#rfc3339:
+# echo "Processing RFC3339 dependency"
+# hg clone https://bitbucket.org/henry/rfc3339 rfc3339
+# mv rfc3339/rfc3339.py rfc3339.py
+# rm -rf rfc3339
diff --git a/ooni/lib/rfc3339.py b/ooni/lib/rfc3339.py
new file mode 100644
index 0000000..e664ce7
--- /dev/null
+++ b/ooni/lib/rfc3339.py
@@ -0,0 +1,283 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2009, 2010, Henry Precheur <henry at precheur.org>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+# FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+#
+'''Formats dates according to the :RFC:`3339`.
+
+Report bugs & problems on BitBucket_
+
+.. _BitBucket: https://bitbucket.org/henry/clan.cx/issues
+'''
+
+__author__ = 'Henry Precheur <henry at precheur.org>'
+__license__ = 'ISCL'
+__version__ = '5.1'
+__all__ = ('rfc3339', )
+
+import datetime
+import time
+import unittest
+
+def _timezone(utc_offset):
+ '''
+ Return a string representing the timezone offset.
+
+ >>> _timezone(0)
+ '+00:00'
+ >>> _timezone(3600)
+ '+01:00'
+ >>> _timezone(-28800)
+ '-08:00'
+ >>> _timezone(-1800)
+ '-00:30'
+ '''
+ # Python's division uses floor(), not round() like in other languages:
+ # -1 / 2 == -1 and not -1 / 2 == 0
+ # That's why we use abs(utc_offset).
+ hours = abs(utc_offset) // 3600
+ minutes = abs(utc_offset) % 3600 // 60
+ sign = (utc_offset < 0 and '-') or '+'
+ return '%c%02d:%02d' % (sign, hours, minutes)
+
+def _timedelta_to_seconds(timedelta):
+ '''
+ >>> _timedelta_to_seconds(datetime.timedelta(hours=3))
+ 10800
+ >>> _timedelta_to_seconds(datetime.timedelta(hours=3, minutes=15))
+ 11700
+ '''
+ return (timedelta.days * 86400 + timedelta.seconds +
+ timedelta.microseconds // 1000)
+
+def _utc_offset(date, use_system_timezone):
+ '''
+ Return the UTC offset of `date`. If `date` does not have any `tzinfo`, use
+ the timezone informations stored locally on the system.
+
+ >>> if time.localtime().tm_isdst:
+ ... system_timezone = -time.altzone
+ ... else:
+ ... system_timezone = -time.timezone
+ >>> _utc_offset(datetime.datetime.now(), True) == system_timezone
+ True
+ >>> _utc_offset(datetime.datetime.now(), False)
+ 0
+ '''
+ if isinstance(date, datetime.datetime) and date.tzinfo is not None:
+ return _timedelta_to_seconds(date.dst() or date.utcoffset())
+ elif use_system_timezone:
+ if date.year < 1970:
+ # We use 1972 because 1970 doesn't have a leap day (feb 29)
+ t = time.mktime(date.replace(year=1972).timetuple())
+ else:
+ t = time.mktime(date.timetuple())
+ if time.localtime(t).tm_isdst: # pragma: no cover
+ return -time.altzone
+ else:
+ return -time.timezone
+ else:
+ return 0
+
+def _string(d, timezone):
+ return ('%04d-%02d-%02dT%02d:%02d:%02d%s' %
+ (d.year, d.month, d.day, d.hour, d.minute, d.second, timezone))
+
+def rfc3339(date, utc=False, use_system_timezone=True):
+ '''
+ Return a string formatted according to the :RFC:`3339`. If called with
+ `utc=True`, it normalizes `date` to the UTC date. If `date` does not have
+ any timezone information, uses the local timezone::
+
+ >>> d = datetime.datetime(2008, 4, 2, 20)
+ >>> rfc3339(d, utc=True, use_system_timezone=False)
+ '2008-04-02T20:00:00Z'
+ >>> rfc3339(d) # doctest: +ELLIPSIS
+ '2008-04-02T20:00:00...'
+
+ If called with `user_system_timezone=False` don't use the local timezone if
+ `date` does not have timezone informations and consider the offset to UTC
+ to be zero::
+
+ >>> rfc3339(d, use_system_timezone=False)
+ '2008-04-02T20:00:00+00:00'
+
+ `date` must be a `datetime.datetime`, `datetime.date` or a timestamp as
+ returned by `time.time()`::
+
+ >>> rfc3339(0, utc=True, use_system_timezone=False)
+ '1970-01-01T00:00:00Z'
+ >>> rfc3339(datetime.date(2008, 9, 6), utc=True,
+ ... use_system_timezone=False)
+ '2008-09-06T00:00:00Z'
+ >>> rfc3339(datetime.date(2008, 9, 6),
+ ... use_system_timezone=False)
+ '2008-09-06T00:00:00+00:00'
+ >>> rfc3339('foo bar')
+ Traceback (most recent call last):
+ ...
+ TypeError: Expected timestamp or date object. Got <type 'str'>.
+
+ For dates before January 1st 1970, the timezones will be the ones used in
+ 1970. It might not be accurate, but on most sytem there is no timezone
+ information before 1970.
+ '''
+ # Try to convert timestamp to datetime
+ try:
+ if use_system_timezone:
+ date = datetime.datetime.fromtimestamp(date)
+ else:
+ date = datetime.datetime.utcfromtimestamp(date)
+ except TypeError:
+ pass
+
+ if not isinstance(date, datetime.date):
+ raise TypeError('Expected timestamp or date object. Got %r.' %
+ type(date))
+
+ if not isinstance(date, datetime.datetime):
+ date = datetime.datetime(*date.timetuple()[:3])
+ utc_offset = _utc_offset(date, use_system_timezone)
+ if utc:
+ return _string(date + datetime.timedelta(seconds=utc_offset), 'Z')
+ else:
+ return _string(date, _timezone(utc_offset))
+
+
+class LocalTimeTestCase(unittest.TestCase):
+ '''
+ Test the use of the timezone saved locally. Since it is hard to test using
+ doctest.
+ '''
+
+ def setUp(self):
+ local_utcoffset = _utc_offset(datetime.datetime.now(), True)
+ self.local_utcoffset = datetime.timedelta(seconds=local_utcoffset)
+ self.local_timezone = _timezone(local_utcoffset)
+
+ def test_datetime(self):
+ d = datetime.datetime.now()
+ self.assertEqual(rfc3339(d),
+ d.strftime('%Y-%m-%dT%H:%M:%S') + self.local_timezone)
+
+ def test_datetime_timezone(self):
+
+ class FixedNoDst(datetime.tzinfo):
+ 'A timezone info with fixed offset, not DST'
+
+ def utcoffset(self, dt):
+ return datetime.timedelta(hours=2, minutes=30)
+
+ def dst(self, dt):
+ return None
+
+ fixed_no_dst = FixedNoDst()
+
+ class Fixed(FixedNoDst):
+ 'A timezone info with DST'
+
+ def dst(self, dt):
+ return datetime.timedelta(hours=3, minutes=15)
+
+ fixed = Fixed()
+
+ d = datetime.datetime.now().replace(tzinfo=fixed_no_dst)
+ timezone = _timezone(_timedelta_to_seconds(fixed_no_dst.\
+ utcoffset(None)))
+ self.assertEqual(rfc3339(d),
+ d.strftime('%Y-%m-%dT%H:%M:%S') + timezone)
+
+ d = datetime.datetime.now().replace(tzinfo=fixed)
+ timezone = _timezone(_timedelta_to_seconds(fixed.dst(None)))
+ self.assertEqual(rfc3339(d),
+ d.strftime('%Y-%m-%dT%H:%M:%S') + timezone)
+
+ def test_datetime_utc(self):
+ d = datetime.datetime.now()
+ d_utc = d + self.local_utcoffset
+ self.assertEqual(rfc3339(d, utc=True),
+ d_utc.strftime('%Y-%m-%dT%H:%M:%SZ'))
+
+ def test_date(self):
+ d = datetime.date.today()
+ self.assertEqual(rfc3339(d),
+ d.strftime('%Y-%m-%dT%H:%M:%S') + self.local_timezone)
+
+ def test_date_utc(self):
+ d = datetime.date.today()
+ # Convert `date` to `datetime`, since `date` ignores seconds and hours
+ # in timedeltas:
+ # >>> datetime.date(2008, 9, 7) + datetime.timedelta(hours=23)
+ # datetime.date(2008, 9, 7)
+ d_utc = datetime.datetime(*d.timetuple()[:3]) + self.local_utcoffset
+ self.assertEqual(rfc3339(d, utc=True),
+ d_utc.strftime('%Y-%m-%dT%H:%M:%SZ'))
+
+ def test_timestamp(self):
+ d = time.time()
+ self.assertEqual(rfc3339(d),
+ datetime.datetime.fromtimestamp(d).\
+ strftime('%Y-%m-%dT%H:%M:%S') + self.local_timezone)
+
+ def test_timestamp_utc(self):
+ d = time.time()
+ d_utc = datetime.datetime.utcfromtimestamp(d) + self.local_utcoffset
+ self.assertEqual(rfc3339(d),
+ (d_utc.strftime('%Y-%m-%dT%H:%M:%S') +
+ self.local_timezone))
+
+ def test_before_1970(self):
+ d = datetime.date(1885, 01, 04)
+ self.failUnless(rfc3339(d).startswith('1885-01-04T00:00:00'))
+ self.assertEqual(rfc3339(d, utc=True, use_system_timezone=False),
+ '1885-01-04T00:00:00Z')
+
+ def test_1920(self):
+ d = datetime.date(1920, 02, 29)
+ x = rfc3339(d, utc=False, use_system_timezone=True)
+ self.failUnless(x.startswith('1920-02-29T00:00:00'))
+
+ # If these tests start failing it probably means there was a policy change
+ # for the Pacific time zone.
+ # See http://en.wikipedia.org/wiki/Pacific_Time_Zone.
+ if 'PST' in time.tzname:
+ def testPDTChange(self):
+ '''Test Daylight saving change'''
+ # PDT switch happens at 2AM on March 14, 2010
+
+ # 1:59AM PST
+ self.assertEqual(rfc3339(datetime.datetime(2010, 3, 14, 1, 59)),
+ '2010-03-14T01:59:00-08:00')
+ # 3AM PDT
+ self.assertEqual(rfc3339(datetime.datetime(2010, 3, 14, 3, 0)),
+ '2010-03-14T03:00:00-07:00')
+
+ def testPSTChange(self):
+ '''Test Standard time change'''
+ # PST switch happens at 2AM on November 6, 2010
+
+ # 0:59AM PDT
+ self.assertEqual(rfc3339(datetime.datetime(2010, 11, 7, 0, 59)),
+ '2010-11-07T00:59:00-07:00')
+
+ # 1:00AM PST
+ # There's no way to have 1:00AM PST without a proper tzinfo
+ self.assertEqual(rfc3339(datetime.datetime(2010, 11, 7, 1, 0)),
+ '2010-11-07T01:00:00-07:00')
+
+
+if __name__ == '__main__': # pragma: no cover
+ import doctest
+ doctest.testmod()
+ unittest.main()
More information about the tor-commits
mailing list