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): |
|
24 |
'''Return the given datetime, or convert the given seconds since epoch.'''
|
|
25 |
if type(datetime_or_seconds) is datetime.datetime: |
|
26 |
return datetime_or_seconds |
|
27 |
return datetime.datetime.fromtimestamp(datetime_or_seconds) |
|
28 |
||
29 |
def make_date_nice(datetime_or_seconds): |
|
30 |
"""Generate a full human-readable representation of a date and time.
|
|
31 |
||
32 |
Given a datetime or number of seconds elapsed since the epoch,
|
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
33 |
generates a string representing the date/time in human-readable form.
|
34 |
"ddd mmm dd, yyyy h:m a"
|
|
35 |
"""
|
|
1172
by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally. |
36 |
dt = get_datetime(datetime_or_seconds) |
37 |
return dt.strftime("%a %b %d %Y, %I:%M %p") |
|
38 |
||
39 |
def make_date_nice_short(datetime_or_seconds): |
|
40 |
"""Generate a very compact human-readable representation of a date.
|
|
41 |
||
42 |
Given a datetime or number of seconds elapsed since the epoch,
|
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
43 |
generates a string representing the date in human-readable form.
|
44 |
Does not include the time.
|
|
1172
by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally. |
45 |
"""
|
46 |
||
47 |
dt = get_datetime(datetime_or_seconds) |
|
48 |
now = datetime.datetime.now() |
|
49 |
||
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
50 |
# Use a "naturalisation" algorithm.
|
1172
by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally. |
51 |
delta = now - dt |
52 |
||
53 |
if delta.days <= 5: |
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
54 |
# Dates today or yesterday, return "today" or "yesterday".
|
1172
by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally. |
55 |
if delta.days == 0: |
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
56 |
return "Today" |
1172
by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally. |
57 |
elif delta.days == 1: |
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
58 |
return "Yesterday" |
59 |
else: |
|
1172
by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally. |
60 |
# Dates in the last 5 days, return "n days ago".
|
61 |
return str(delta.days) + " days ago" |
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
62 |
# Other dates, return a short date format.
|
63 |
# 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. |
64 |
if dt.year == now.year: |
65 |
return dt.strftime("%b %d") |
|
1079
by William Grant
Merge setup-refactor branch. This completely breaks existing installations; |
66 |
# Else, include the year (mmm dd, yyyy)
|
67 |
else: |
|
1172
by William Grant
Let functions in ivle.date take datetimes, and deal in datetimes internally. |
68 |
return dt.strftime("%b %d, %Y") |
1165.1.15
by William Grant
Add ivle.date.format_datetime_for_paragraph, a nice readable date formatter. |
69 |
|
70 |
def format_datetime_for_paragraph(datetime_or_seconds): |
|
71 |
"""Generate a compact representation of a datetime for use in a paragraph.
|
|
72 |
||
73 |
Given a datetime or number of seconds elapsed since the epoch, generates
|
|
74 |
a compact string representing the date and time in human-readable form.
|
|
75 |
||
76 |
Unlike make_date_nice_short, the time will always be included.
|
|
77 |
||
78 |
Also unlike make_date_nice_short, it is suitable for use in the middle of
|
|
79 |
a block of prose and properly handles timestamps in the future nicely.
|
|
80 |
"""
|
|
81 |
||
82 |
dt = get_datetime(datetime_or_seconds) |
|
83 |
now = datetime.datetime.now() |
|
84 |
||
85 |
delta = dt - now |
|
86 |
||
87 |
# If the date is earlier than now, we want to either say something like
|
|
88 |
# '5 days ago' or '25 seconds ago', 'yesterday at 08:54' or
|
|
89 |
# 'on 2009-03-26 at 20:09'.
|
|
90 |
||
91 |
# If the time is within one hour of now, we show it nicely in either
|
|
92 |
# minutes or seconds.
|
|
93 |
||
94 |
if abs(delta).days == 0 and abs(delta).seconds <= 1: |
|
95 |
return 'now' |
|
96 |
||
97 |
if abs(delta).days == 0 and abs(delta).seconds < 60*60: |
|
98 |
if abs(delta) == delta: |
|
99 |
# It's in the future.
|
|
100 |
prefix = 'in ' |
|
101 |
suffix = '' |
|
102 |
else: |
|
103 |
prefix = '' |
|
104 |
suffix = ' ago' |
|
105 |
||
106 |
# Show the number of minutes unless we are within two minutes.
|
|
107 |
if abs(delta).seconds >= 120: |
|
108 |
return (prefix + '%d minutes' + suffix) % (abs(delta).seconds / 60) |
|
109 |
else: |
|
110 |
return (prefix + '%d seconds' + suffix) % (abs(delta).seconds) |
|
111 |
||
112 |
if dt < now: |
|
113 |
if dt.date() == now.date(): |
|
114 |
# Today.
|
|
1165.1.30
by William Grant
Display times in 12 hour - not 24 hour - format, by popular demand. |
115 |
return dt.strftime('today at %I:%M %p') |
1165.1.15
by William Grant
Add ivle.date.format_datetime_for_paragraph, a nice readable date formatter. |
116 |
elif dt.date() == now.date() - datetime.timedelta(days=1): |
117 |
# Yesterday.
|
|
1165.1.30
by William Grant
Display times in 12 hour - not 24 hour - format, by popular demand. |
118 |
return dt.strftime('yesterday at %I:%M %p') |
1165.1.15
by William Grant
Add ivle.date.format_datetime_for_paragraph, a nice readable date formatter. |
119 |
elif dt > now: |
120 |
if dt.date() == now.date(): |
|
121 |
# Today.
|
|
1165.1.30
by William Grant
Display times in 12 hour - not 24 hour - format, by popular demand. |
122 |
return dt.strftime('today at %I:%M %p') |
1165.1.15
by William Grant
Add ivle.date.format_datetime_for_paragraph, a nice readable date formatter. |
123 |
elif dt.date() == now.date() + datetime.timedelta(days=1): |
124 |
# Tomorrow
|
|
1165.1.30
by William Grant
Display times in 12 hour - not 24 hour - format, by popular demand. |
125 |
return dt.strftime('tomorrow at %I:%M %p') |
1165.1.15
by William Grant
Add ivle.date.format_datetime_for_paragraph, a nice readable date formatter. |
126 |
|
1165.1.30
by William Grant
Display times in 12 hour - not 24 hour - format, by popular demand. |
127 |
return dt.strftime('on %Y-%m-%d at %I:%M %p') |