~launchpad-pqm/launchpad/devel

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
Date Display
============

We aim for "friendly" display of dates. That means we prefer to express the
date "relative to the present" when it is close to now. Instead of saying
"2007-12-15 06:15 EST" we say "3 minutes ago" or "in 18 seconds".

There are two TALES formatters:

  o fmt:approximatedate does the hard work of turning a timestamp into an
    relative time description. It should be used for tabular data. For
    example:

        Product           Registered               Registrant
        =======           ==========               ==========
        foobar            *3 minutes ago*          James Wilson
        bzrness           *2005-11-07*             Richard Downes

  o fmt:displaydate is similar but is better in paragraphs or sentences. So,
    for example: "FooBar was registered *on 2005-11-06* and last updated
    *4 minutes ago*."

The difference between them is TINY: fmt:displaydate prepends "on " to the
result of fmt:approximatedate IF the time delta is greater than 1 day, and
hence if the display will be the date.

First, let's bring in some dependencies:

    >>> from datetime import datetime, timedelta
    >>> from canonical.launchpad.ftests import test_tales
    >>> import pytz
    >>> UTC = pytz.timezone('UTC')

fmt:approximatedate and fmt:displaydate display the difference between
the formatted timestamp and the present.  This is a really bad idea
for tests, so we register an alternate formatter that use the same
formatting code, but always display the difference from a known
timestamp.

    >>> fixed_time_utc = datetime(2005, 12, 25, 12, 0, 0, tzinfo=UTC)
    >>> fixed_time = datetime(2005, 12, 25, 12, 0, 0)
    >>> from lp.app.browser.tales import DateTimeFormatterAPI
    >>> class TestDateTimeFormatterAPI(DateTimeFormatterAPI):
    ...     def _now(self):
    ...         if self._datetime.tzinfo:
    ...             return fixed_time_utc
    ...         else:
    ...             return fixed_time
    >>> from zope.app.testing import ztapi
    >>> from zope.traversing.interfaces import IPathAdapter
    >>> ztapi.provideAdapter(
    ...     datetime, IPathAdapter, TestDateTimeFormatterAPI, 'testfmt')

A time that is very close to the present will be displayed in seconds:

    >>> t = fixed_time + timedelta(0, 5, 0)
    >>> test_tales('t/testfmt:approximatedate', t=t)
    'in 5 seconds'
    >>> print (test_tales('t/testfmt:approximatedate', t=t) ==
    ...        test_tales('t/testfmt:displaydate', t=t))
    True
    >>> t = fixed_time_utc - timedelta(0, 5, 0)
    >>> test_tales('t/testfmt:approximatedate', t=t)
    '5 seconds ago'
    >>> print (test_tales('t/testfmt:approximatedate', t=t) ==
    ...        test_tales('t/testfmt:displaydate', t=t))
    True

Further out we expect minutes.  Note that for singular units (e.g. "1
minute"), we present the singular unit:

    >>> t = fixed_time_utc + timedelta(0, 185, 0)
    >>> test_tales('t/testfmt:approximatedate', t=t)
    'in 3 minutes'
    >>> print (test_tales('t/testfmt:approximatedate', t=t) ==
    ...        test_tales('t/testfmt:displaydate', t=t))
    True
    >>> t = fixed_time_utc - timedelta(0, 75, 0)
    >>> test_tales('t/testfmt:approximatedate', t=t)
    '1 minute ago'
    >>> print (test_tales('t/testfmt:approximatedate', t=t) ==
    ...        test_tales('t/testfmt:displaydate', t=t))
    True

Further out we expect hours:

    >>> t = fixed_time_utc + timedelta(0, 3635, 0)
    >>> test_tales('t/testfmt:approximatedate', t=t)
    'in 1 hour'
    >>> print (test_tales('t/testfmt:approximatedate', t=t) ==
    ...        test_tales('t/testfmt:displaydate', t=t))
    True
    >>> t = fixed_time_utc - timedelta(0, 3635, 0)
    >>> test_tales('t/testfmt:approximatedate', t=t)
    '1 hour ago'
    >>> print (test_tales('t/testfmt:approximatedate', t=t) ==
    ...        test_tales('t/testfmt:displaydate', t=t))
    True

And if the approximate date is more than a day away, we expect the date. We
also expect the fmt:displaydate to change form, and become "on yyyy-mm-dd".

    >>> t = datetime(2004, 1, 13, 15, 35)
    >>> test_tales('t/testfmt:approximatedate', t=t)
    '2004-01-13'
    >>> print (test_tales('t/testfmt:approximatedate', t=t) ==
    ...        test_tales('t/testfmt:displaydate', t=t))
    False
    >>> test_tales('t/testfmt:displaydate', t=t)
    'on 2004-01-13'
    >>> t = datetime(2015, 1, 13, 15, 35)
    >>> test_tales('t/testfmt:approximatedate', t=t)
    '2015-01-13'
    >>> print (test_tales('t/testfmt:approximatedate', t=t) ==
    ...        test_tales('t/testfmt:displaydate', t=t))
    False
    >>> test_tales('t/testfmt:displaydate', t=t)
    'on 2015-01-13'