~mterry/duplicity/gdrive

« back to all changes in this revision

Viewing changes to duplicity/dup_time.py

  • Committer: bescoto
  • Date: 2002-10-29 01:49:46 UTC
  • Revision ID: vcs-imports@canonical.com-20021029014946-3m4rmm5plom7pl6q
Initial checkin

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2002 Ben Escoto
 
2
#
 
3
# This file is part of duplicity.
 
4
#
 
5
# duplicity is free software; you can redistribute it and/or modify it
 
6
# under the terms of the GNU General Public License as published by
 
7
# the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA
 
8
# 02139, USA; either version 2 of the License, or (at your option) any
 
9
# later version; incorporated herein by reference.
 
10
 
 
11
"""Provide time related exceptions and functions"""
 
12
 
 
13
import time, types, re
 
14
import globals
 
15
 
 
16
 
 
17
class TimeException(Exception): pass
 
18
 
 
19
_interval_conv_dict = {"s": 1, "m": 60, "h": 3600, "D": 86400,
 
20
                                           "W": 7*86400, "M": 30*86400, "Y": 365*86400}
 
21
_integer_regexp = re.compile("^[0-9]+$")
 
22
_interval_regexp = re.compile("^([0-9]+)([smhDWMY])")
 
23
_genstr_date_regexp1 = re.compile("^(?P<year>[0-9]{4})[-/]"
 
24
                                           "(?P<month>[0-9]{1,2})[-/](?P<day>[0-9]{1,2})$")
 
25
_genstr_date_regexp2 = re.compile("^(?P<month>[0-9]{1,2})[-/]"
 
26
                                           "(?P<day>[0-9]{1,2})[-/](?P<year>[0-9]{4})$")
 
27
curtime = curtimestr = None
 
28
prevtime = prevtimestr = None
 
29
been_awake_since = None # stores last time sleep() was run
 
30
 
 
31
def setcurtime(time_in_secs = None):
 
32
        """Sets the current time in curtime and curtimestr"""
 
33
        global curtime, curtimestr
 
34
        t = time_in_secs or time.time()
 
35
        curtime, curtimestr = t, timetostring(t)
 
36
 
 
37
def setprevtime(time_in_secs):
 
38
        """Sets the previous time in prevtime and prevtimestr"""
 
39
        global prevtime, prevtimestr
 
40
        prevtime, prevtimestr = time_in_secs, timetostring(time_in_secs)
 
41
 
 
42
def timetostring(timeinseconds):
 
43
        """Return w3 datetime compliant listing of timeinseconds"""
 
44
        return time.strftime("%Y-%m-%dT%H" + globals.time_separator +
 
45
                                                 "%M" + globals.time_separator + "%S",
 
46
                                                 time.localtime(timeinseconds)) + gettzd()
 
47
 
 
48
def stringtotime(timestring):
 
49
        """Return time in seconds from w3 timestring
 
50
 
 
51
        If there is an error parsing the string, or it doesn't look
 
52
        like a w3 datetime string, return None.
 
53
 
 
54
        """
 
55
        try:
 
56
                date, daytime = timestring[:19].split("T")
 
57
                year, month, day = map(int, date.split("-"))
 
58
                hour, minute, second = map(int,
 
59
                                                                   daytime.split(globals.time_separator))
 
60
                assert 1900 < year < 2100, year
 
61
                assert 1 <= month <= 12
 
62
                assert 1 <= day <= 31
 
63
                assert 0 <= hour <= 23
 
64
                assert 0 <= minute <= 59
 
65
                assert 0 <= second <= 61  # leap seconds
 
66
                timetuple = (year, month, day, hour, minute, second, -1, -1, -1)
 
67
                if time.daylight:
 
68
                        utc_in_secs = time.mktime(timetuple) - time.altzone
 
69
                else: utc_in_secs = time.mktime(timetuple) - time.timezone
 
70
 
 
71
                return long(utc_in_secs) + tzdtoseconds(timestring[19:])
 
72
        except (TypeError, ValueError, AssertionError): return None
 
73
 
 
74
 
 
75
def timetopretty(timeinseconds):
 
76
        """Return pretty version of time"""
 
77
        return time.asctime(time.localtime(timeinseconds))
 
78
 
 
79
def stringtopretty(timestring):
 
80
        """Return pretty version of time given w3 time string"""
 
81
        return timetopretty(stringtotime(timestring))
 
82
 
 
83
def inttopretty(seconds):
 
84
        """Convert num of seconds to readable string like "2 hours"."""
 
85
        partlist = []
 
86
        hours, seconds = divmod(seconds, 3600)
 
87
        if hours > 1: partlist.append("%d hours" % hours)
 
88
        elif hours == 1: partlist.append("1 hour")
 
89
 
 
90
        minutes, seconds = divmod(seconds, 60)
 
91
        if minutes > 1: partlist.append("%d minutes" % minutes)
 
92
        elif minutes == 1: partlist.append("1 minute")
 
93
 
 
94
        if seconds == 1: partlist.append("1 second")
 
95
        elif not partlist or seconds > 1:
 
96
                if isinstance(seconds, int) or isinstance(seconds, long):
 
97
                        partlist.append("%s seconds" % seconds)
 
98
                else: partlist.append("%.2f seconds" % seconds)
 
99
        return " ".join(partlist)
 
100
 
 
101
def intstringtoseconds(interval_string):
 
