~azzar1/unity/add-show-desktop-key

1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
1
# IVLE
2
# Copyright (C) 2008 The University of Melbourne
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
1172 by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally.
18
'''Utilities for making nice, human readable dates.'''
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
19
20
import time
1172 by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally.
21
import datetime
22
23
def get_datetime(datetime_or_seconds):
1265 by William Grant
Add some doctests to ivle.date.
24
    '''Return the given datetime, or convert the given seconds since epoch.
25
26
    >>> get_datetime(1000000000)
27
    datetime.datetime(2001, 9, 9, 11, 46, 40)
28
    >>> get_datetime(2000000000)
29
    datetime.datetime(2033, 5, 18, 13, 33, 20)
30
31
    >>> get_datetime(datetime.datetime(2009, 5, 26, 11, 38, 53))
32
    datetime.datetime(2009, 5, 26, 11, 38, 53)
33
    >>> get_datetime(datetime.datetime(2001, 9, 9, 11, 46, 40))
34
    datetime.datetime(2001, 9, 9, 11, 46, 40)
35
    '''
1172 by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally.
36
    if type(datetime_or_seconds) is datetime.datetime:
37
        return datetime_or_seconds
38
    return datetime.datetime.fromtimestamp(datetime_or_seconds)
39
40
def make_date_nice(datetime_or_seconds):
41
    """Generate a full human-readable representation of a date and time.
42
43
    Given a datetime or number of seconds elapsed since the epoch,
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
44
    generates a string representing the date/time in human-readable form.
45
    "ddd mmm dd, yyyy h:m a"
1265 by William Grant
Add some doctests to ivle.date.
46
47
    >>> make_date_nice(datetime.datetime(2009, 5, 26, 11, 38, 53))
48
    'Tue May 26 2009, 11:38am'
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
49
    """
1172 by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally.
50
    dt = get_datetime(datetime_or_seconds)
1263 by William Grant
Drop leading 0s from pretty hours, and lowercase AM/PM.
51
    return dt.strftime("%a %b %d %Y, %l:%M%P")
1172 by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally.
52
53
def make_date_nice_short(datetime_or_seconds):
54
    """Generate a very compact human-readable representation of a date.
55
56
    Given a datetime or number of seconds elapsed since the epoch,
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
57
    generates a string representing the date in human-readable form.
58
    Does not include the time.
1265 by William Grant
Add some doctests to ivle.date.
59
60
    >>> now = datetime.datetime.now()
61
    >>> make_date_nice_short(now)
62
    'Today'
63
    >>> make_date_nice_short(now - datetime.timedelta(1))
64
    'Yesterday'
65
    >>> make_date_nice_short(now - datetime.timedelta(2))
66
    '2 days ago'
67
    >>> make_date_nice_short(now - datetime.timedelta(5))
68
    '5 days ago'
69
    >>> make_date_nice_short(1242783748)
1500 by William Grant
Unbreak existing tests.
70
    'May 20, 2009'
1172 by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally.
71
    """
72
73
    dt = get_datetime(datetime_or_seconds)
74
    now = datetime.datetime.now()
75
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
76
    # Use a "naturalisation" algorithm.
1172 by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally.
77
    delta = now - dt
78
79
    if delta.days <= 5:
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
80
        # Dates today or yesterday, return "today" or "yesterday".
1172 by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally.
81
        if delta.days == 0:
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
82
            return "Today"
1172 by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally.
83
        elif delta.days == 1:
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
84
            return "Yesterday"
85
        else:
1172 by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally.
86
            # Dates in the last 5 days, return "n days ago".
87
            return str(delta.days) + " days ago"
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
88
    # Other dates, return a short date format.
89
    # If within the same year, omit the year (mmm dd)
1172 by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally.
90
    if dt.year == now.year:
91
        return dt.strftime("%b %d")
1079 by William Grant
Merge setup-refactor branch. This completely breaks existing installations;
92
    # Else, include the year (mmm dd, yyyy)
93
    else:
1172 by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally.
94
        return dt.strftime("%b %d, %Y")
