~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/timestamp.py

merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2007, 2008, 2009, 2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
16
16
 
17
17
import calendar
18
18
import time
 
19
import re
19
20
 
20
21
from bzrlib import osutils
21
22
 
72
73
    :param date: A date formated by format_highres_date
73
74
    :type date: string
74
75
 
75
 
    >>> import time, random
76
 
    >>> unpack_highres_date('Thu 2005-06-30 12:38:52.350850105 -0500')
77
 
    (1120153132.3508501, -18000)
78
 
    >>> unpack_highres_date('Thu 2005-06-30 17:38:52.350850105 +0000')
79
 
    (1120153132.3508501, 0)
80
 
    >>> unpack_highres_date('Thu 2005-06-30 19:38:52.350850105 +0200')
81
 
    (1120153132.3508501, 7200)
82
 
    >>> unpack_highres_date('Sun 2006-07-09 12:35:38.867522001 +0530')
83
 
    (1152428738.867522, 19800)
84
 
    >>> from bzrlib.osutils import local_time_offset
85
 
    >>> t = time.time()
86
 
    >>> o = local_time_offset()
87
 
    >>> t2, o2 = unpack_highres_date(format_highres_date(t, o))
88
 
    >>> t == t2
89
 
    True
90
 
    >>> o == o2
91
 
    True
92
 
    >>> t -= 24*3600*365*2 # Start 2 years ago
93
 
    >>> o = -12*3600
94
 
    >>> for count in xrange(500):
95
 
    ...   t += random.random()*24*3600*30
96
 
    ...   o = ((o/3600 + 13) % 25 - 12)*3600 # Add 1 wrap around from [-12, 12]
97
 
    ...   date = format_highres_date(t, o)
98
 
    ...   t2, o2 = unpack_highres_date(date)
99
 
    ...   if t != t2 or o != o2:
100
 
    ...      print 'Failed on date %r, %s,%s diff:%s' % (date, t, o, t2-t)
101
 
    ...      break
102
 
 
103
76
    """
104
77
    # Weekday parsing is locale sensitive, so drop the weekday
105
78
    space_loc = date.find(' ')
152
125
            date_fmt='%Y-%m-%d %H:%M:%S')
153
126
 
154
127
 
 
128
# Format for patch dates: %Y-%m-%d %H:%M:%S [+-]%H%M
 
129
# Groups: 1 = %Y-%m-%d %H:%M:%S; 2 = [+-]%H; 3 = %M
 
130
RE_PATCHDATE = re.compile("(\d+-\d+-\d+\s+\d+:\d+:\d+)\s*([+-]\d\d)(\d\d)$")
 
131
RE_PATCHDATE_NOOFFSET = re.compile("\d+-\d+-\d+\s+\d+:\d+:\d+$")
 
132
 
155
133
def parse_patch_date(date_str):
156
134
    """Parse a patch-style date into a POSIX timestamp and offset.
157
135
 
158
136
    Inverse of format_patch_date.
159
137
    """
160
 
    secs_str = date_str[:-6]
161
 
    offset_str = date_str[-5:]
162
 
    if len(offset_str) != 5:
163
 
        raise ValueError(
164
 
            "invalid timezone %r" % offset_str)
165
 
    offset_hours, offset_mins = offset_str[:3], offset_str[3:]
166
 
    offset = int(offset_hours) * 3600 + int(offset_mins) * 60
 
138
    match = RE_PATCHDATE.match(date_str)
 
139
    if match is None:
 
140
        if RE_PATCHDATE_NOOFFSET.match(date_str) is not None:
 
141
            raise ValueError("time data %r is missing a timezone offset"
 
142
                % date_str)
 
143
        else:
 
144
            raise ValueError("time data %r does not match format " % date_str
 
145
                + "'%Y-%m-%d %H:%M:%S %z'")
 
146
    secs_str = match.group(1)
 
147
    offset_hours, offset_mins = int(match.group(2)), int(match.group(3))
 
148
    if abs(offset_hours) >= 24 or offset_mins >= 60:
 
149
        raise ValueError("invalid timezone %r" %
 
150
            (match.group(2) + match.group(3)))
 
151
    offset = offset_hours * 3600 + offset_mins * 60
167
152
    tm_time = time.strptime(secs_str, '%Y-%m-%d %H:%M:%S')
168
153
    # adjust seconds according to offset before converting to POSIX
169
154
    # timestamp, to avoid edge problems