imip-agent

Annotated imiptools/dates.py

152:e835f990697a
2015-01-13 Paul Boddie Moved date-related functions into a separate module for period module usage.
paul@152 1
#!/usr/bin/env python
paul@152 2
paul@152 3
"""
paul@152 4
Date processing functions.
paul@152 5
paul@152 6
Copyright (C) 2014, 2015 Paul Boddie <paul@boddie.org.uk>
paul@152 7
paul@152 8
This program is free software; you can redistribute it and/or modify it under
paul@152 9
the terms of the GNU General Public License as published by the Free Software
paul@152 10
Foundation; either version 3 of the License, or (at your option) any later
paul@152 11
version.
paul@152 12
paul@152 13
This program is distributed in the hope that it will be useful, but WITHOUT
paul@152 14
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
paul@152 15
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
paul@152 16
details.
paul@152 17
paul@152 18
You should have received a copy of the GNU General Public License along with
paul@152 19
this program.  If not, see <http://www.gnu.org/licenses/>.
paul@152 20
"""
paul@152 21
paul@152 22
from datetime import date, datetime
paul@152 23
from pytz import timezone, UnknownTimeZoneError
paul@152 24
import re
paul@152 25
paul@152 26
# iCalendar date and datetime parsing (from DateSupport in MoinSupport).
paul@152 27
paul@152 28
date_icalendar_regexp_str = ur'(?P<year>[0-9]{4})(?P<month>[0-9]{2})(?P<day>[0-9]{2})'
paul@152 29
datetime_icalendar_regexp_str = date_icalendar_regexp_str + \
paul@152 30
    ur'(?:' \
paul@152 31
    ur'T(?P<hour>[0-2][0-9])(?P<minute>[0-5][0-9])(?P<second>[0-6][0-9])' \
paul@152 32
    ur'(?P<utc>Z)?' \
paul@152 33
    ur')?'
paul@152 34
paul@152 35
match_date_icalendar = re.compile(date_icalendar_regexp_str, re.UNICODE).match
paul@152 36
match_datetime_icalendar = re.compile(datetime_icalendar_regexp_str, re.UNICODE).match
paul@152 37
paul@152 38
def to_utc_datetime(dt):
paul@152 39
    if not dt:
paul@152 40
        return None
paul@152 41
    elif isinstance(dt, datetime):
paul@152 42
        return dt.astimezone(timezone("UTC"))
paul@152 43
    else:
paul@152 44
        return dt
paul@152 45
paul@152 46
def to_timezone(dt, name):
paul@152 47
    try:
paul@152 48
        tz = name and timezone(name) or None
paul@152 49
    except UnknownTimeZoneError:
paul@152 50
        tz = None
paul@152 51
    if tz is not None:
paul@152 52
        if not dt.tzinfo:
paul@152 53
            return tz.localize(dt)
paul@152 54
        else:
paul@152 55
            return dt.astimezone(tz)
paul@152 56
    else:
paul@152 57
        return dt
paul@152 58
paul@152 59
def format_datetime(dt):
paul@152 60
    if not dt:
paul@152 61
        return None
paul@152 62
    elif isinstance(dt, datetime):
paul@152 63
        if dt.tzname() == "UTC":
paul@152 64
            return dt.strftime("%Y%m%dT%H%M%SZ")
paul@152 65
        else:
paul@152 66
            return dt.strftime("%Y%m%dT%H%M%S")
paul@152 67
    else:
paul@152 68
        return dt.strftime("%Y%m%d")
paul@152 69
paul@152 70
def get_datetime(value, attr=None):
paul@152 71
paul@152 72
    """
paul@152 73
    Return a datetime object from the given 'value' in iCalendar format, using
paul@152 74
    the 'attr' mapping (if specified) to control the conversion.
paul@152 75
    """
paul@152 76
paul@152 77
    if not attr or attr.get("VALUE") in (None, "DATE-TIME"):
paul@152 78
        m = match_datetime_icalendar(value)
paul@152 79
        if m:
paul@152 80
            dt = datetime(
paul@152 81
                int(m.group("year")), int(m.group("month")), int(m.group("day")),
paul@152 82
                int(m.group("hour")), int(m.group("minute")), int(m.group("second"))
paul@152 83
                )
paul@152 84
paul@152 85
            # Impose the indicated timezone.
paul@152 86
            # NOTE: This needs an ambiguity policy for DST changes.
paul@152 87
paul@152 88
            return to_timezone(dt, m.group("utc") and "UTC" or attr and attr.get("TZID") or None)
paul@152 89
paul@152 90
    if not attr or attr.get("VALUE") == "DATE":
paul@152 91
        m = match_date_icalendar(value)
paul@152 92
        if m:
paul@152 93
            return date(
paul@152 94
                int(m.group("year")), int(m.group("month")), int(m.group("day"))
paul@152 95
                )
paul@152 96
    return None
paul@152 97
paul@152 98
def get_start_of_day(dt):
paul@152 99
    return datetime(dt.year, dt.month, dt.day, 0, 0, tzinfo=dt.tzinfo)
paul@152 100
paul@152 101
# vim: tabstop=4 expandtab shiftwidth=4