~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/timestamp.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-03-28 06:58:22 UTC
  • mfrom: (2379.2.3 hpss-chroot)
  • Revision ID: pqm@pqm.ubuntu.com-20070328065822-999550a858a3ced3
(robertc) Fix chroot urls to not expose the url of the transport they are protecting, allowing regular url operations to work on them. (Robert Collins, Andrew Bennetts)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007, 2008, 2009, 2011 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
from __future__ import absolute_import
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
16
 
19
17
import calendar
20
18
import time
21
 
import re
22
 
 
23
 
from bzrlib import osutils
24
19
 
25
20
 
26
21
def format_highres_date(t, offset=0):
50
45
    >>> format_highres_date(1152428738.867522, 19800)
51
46
    'Sun 2006-07-09 12:35:38.867522001 +0530'
52
47
    """
53
 
    if not isinstance(t, float):
54
 
        raise ValueError(t)
 
48
    assert isinstance(t, float)
55
49
 
56
50
    # This has to be formatted for "original" date, so that the
57
51
    # revision XML entry will be reproduced faithfully.
59
53
        offset = 0
60
54
    tt = time.gmtime(t + offset)
61
55
 
62
 
    return (osutils.weekdays[tt[6]] +
63
 
            time.strftime(" %Y-%m-%d %H:%M:%S", tt)
 
56
    return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
64
57
            # Get the high-res seconds, but ignore the 0
65
58
            + ('%.9f' % (t - int(t)))[1:]
66
59
            + ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
75
68
    :param date: A date formated by format_highres_date
76
69
    :type date: string
77
70
 
 
71
    >>> import time, random
 
72
    >>> unpack_highres_date('Thu 2005-06-30 12:38:52.350850105 -0500')
 
73
    (1120153132.3508501, -18000)
 
74
    >>> unpack_highres_date('Thu 2005-06-30 17:38:52.350850105 +0000')
 
75
    (1120153132.3508501, 0)
 
76
    >>> unpack_highres_date('Thu 2005-06-30 19:38:52.350850105 +0200')
 
77
    (1120153132.3508501, 7200)
 
78
    >>> unpack_highres_date('Sun 2006-07-09 12:35:38.867522001 +0530')
 
79
    (1152428738.867522, 19800)
 
80
    >>> from bzrlib.osutils import local_time_offset
 
81
    >>> t = time.time()
 
82
    >>> o = local_time_offset()
 
83
    >>> t2, o2 = unpack_highres_date(format_highres_date(t, o))
 
84
    >>> t == t2
 
85
    True
 
86
    >>> o == o2
 
87
    True
 
88
    >>> t -= 24*3600*365*2 # Start 2 years ago
 
89
    >>> o = -12*3600
 
90
    >>> for count in xrange(500):
 
91
    ...   t += random.random()*24*3600*30
 
92
    ...   o = ((o/3600 + 13) % 25 - 12)*3600 # Add 1 wrap around from [-12, 12]
 
93
    ...   date = format_highres_date(t, o)
 
94
    ...   t2, o2 = unpack_highres_date(date)
 
95
    ...   if t != t2 or o != o2:
 
96
    ...      print 'Failed on date %r, %s,%s diff:%s' % (date, t, o, t2-t)
 
97
    ...      break
 
98
 
78
99
    """
79
 
    # Weekday parsing is locale sensitive, so drop the weekday
80
 
    space_loc = date.find(' ')
81
 
    if space_loc == -1 or date[:space_loc] not in osutils.weekdays:
82
 
        raise ValueError(
83
 
            'Date string does not contain a day of week: %r' % date)
84
100
    # Up until the first period is a datestamp that is generated
85
101
    # as normal from time.strftime, so use time.strptime to
86
102
    # parse it
88
104
    if dot_loc == -1:
89
105
        raise ValueError(
90
106
            'Date string does not contain high-precision seconds: %r' % date)
91
 
    base_time = time.strptime(date[space_loc:dot_loc], " %Y-%m-%d %H:%M:%S")
 
107
    base_time = time.strptime(date[:dot_loc], "%a %Y-%m-%d %H:%M:%S")
92
108
    fract_seconds, offset = date[dot_loc:].split()
93
109
    fract_seconds = float(fract_seconds)
94
110
 
111
127
 
112
128
    Inverse of parse_patch_date.
113
129
    """
114
 
    if offset % 60 != 0:
115
 
        raise ValueError(
116
 
        "can't represent timezone %s offset by fractional minutes" % offset)
117
 
    # so that we don't need to do calculations on pre-epoch times,
118
 
    # which doesn't work with win32 python gmtime, we always
119
 
    # give the epoch in utc
120
 
    if secs == 0:
121
 
        offset = 0
122
 
    if secs + offset < 0:
123
 
        from warnings import warn
124
 
        warn("gmtime of negative time (%s, %s) may not work on Windows" %
125
 
                (secs, offset))
126
 
    return osutils.format_date(secs, offset=offset,
127
 
            date_fmt='%Y-%m-%d %H:%M:%S')
128
 
 
129
 
 
130
 
# Format for patch dates: %Y-%m-%d %H:%M:%S [+-]%H%M
131
 
# Groups: 1 = %Y-%m-%d %H:%M:%S; 2 = [+-]%H; 3 = %M
132
 
RE_PATCHDATE = re.compile("(\d+-\d+-\d+\s+\d+:\d+:\d+)\s*([+-]\d\d)(\d\d)$")
133
 
RE_PATCHDATE_NOOFFSET = re.compile("\d+-\d+-\d+\s+\d+:\d+:\d+$")
 
130
    assert offset % 36 == 0
 
131
    tm = time.gmtime(secs+offset)
 
132
    time_str = time.strftime('%Y-%m-%d %H:%M:%S', tm)
 
133
    return '%s %+05d' % (time_str, offset/36)
 
134
 
134
135
 
135
136
def parse_patch_date(date_str):
136
137
    """Parse a patch-style date into a POSIX timestamp and offset.
137
138
 
138
139
    Inverse of format_patch_date.
139
140
    """
140
 
    match = RE_PATCHDATE.match(date_str)
141
 
    if match is None:
142
 
        if RE_PATCHDATE_NOOFFSET.match(date_str) is not None:
143
 
            raise ValueError("time data %r is missing a timezone offset"
144
 
                % date_str)
145
 
        else:
146
 
            raise ValueError("time data %r does not match format " % date_str
147
 
                + "'%Y-%m-%d %H:%M:%S %z'")
148
 
    secs_str = match.group(1)
149
 
    offset_hours, offset_mins = int(match.group(2)), int(match.group(3))
150
 
    if abs(offset_hours) >= 24 or offset_mins >= 60:
151
 
        raise ValueError("invalid timezone %r" %
152
 
            (match.group(2) + match.group(3)))
153
 
    offset = offset_hours * 3600 + offset_mins * 60
 
141
    secs_str = date_str[:-6]
 
142
    offset_str = date_str[-6:]
 
143
    offset = int(offset_str) * 36
154
144
    tm_time = time.strptime(secs_str, '%Y-%m-%d %H:%M:%S')
155
145
    # adjust seconds according to offset before converting to POSIX
156
146
    # timestamp, to avoid edge problems