/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/timestamp.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-04-24 10:31:28 UTC
  • mfrom: (1684.1.2 bzr.mbp.integration)
  • Revision ID: pqm@pqm.ubuntu.com-20060424103128-a637f56a7c529bad
(mbp) tutorial improvements

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007, 2008, 2009, 2011 Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
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
18
 
 
19
 
import calendar
20
 
import time
21
 
import re
22
 
 
23
 
from . import osutils
24
 
 
25
 
 
26
 
def format_highres_date(t, offset=0):
27
 
    """Format a date, such that it includes higher precision in the
28
 
    seconds field.
29
 
 
30
 
    :param t:   The local time in fractional seconds since the epoch
31
 
    :type t: float
32
 
    :param offset:  The timezone offset in integer seconds
33
 
    :type offset: int
34
 
 
35
 
    Example: format_highres_date(time.time(), -time.timezone)
36
 
    this will return a date stamp for right now,
37
 
    formatted for the local timezone.
38
 
 
39
 
    >>> from breezy.osutils import format_date
40
 
    >>> format_date(1120153132.350850105, 0)
41
 
    'Thu 2005-06-30 17:38:52 +0000'
42
 
    >>> format_highres_date(1120153132.350850105, 0)
43
 
    'Thu 2005-06-30 17:38:52.350850105 +0000'
44
 
    >>> format_date(1120153132.350850105, -5*3600)
45
 
    'Thu 2005-06-30 12:38:52 -0500'
46
 
    >>> format_highres_date(1120153132.350850105, -5*3600)
47
 
    'Thu 2005-06-30 12:38:52.350850105 -0500'
48
 
    >>> format_highres_date(1120153132.350850105, 7200)
49
 
    'Thu 2005-06-30 19:38:52.350850105 +0200'
50
 
    >>> format_highres_date(1152428738.867522, 19800)
51
 
    'Sun 2006-07-09 12:35:38.867522001 +0530'
52
 
    """
53
 
    if not isinstance(t, float):
54
 
        raise ValueError(t)
55
 
 
56
 
    # This has to be formatted for "original" date, so that the
57
 
    # revision XML entry will be reproduced faithfully.
58
 
    if offset is None:
59
 
        offset = 0
60
 
    tt = time.gmtime(t + offset)
61
 
 
62
 
    return (osutils.weekdays[tt[6]] + time.strftime(" %Y-%m-%d %H:%M:%S", tt) +
63
 
            # Get the high-res seconds, but ignore the 0
64
 
            ('%.9f' % (t - int(t)))[1:] +
65
 
            ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
66
 
 
67
 
 
68
 
def unpack_highres_date(date):
69
 
    """This takes the high-resolution date stamp, and
70
 
    converts it back into the tuple (timestamp, timezone)
71
 
    Where timestamp is in real UTC since epoch seconds, and timezone is an
72
 
    integer number of seconds offset.
73
 
 
74
 
    :param date: A date formated by format_highres_date
75
 
    :type date: string
76
 
 
77
 
    """
78
 
    # Weekday parsing is locale sensitive, so drop the weekday
79
 
    space_loc = date.find(' ')
80
 
    if space_loc == -1 or date[:space_loc] not in osutils.weekdays:
81
 
        raise ValueError(
82
 
            'Date string does not contain a day of week: %r' % date)
83
 
    # Up until the first period is a datestamp that is generated
84
 
    # as normal from time.strftime, so use time.strptime to
85
 
    # parse it
86
 
    dot_loc = date.find('.')
87
 
    if dot_loc == -1:
88
 
        raise ValueError(
89
 
            'Date string does not contain high-precision seconds: %r' % date)
90
 
    base_time = time.strptime(date[space_loc:dot_loc], " %Y-%m-%d %H:%M:%S")
91
 
    fract_seconds, offset = date[dot_loc:].split()
92
 
    fract_seconds = float(fract_seconds)
93
 
 
94
 
    offset = int(offset)
95
 
 
96
 
    hours = int(offset / 100)
97
 
    minutes = (offset % 100)
98
 
    seconds_offset = (hours * 3600) + (minutes * 60)
99
 
 
100
 
    # time.mktime returns localtime, but calendar.timegm returns UTC time
101
 
    timestamp = calendar.timegm(base_time)
102
 
    timestamp -= seconds_offset
103
 
    # Add back in the fractional seconds
104
 
    timestamp += fract_seconds
105
 
    return (timestamp, seconds_offset)
106
 
 
107
 
 
108
 
def format_patch_date(secs, offset=0):
109
 
    """Format a POSIX timestamp and optional offset as a patch-style date.
110
 
 
111
 
    Inverse of parse_patch_date.
112
 
    """
113
 
    if offset % 60 != 0:
114
 
        raise ValueError(
115
 
            "can't represent timezone %s offset by fractional minutes" % offset)
116
 
    # so that we don't need to do calculations on pre-epoch times,
117
 
    # which doesn't work with win32 python gmtime, we always
118
 
    # give the epoch in utc
119
 
    if secs == 0:
120
 
        offset = 0
121
 
    if secs + offset < 0:
122
 
        from warnings import warn
123
 
        warn("gmtime of negative time (%s, %s) may not work on Windows" %
124
 
             (secs, offset))
125
 
    return osutils.format_date(secs, offset=offset,
126
 
                               date_fmt='%Y-%m-%d %H:%M:%S')
127
 
 
128
 
 
129
 
# Format for patch dates: %Y-%m-%d %H:%M:%S [+-]%H%M
130
 
# Groups: 1 = %Y-%m-%d %H:%M:%S; 2 = [+-]%H; 3 = %M
131
 
RE_PATCHDATE = re.compile(
132
 
    "(\\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+$")
134
 
 
135
 
 
136
 
def parse_patch_date(date_str):
137
 
    """Parse a patch-style date into a POSIX timestamp and offset.
138
 
 
139
 
    Inverse of format_patch_date.
140
 
    """
141
 
    match = RE_PATCHDATE.match(date_str)
142
 
    if match is None:
143
 
        if RE_PATCHDATE_NOOFFSET.match(date_str) is not None:
144
 
            raise ValueError("time data %r is missing a timezone offset"
145
 
                             % date_str)
146
 
        else:
147
 
            raise ValueError("time data %r does not match format " % date_str +
148
 
                             "'%Y-%m-%d %H:%M:%S %z'")
149
 
    secs_str = match.group(1)
150
 
    offset_hours, offset_mins = int(match.group(2)), int(match.group(3))
151
 
    if abs(offset_hours) >= 24 or offset_mins >= 60:
152
 
        raise ValueError("invalid timezone %r" %
153
 
                         (match.group(2) + match.group(3)))
154
 
    offset = offset_hours * 3600 + offset_mins * 60
155
 
    tm_time = time.strptime(secs_str, '%Y-%m-%d %H:%M:%S')
156
 
    # adjust seconds according to offset before converting to POSIX
157
 
    # timestamp, to avoid edge problems
158
 
    tm_time = tm_time[:5] + (tm_time[5] - offset,) + tm_time[6:]
159
 
    secs = calendar.timegm(tm_time)
160
 
    return secs, offset