102
        """Convert a string expressing an interval (e.g. "4D2s") to seconds"""
 
103
        def error():
 
104
                raise TimeException("""Bad interval string "%s"
 
105
 
 
106
Intervals are specified like 2Y (2 years) or 2h30m (2.5 hours).  The
 
107
allowed special characters are s, m, h, D, W, M, and Y.  See the man
 
108
page for more information.
 
109
""" % interval_string)
 
110
        if len(interval_string) < 2: error()
 
111
 
 
112
        total = 0
 
113
        while interval_string:
 
114
                match = _interval_regexp.match(interval_string)
 
115
                if not match: error()
 
116
                num, ext = int(match.group(1)), match.group(2)
 
117
                if not ext in _interval_conv_dict or num < 0: error()
 
118
                total += num*_interval_conv_dict[ext]
 
119
                interval_string = interval_string[match.end(0):]
 
120
        return total
 
121
 
 
122
def gettzd():
 
123
        """Return w3's timezone identification string.
 
124
 
 
125
        Expresed as [+/-]hh:mm.  For instance, PST is -08:00.  Zone is
 
126
        coincides with what localtime(), etc., use.
 
127
 
 
128
        """
 
129
        if time.daylight: offset = -1 * time.altzone/60
 
130
        else: offset = -1 * time.timezone/60
 
131
        if offset > 0: prefix = "+"
 
132
        elif offset < 0: prefix = "-"
 
133
        else: return "Z" # time is already in UTC
 
134
 
 
135
        hours, minutes = map(abs, divmod(offset, 60))
 
136
        assert 0 <= hours <= 23
 
137
        assert 0 <= minutes <= 59
 
138
        return "%s%02d%s%02d" % (prefix, hours, globals.time_separator, minutes)
 
139
 
 
140
def tzdtoseconds(tzd):
 
141
        """Given w3 compliant TZD, return how far ahead UTC is"""
 
142
        if tzd == "Z": return 0
 
143
        assert len(tzd) == 6 # only accept forms like +08:00 for now
 
144
        assert (tzd[0] == "-" or tzd[0] == "+") and \
 
145
                   tzd[3] == globals.time_separator
 
146
        return -60 * (60 * int(tzd[:3]) + int(tzd[4:]))
 
147
 
 
148
def cmp(time1, time2):
 
149
        """Compare time1 and time2 and return -1, 0, or 1"""
 
150
        if type(time1) is types.StringType:
 
151
                time1 = stringtotime(time1)
 
152
                assert time1 is not None
 
153
        if type(time2) is types.StringType:
 
154
                time2 = stringtotime(time2)
 
155
                assert time2 is not None
 
156
 
 
157
        if time1 < time2: return -1
 
158
        elif time1 == time2: return 0
 
159
        else: return 1
 
160
 
 
161
 
 
162
def sleep(sleep_ratio):
 
163
        """Sleep for period to maintain given sleep_ratio
 
164
 
 
165
        On my system sleeping for periods less than 1/20th of a second
 
166
        doesn't seem to work very accurately, so accumulate at least that
 
167
        much time before sleeping.
 
168
 
 
169
        """
 
170
        global been_awake_since
 
171
        if been_awake_since is None: # first running
 
172
                been_awake_since = time.time()
 
173
        else:
 
174
                elapsed_time = time.time() - been_awake_since
 
175
                sleep_time = elapsed_time * (sleep_ratio/(1-sleep_ratio))
 
176
                if sleep_time >= 0.05:
 
177
                        time.sleep(sleep_time)
 
178
                        been_awake_since = time.time()
 
179
 
 
180
def genstrtotime(timestr, override_curtime = None):
 
181
        """Convert a generic time string to a time in seconds"""
 
182
        if override_curtime is None: override_curtime = curtime
 
183
        if timestr == "now": return override_curtime
 
184
 
 
185
        def error():
 
186
                raise TimeException("""Bad time string "%s"
 
187
 
 
188
The acceptible time strings are intervals (like "3D64s"), w3-datetime
 
189
strings, like "2002-04-26T04:22:01-07:00" (strings like
 
190
"2002-04-26T04:22:01" are also acceptable - rdiff-backup will use the
 
191
current time zone), or ordinary dates like 2/4/1997 or 2001-04-23
 
192
(various combinations are acceptable, but the month always precedes
 
193
the day).""" % timestr)
 
194
 
 
195
        # Test for straight integer
 
196
        if _integer_regexp.search(timestr): return int(timestr)
 
197
 
 
198
        # Test for w3-datetime format, possibly missing tzd
 
199
        t = stringtotime(timestr) or stringtotime(timestr+gettzd())
 
200
        if t: return t
 
201
 
 
202
        try: # test for an interval, like "2 days ago"
 
203
                return override_curtime - intstringtoseconds(timestr)
 
204
        except TimeException: pass
 
205
 
 
206
        # Now check for dates like 2001/3/23
 
207
        match = _genstr_date_regexp1.search(timestr) or \
 
208
                        _genstr_date_regexp2.search(timestr)
 
209
        if not match: error()
 
210
        timestr = "%s-%02d-%02dT00:00:00%s" % (match.group('year'),
 
211
                             int(match.group('month')), int(match.group('day')), gettzd())
 
212
        t = stringtotime(timestr)
 
213
        if t: return t
 
214
        else: error()