Add BandwidthProcessor and IPBandwidthProcessor in apachelog.processor.bandwidth.
[apachelog.git] / apachelog / date.py
1 """Utilities for parsing the request time field (``%t``).
2
3 The ``parse_date`` function is intended as a fast way to convert a log
4 date into something useful, without incurring a significant date
5 parsing overhead---good enough for basic stuff but will be a problem
6 if you need to deal with log from multiple servers in different
7 timezones.
8
9 An alternative funtion, ``parse_time``, parses the data into
10 ``datetime.datetime`` instances, which may be slower, but it does take
11 the offset into account.  It also makes it easy to calculate time
12 differences.
13 """
14
15 import datetime as _datetime
16
17
18 MONTHS = {
19     'Jan':'01',
20     'Feb':'02',
21     'Mar':'03',
22     'Apr':'04',
23     'May':'05',
24     'Jun':'06',
25     'Jul':'07',
26     'Aug':'08',
27     'Sep':'09',
28     'Oct':'10',
29     'Nov':'11',
30     'Dec':'12'
31     }
32
33
34 def parse_date(date):
35     """Convert a date to a (`timestamp`, `offset`) tuple.
36
37     Takes a date in the format: [05/Dec/2006:10:51:44 +0000]
38     (including square brackets) and returns a two element
39     tuple containing first a timestamp of the form
40     YYYYMMDDHH24IISS e.g. 20061205105144 and second the
41     timezone offset as is e.g.;
42
43     >>> parse_date('[05/Dec/2006:10:51:44 +0000]')
44     ('20061205105144', '+0000')
45
46     It does not attempt to adjust the timestamp according
47     to the timezone---if you need this, use ``parse_time``.
48     """
49     date = date.strip('[]')
50     elems = [
51         date[7:11],
52         MONTHS[date[3:6]],
53         date[0:2],
54         date[12:14],
55         date[15:17],
56         date[18:20],
57         ]
58     return (''.join(elems),date[21:])
59
60
61 class FixedOffset(_datetime.tzinfo):
62     """Fixed offset in minutes east from UTC.
63
64     >>> f = FixedOffset(name='-0500', hours=-5)
65     >>> f.utcoffset(dt=None)
66     datetime.timedelta(-1, 68400)
67     >>> (24-5)*60*60
68     68400
69     >>> f.tzname(dt=None)
70     '-0500'
71     >>> f.dst(dt=None)
72     datetime.timedelta(0)
73     """
74     _ZERO = _datetime.timedelta(0)
75
76     def __init__(self, name, **kwargs):
77         self._offset = _datetime.timedelta(**kwargs)
78         self._name = name
79
80     def utcoffset(self, dt):
81         return self._offset
82
83     def tzname(self, dt):
84         return self._name
85
86     def dst(self, dt):
87         return self._ZERO
88
89 def parse_time(date):
90     """
91     >>> import time
92     >>> dt = parse_time("[12/Feb/2012:09:55:33 -0500]")
93     >>> dt.isoformat()
94     '2012-02-12T09:55:33-05:00'
95     >>> time.mktime(dt.utctimetuple())
96     1329076533.0
97     """
98     date = date.strip('[]')
99     tzdate = date[21:].strip()
100     soff = int(date[21:22] + '1')
101     hoff = int(date[22:24])
102     moff = int(date[24:])
103     tz = FixedOffset(tzdate, hours=soff*hoff, minutes=soff*moff)
104     return _datetime.datetime(
105         year=int(date[7:11]),
106         month=int(MONTHS[date[3:6]]),
107         day=int(date[0:2]),
108         hour=int(date[12:14]),
109         minute=int(date[15:17]),
110         second=int(date[18:20]),
111         microsecond=int(0),
112         tzinfo=tz)