wheezy.core / src / wheezy / core / datetime.py

""" ``datetime`` module.
"""

from time import localtime
from time import mktime

from wheezy.core.comp import parsedate
from wheezy.core.introspection import import_name

# The lines below are equivalent to:
# from datetime import timedelta
# However it is not used due module name confict
# since the use of relative imports by default.
# absolute imports are available since python 2.5,
# however we want keep compatibility with python 2.4
datetime = import_name('datetime.datetime')
time = import_name('datetime.time')
timedelta = import_name('datetime.timedelta')
tzinfo = import_name('datetime.tzinfo')


ZERO = timedelta(0)
WEEKDAYS = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
MONTHS = (
    None, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")


def format_http_datetime(stamp):
    """ Formats datetime to a string following rfc1123 pattern.

        >>> now = datetime(2011, 9, 19, 10, 45, 30, 0, UTC)
        >>> format_http_datetime(now)
        'Mon, 19 Sep 2011 10:45:30 GMT'

        if timezone is not set in datetime instance the ``stamp``
        is assumed to be in UTC (``datetime.utcnow``).

        >>> now = datetime(2011, 9, 19, 10, 45, 30, 0)
        >>> format_http_datetime(now)
        'Mon, 19 Sep 2011 10:45:30 GMT'

        >>> now = datetime.utcnow()
        >>> assert format_http_datetime(now)

        if ``stamp`` is a string just return it

        >>> format_http_datetime('x')
        'x'

        >>> format_http_datetime(100) # doctest: +ELLIPSIS
        Traceback (most recent call last):
            ...
        TypeError: ...
    """
    if isinstance(stamp, datetime):
        if stamp.tzinfo:
            stamp = stamp.astimezone(UTC).timetuple()
        else:
            stamp = localtime(mktime(stamp.timetuple()))
    elif isinstance(stamp, str):
        return stamp
    else:
        raise TypeError('Expecting type ``datetime.datetime``.')

    year, month, day, hh, mm, ss, wd, y, z = stamp
    return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (
        WEEKDAYS[wd], day, MONTHS[month], year, hh, mm, ss
    )


def format_iso_datetime(stamp):
    """ Return a string representing the date and time in ISO 8601 format.
        If the time is in UTC, adds a 'Z' directly after the time without
        a space.

        see http://en.wikipedia.org/wiki/ISO_8601.

        >>> class EET(tzinfo):
        ...     def utcoffset(self, dt):
        ...         return timedelta(minutes=120)
        ...     def dst(self, dt):
        ...         return timedelta()
        >>> format_iso_datetime(datetime(2012, 2, 22, 12, 52, 29, 300))
        '2012-02-22T12:52:29'
        >>> format_iso_datetime(datetime(2012, 2, 22, 12, 52, 29, 300,
        ...     tzinfo=UTC))
        '2012-02-22T12:52:29Z'
        >>> format_iso_datetime(datetime(2012, 2, 22, 12, 52, 29, 300,
        ...     tzinfo=EET()))
        '2012-02-22T12:52:29+02:00'
    """
    if stamp.tzinfo:
        if stamp.utcoffset() == ZERO:
            return datetime(*stamp.timetuple()[:6]).isoformat() + 'Z'
    if stamp.microsecond:
        stamp = stamp.replace(microsecond=0)
    return stamp.isoformat()


def format_iso_time(stamp):
    """ Return a string representing the time in ISO 8601 format.
        If the time is in UTC, adds a 'Z' directly after the time without
        a space.

        see http://en.wikipedia.org/wiki/ISO_8601.

        >>> class EET(tzinfo):
        ...     def utcoffset(self, dt):
        ...         return timedelta(minutes=120)
        ...     def dst(self, dt):
        ...         return timedelta()
        >>> format_iso_time(time(12, 52, 29, 300))
        '12:52:29'
        >>> format_iso_time(time(12, 52, 29, 300,
        ...     tzinfo=UTC))
        '12:52:29Z'
        >>> format_iso_time(time(12, 52, 29, 300,
        ...     tzinfo=EET()))
        '12:52:29+02:00'
    """
    if stamp.microsecond:
        stamp = stamp.replace(microsecond=0)
    if stamp.tzinfo:
        if stamp.utcoffset() == ZERO:
            return stamp.replace(tzinfo=None).isoformat() + 'Z'
        else:
            return stamp.isoformat()
    else:
        return stamp.isoformat()


def parse_http_datetime(stamp):
    """ Parses a string in rfc1123 format to ``datetime``.

        >>> parse_http_datetime('Mon, 19 Sep 2011 10:45:30 GMT')
        datetime.datetime(2011, 9, 19, 10, 45, 30)
    """
    return datetime.fromtimestamp(mktime(parsedate(stamp)))


def total_seconds(delta):
    """ Returns a total number of seconds for the given delta.

        ``delta`` can be ``datetime.timedelta``.

        >>> total_seconds(timedelta(hours=2))
        7200

        or int:

        >>> total_seconds(100)
        100

        otherwise raise ``TypeError``.

        >>> total_seconds('100') # doctest: +ELLIPSIS
        Traceback (most recent call last):
            ...
        TypeError: ...
    """
    if isinstance(delta, int):
        return delta
    elif isinstance(delta, timedelta):
        return delta.seconds + delta.days * 86400
    else:
        raise TypeError('Expecting type datetime.timedelta '
                        'or int for seconds')


class utc(tzinfo):
    """ UTC timezone.

    """
    __slots__ = ('name')

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

    def tzname(self, dt):
        """ Name of time zone.

            >>> GMT.tzname(None)
            'GMT'
            >>> UTC.tzname(None)
            'UTC'
        """
        return self.name

    def utcoffset(self, dt):
        """ Offset from UTC.

            >>> UTC.utcoffset(None)
            datetime.timedelta(0)
        """
        return ZERO

    def dst(self, dt):
        """ DST is not in effect.

            >>> UTC.dst(None)
            datetime.timedelta(0)
        """
        return ZERO


GMT = utc('GMT')
UTC = utc('UTC')
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.