~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/timestamp.py

  • Committer: Robert Collins
  • Date: 2005-08-24 12:54:49 UTC
  • mto: (974.1.50) (1185.1.10) (1092.3.1)
  • mto: This revision was merged to the branch mainline in revision 1139.
  • Revision ID: robertc@robertcollins.net-20050824125449-4cc5745568016866
update hacking with some test foo

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
 
 
17
 
import calendar
18
 
import time
19
 
 
20
 
 
21
 
def format_highres_date(t, offset=0):
22
 
    """Format a date, such that it includes higher precision in the
23
 
    seconds field.
24
 
 
25
 
    :param t:   The local time in fractional seconds since the epoch
26
 
    :type t: float
27
 
    :param offset:  The timezone offset in integer seconds
28
 
    :type offset: int
29
 
 
30
 
    Example: format_highres_date(time.time(), -time.timezone)
31
 
    this will return a date stamp for right now,
32
 
    formatted for the local timezone.
33
 
 
34
 
    >>> from bzrlib.osutils import format_date
35
 
    >>> format_date(1120153132.350850105, 0)
36
 
    'Thu 2005-06-30 17:38:52 +0000'
37
 
    >>> format_highres_date(1120153132.350850105, 0)
38
 
    'Thu 2005-06-30 17:38:52.350850105 +0000'
39
 
    >>> format_date(1120153132.350850105, -5*3600)
40
 
    'Thu 2005-06-30 12:38:52 -0500'
41
 
    >>> format_highres_date(1120153132.350850105, -5*3600)
42
 
    'Thu 2005-06-30 12:38:52.350850105 -0500'
43
 
    >>> format_highres_date(1120153132.350850105, 7200)
44
 
    'Thu 2005-06-30 19:38:52.350850105 +0200'
45
 
    >>> format_highres_date(1152428738.867522, 19800)
46
 
    'Sun 2006-07-09 12:35:38.867522001 +0530'
47
 
    """
48
 
    assert isinstance(t, float)
49
 
 
50
 
    # This has to be formatted for "original" date, so that the
51
 
    # revision XML entry will be reproduced faithfully.
52
 
    if offset is None:
53
 
        offset = 0
54
 
    tt = time.gmtime(t + offset)
55
 
 
56
 
    return (time.strftime("%a %Y-%m-%d %H:%M:%S", tt)
57
 
            # Get the high-res seconds, but ignore the 0
58
 
            + ('%.9f' % (t - int(t)))[1:]
59
 
            + ' %+03d%02d' % (offset / 3600, (offset / 60) % 60))
60
 
 
61
 
 
62
 
def unpack_highres_date(date):
63
 
    """This takes the high-resolution date stamp, and
64
 
    converts it back into the tuple (timestamp, timezone)
65
 
    Where timestamp is in real UTC since epoch seconds, and timezone is an
66
 
    integer number of seconds offset.
67
 
 
68
 
    :param date: A date formated by format_highres_date
69
 
    :type date: string
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
 
 
99
 
    """
100
 
    # Up until the first period is a datestamp that is generated
101
 
    # as normal from time.strftime, so use time.strptime to
102
 
    # parse it
103
 
    dot_loc = date.find('.')
104
 
    if dot_loc == -1:
105
 
        raise ValueError(
106
 
            'Date string does not contain high-precision seconds: %r' % date)
107
 
    base_time = time.strptime(date[:dot_loc], "%a %Y-%m-%d %H:%M:%S")
108
 
    fract_seconds, offset = date[dot_loc:].split()
109
 
    fract_seconds = float(fract_seconds)
110
 
 
111
 
    offset = int(offset)
112
 
 
113
 
    hours = int(offset / 100)
114
 
    minutes = (offset % 100)
115
 
    seconds_offset = (hours * 3600) + (minutes * 60)
116
 
 
117
 
    # time.mktime returns localtime, but calendar.timegm returns UTC time
118
 
    timestamp = calendar.timegm(base_time)
119
 
    timestamp -= seconds_offset
120
 
    # Add back in the fractional seconds
121
 
    timestamp += fract_seconds
122
 
    return (timestamp, seconds_offset)
123
 
 
124
 
 
125
 
def format_patch_date(secs, offset=0):
126
 
    """Format a POSIX timestamp and optional offset as a patch-style date.
127
 
 
128
 
    Inverse of parse_patch_date.
129
 
    """
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
 
 
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
 
    secs_str = date_str[:-6]
142
 
    offset_str = date_str[-6:]
143
 
    offset = int(offset_str) * 36
144
 
    tm_time = time.strptime(secs_str, '%Y-%m-%d %H:%M:%S')
145
 
    # adjust seconds according to offset before converting to POSIX
146
 
    # timestamp, to avoid edge problems
147
 
    tm_time = tm_time[:5] + (tm_time[5] - offset,) + tm_time[6:]
148
 
    secs = calendar.timegm(tm_time)
149
 
    return secs, offset