forked from tominsam/shelf-python
/
Utilities.py
160 lines (132 loc) · 6 KB
/
Utilities.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
from Foundation import *
from AppKit import *
from ScriptingBridge import *
from AddressBook import *
import re
def as_dump( obj ):
methods = dir(obj)
for x in dir(object()) + dir(NSObject.alloc().init()):
if x in methods: methods.remove(x)
methods.sort()
print( obj.__class__.__name__ )
print( "\n".join(map(lambda x: " - %s"%x, methods) ) )
def as_app(bundle):
return SBApplication.applicationWithBundleIdentifier_(bundle)
def print_info(stuff):
if NSUserDefaults.standardUserDefaults().boolForKey_("debug"):
print(stuff)
def html_escape( s ):
s = re.sub(r"&", "&", s)
s = re.sub(r"<", "<", s)
s = re.sub(r">", ">", s)
return s
# this is a HACK to normalize urls. not that it's not required to return
# something that's still a valid url! (though it currently does) Don't assume
# that it does
def normalize_url( url ):
url = re.sub(r'/$', '', url) # trailing slash
url = re.sub(r'^\w+://', '', url) # protocol
url = re.sub(r'^www.flickr.', 'flickr.', url) # flickr special casing
return url.lower() # ewwww
# from http://pylonshq.com/WebHelpers/webhelpers/rails/date.py.html on 2008-02-11
"""Date/Time Helpers"""
# Last synced with Rails copy at Revision 6080 on Feb 8th, 2007.
# Note that the select_ tags are purposely not ported as they're very totally useless
# and inefficient beyond comprehension.
from datetime import datetime
import time
DEFAULT_PREFIX = 'date'
def distance_of_time_in_words(from_time, to_time=0, include_seconds=False):
"""
Reports the approximate distance in time between two datetime objects or
integers as seconds.
Set ``include_seconds`` to True for more more detailed approximations when
distance < 1 min, 29 secs
Distances are reported based on the following table:
0 <-> 29 secs => less than a minute
30 secs <-> 1 min, 29 secs => 1 minute
1 min, 30 secs <-> 44 mins, 29 secs => [2..44] minutes
44 mins, 30 secs <-> 89 mins, 29 secs => about 1 hour
89 mins, 29 secs <-> 23 hrs, 59 mins, 29 secs => about [2..24] hours
23 hrs, 59 mins, 29 secs <-> 47 hrs, 59 mins, 29 secs => 1 day
47 hrs, 59 mins, 29 secs <-> 29 days, 23 hrs, 59 mins, 29 secs => [2..29] days
29 days, 23 hrs, 59 mins, 30 secs <-> 59 days, 23 hrs, 59 mins, 29 secs => about 1 month
59 days, 23 hrs, 59 mins, 30 secs <-> 1 yr minus 31 secs => [2..12] months
1 yr minus 30 secs <-> 2 yrs minus 31 secs => about 1 year
2 yrs minus 30 secs <-> max time or date => over [2..X] years
With ``include_seconds`` set to True and the difference < 1 minute 29
seconds:
0-4 secs => less than 5 seconds
5-9 secs => less than 10 seconds
10-19 secs => less than 20 seconds
20-39 secs => half a minute
40-59 secs => less than a minute
60-89 secs => 1 minute
Examples:
>>> from datetime import datetime, timedelta
>>> from_time = datetime.now()
>>> distance_of_time_in_words(from_time, from_time + timedelta(minutes=50))
'about 1 hour'
>>> distance_of_time_in_words(from_time, from_time + timedelta(seconds=15))
'less than a minute'
>>> distance_of_time_in_words(from_time, from_time + timedelta(seconds=15), include_seconds=True)
'less than 20 seconds'
Note: ``distance_of_time_in_words`` calculates one year as 365.25 days.
"""
if isinstance(from_time, int):
from_time = time.time()+from_time
elif isinstance( from_time, time.struct_time ):
from_time = time.mktime(from_time)
else:
from_time = time.mktime(from_time.timetuple())
if isinstance(to_time, int):
to_time = time.time()+to_time
else:
to_time = time.mktime(to_time.timetuple())
distance_in_minutes = int(round(abs(to_time-from_time)/60))
distance_in_seconds = int(round(abs(to_time-from_time)))
if distance_in_minutes <= 1:
if include_seconds:
for remainder in [5, 10, 20]:
if distance_in_seconds < remainder:
return "less than %s seconds" % remainder
if distance_in_seconds < 40:
return "half a minute"
elif distance_in_seconds < 60:
return "less than a minute"
else:
return "1 minute"
else:
if distance_in_minutes == 0:
return "less than a minute"
else:
return "1 minute"
elif distance_in_minutes < 45:
return "%s minutes" % distance_in_minutes
elif distance_in_minutes < 90:
return "about 1 hour"
elif distance_in_minutes < 1440:
return "about %d hours" % (round(distance_in_minutes / 60.0))
elif distance_in_minutes < 2880:
return "1 day"
elif distance_in_minutes < 43220:
return "%d days" % (round(distance_in_minutes / 1440))
elif distance_in_minutes < 86400:
return "about 1 month"
elif distance_in_minutes < 525600:
return "%d months" % (round(distance_in_minutes / 43200))
elif distance_in_minutes < 1051200:
return "about 1 year"
else:
return "over %d years" % (round(distance_in_minutes / 525600))
def time_ago_in_words(from_time, include_seconds=False):
"""
Like distance_of_time_in_words, but where ``to_time`` is fixed to ``datetime.now()``.
"""
ago = distance_of_time_in_words(from_time, datetime.utcnow(), include_seconds)
# TODO - think about these. The output from the function is Too Damn Long, is all.
ago = re.sub(r'^about ', '~', ago )
ago = re.sub(r'minute', 'min', ago )
ago = re.sub(r'second', 'sec', ago )
return ago
__all__ = ['as_dump', 'as_app', 'print_info', 'html_escape', 'normalize_url','distance_of_time_in_words', 'time_ago_in_words']