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

« back to all changes in this revision

Viewing changes to ivle/date.py

  • Committer: William Grant
  • Date: 2010-02-23 08:48:09 UTC
  • mfrom: (1673 trunk)
  • mto: This revision was merged to the branch mainline in revision 1674.
  • Revision ID: grantw@unimelb.edu.au-20100223084809-du6dvsxrjhw15ytr
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
18
'''Utilities for making nice, human readable dates.'''
 
19
 
 
20
import time
 
21
import datetime
 
22
 
 
23
def get_datetime(datetime_or_seconds):
 
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
    '''
 
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,
 
44
    generates a string representing the date/time in human-readable form.
 
45
    "ddd mmm dd, yyyy h:m a"
 
46
 
 
47
    >>> make_date_nice(datetime.datetime(2009, 5, 26, 11, 38, 53))
 
48
    'Tue May 26 2009, 11:38am'
 
49
    """
 
50
    dt = get_datetime(datetime_or_seconds)
 
51
    return dt.strftime("%a %b %d %Y, %l:%M%P")
 
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,
 
57
    generates a string representing the date in human-readable form.
 
58
    Does not include the time.
 
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)
 
70
    'May 20, 2009'
 
71
    """
 
72
 
 
73
    dt = get_datetime(datetime_or_seconds)
 
74
    now = datetime.datetime.now()
 
75
 
 
76
    # Use a "naturalisation" algorithm.
 
77
    delta = now - dt
 
78
 
 
79
    if delta.days <= 5:
 
80
        # Dates today or yesterday, return "today" or "yesterday".
 
81
        if delta.days == 0:
 
82
            return "Today"
 
83
        elif delta.days == 1:
 
84
            return "Yesterday"
 
85
        else:
 
86
            # Dates in the last 5 days, return "n days ago".
 
87
            return str(delta.days) + " days ago"
 
88
    # Other dates, return a short date format.
 
89
    # If within the same year, omit the year (mmm dd)
 
90
    if dt.year == now.year:
 
91
        return dt.strftime("%b %d")
 
92
    # Else, include the year (mmm dd, yyyy)
 
93
    else:
 
94
        return dt.strftime("%b %d, %Y")
 
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.
 
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'
 
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.
 
170
            return dt.strftime('today at %l:%M%P')
 
171
        elif dt.date() == now.date() - datetime.timedelta(days=1):
 
172
            # Yesterday.
 
173
            return dt.strftime('yesterday at %l:%M%P')
 
174
    elif dt > now:
 
175
        if dt.date() == now.date():
 
176
            # Today.
 
177
            return dt.strftime('today at %l:%M%P')
 
178
        elif dt.date() == now.date() + datetime.timedelta(days=1):
 
179
            # Tomorrow
 
180
            return dt.strftime('tomorrow at %l:%M%P')
 
181
 
 
182
    return dt.strftime('on %Y-%m-%d at %l:%M%P')