summaryrefslogtreecommitdiff
path: root/tracdb/tractime.py
blob: ad12b2c236b1985f9a7bcf0ad056d86a34c40a45 (plain)
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
import datetime

from django.utils import timezone

_epoc = datetime.datetime(1970, 1, 1, tzinfo=datetime.UTC)


class time_property:
    """
    Convert Trac timestamps into UTC datetimes.

    See http://trac.edgewall.org/browser//branches/0.12-stable/trac/util/datefmt.py
    for Trac's version of all this. Mine's something of a simplification.

    Like the rest of this module this is far from perfect -- no setters, for
    example! That's good enough for now.
    """

    def __init__(self, fieldname):
        self.fieldname = fieldname

    def __get__(self, instance, owner):
        if instance is None:
            return self
        return timestamp_to_datetime(getattr(instance, self.fieldname))


def datetime_to_timestamp(dt):
    """
    Convert a python datetime object to a Trac-style timestamp.
    """
    return (dt - _epoc).total_seconds() * 1000000


def timestamp_to_datetime(ts):
    """
    Convert a Trac-style timestamp to a python datetime object.
    """
    if ts is None:
        return None
    return _epoc + datetime.timedelta(microseconds=ts)


def dayrange(d, days):
    """
    Return a tuple of two timestamps (Trac-style) corresponding to the bounds
    of the range of `days` days before the given date (included). That is to
    say, `dayrange(TODAY, 1)` will return the range for today, and
    `dayrange(TODAY, 7)` will be the last 7 days.
    """
    if days <= 0:
        raise ValueError(f"days must be greater than 0, not {days!r}")
    if type(d) is not datetime.date:
        raise TypeError(f"d must be a date object, not {d.__class__.__name__}")

    tz = timezone.get_current_timezone()
    start = datetime.datetime.combine(
        d - datetime.timedelta(days=days - 1), datetime.time(0, 0, 0), tzinfo=tz
    )
    end = datetime.datetime.combine(d, datetime.time(23, 59, 59, 999_999), tzinfo=tz)

    return (
        datetime_to_timestamp(start),
        datetime_to_timestamp(end),
    )