1165.1.15 by William Grant
Add ivle.date.format_datetime_for_paragraph, a nice readable date formatter.
95
96
def format_datetime_for_paragraph(datetime_or_seconds):
97
    """Generate a compact representation of a datetime for use in a paragraph.
98
99
    Given a datetime or number of seconds elapsed since the epoch, generates
100
    a compact string representing the date and time in human-readable form.
101
102
    Unlike make_date_nice_short, the time will always be included.
103
104
    Also unlike make_date_nice_short, it is suitable for use in the middle of
105
    a block of prose and properly handles timestamps in the future nicely.
1265 by William Grant
Add some doctests to ivle.date.
106
107
    >>> now = datetime.datetime.now()
108
    >>> today = now.date()
109
    >>> time = datetime.time(10, 35, 40)
110
    >>> earlier = datetime.datetime.combine(today, time)
111
    >>> date = datetime.datetime(2009, 5, 20, 21, 19, 53)
112
113
    >>> format_datetime_for_paragraph(now)
114
    'now'
115
116
    # We can go backwards and forwards a little while and be pretty.
117
    >>> format_datetime_for_paragraph(now - datetime.timedelta(0, 40))
118
    '40 seconds ago'
119
    >>> format_datetime_for_paragraph(now + datetime.timedelta(0, 30))
120
    'in 29 seconds'
121
122
    >>> format_datetime_for_paragraph(now - datetime.timedelta(0, 245))
123
    '4 minutes ago'
124
    >>> format_datetime_for_paragraph(now + datetime.timedelta(0, 3500))
125
    'in 58 minutes'
126
127
    # If we go back further, it gets a bit ugly.
128
    >>> format_datetime_for_paragraph(earlier - datetime.timedelta(1))
129
    'yesterday at 10:35am'
130
    >>> format_datetime_for_paragraph(date)
131
    'on 2009-05-20 at  9:19pm'
132
133
    >>> format_datetime_for_paragraph(earlier + datetime.timedelta(1))
134
    'tomorrow at 10:35am'
1165.1.15 by William Grant
Add ivle.date.format_datetime_for_paragraph, a nice readable date formatter.
135
    """
136
137
    dt = get_datetime(datetime_or_seconds)
138
    now = datetime.datetime.now()
139
140
    delta = dt - now
141
142
    # If the date is earlier than now, we want to either say something like
143
    # '5 days ago' or '25 seconds ago', 'yesterday at 08:54' or
144
    # 'on 2009-03-26 at 20:09'.
145
146
    # If the time is within one hour of now, we show it nicely in either
147
    # minutes or seconds.
148
149
    if abs(delta).days == 0 and abs(delta).seconds <= 1:
150
        return 'now'
151
152
    if abs(delta).days == 0 and abs(delta).seconds < 60*60:
153
        if abs(delta) == delta:
154
            # It's in the future.
155
            prefix = 'in '
156
            suffix = ''
157
        else:
158
            prefix = ''
159
            suffix = ' ago'
160
161
        # Show the number of minutes unless we are within two minutes.
162
        if abs(delta).seconds >= 120:
163
            return (prefix + '%d minutes' + suffix) % (abs(delta).seconds / 60)
164
        else:
165
            return (prefix + '%d seconds' + suffix) % (abs(delta).seconds)
166
167
    if dt < now:
168
        if dt.date() == now.date():
169
            # Today.
1263 by William Grant
Drop leading 0s from pretty hours, and lowercase AM/PM.
170
            return dt.strftime('today at %l:%M%P')
1165.1.15 by William Grant
Add ivle.date.format_datetime_for_paragraph, a nice readable date formatter.
171
        elif dt.date() == now.date() - datetime.timedelta(days=1):
172
            # Yesterday.
1263 by William Grant
Drop leading 0s from pretty hours, and lowercase AM/PM.
173
            return dt.strftime('yesterday at %l:%M%P')
1165.1.15 by William Grant
Add ivle.date.format_datetime_for_paragraph, a nice readable date formatter.
174
    elif dt > now:
175
        if dt.date() == now.date():
176
            # Today.
1263 by William Grant
Drop leading 0s from pretty hours, and lowercase AM/PM.
177
            return dt.strftime('today at %l:%M%P')
1165.1.15 by William Grant
Add ivle.date.format_datetime_for_paragraph, a nice readable date formatter.
178
        elif dt.date() == now.date() + datetime.timedelta(days=1):
179
            # Tomorrow
1263 by William Grant
Drop leading 0s from pretty hours, and lowercase AM/PM.
180
            return dt.strftime('tomorrow at %l:%M%P')
1165.1.15 by William Grant
Add ivle.date.format_datetime_for_paragraph, a nice readable date formatter.
181
1263 by William Grant
Drop leading 0s from pretty hours, and lowercase AM/PM.
182
    return dt.strftime('on %Y-%m-%d at %l:%M%P')