Beispiel #1
0
    def getTimezone(self, tzid):
        """
        Generate a PyCalendar containing the requested timezone.
        """
        # We will just use our existing TimezoneCache here
        calendar = Calendar()
        try:
            vtz = readVTZ(tzid)
            calendar.addComponent(vtz.getComponents()[0].duplicate())
        except TimezoneException:

            # Check if an alias exists and create data for that
            if tzid in self.aliases:
                try:
                    vtz = readVTZ(self.aliases[tzid])
                except TimezoneException:
                    log.error("Failed to find timezone data for alias: %s" % (tzid,))
                    return None
                else:
                    vtz = vtz.duplicate()
                    vtz.getComponents()[0].getProperties("TZID")[0].setValue(tzid)
                    addVTZ(tzid, vtz)
                    calendar.addComponent(vtz.getComponents()[0].duplicate())
            else:
                log.error("Failed to find timezone data for: %s" % (tzid,))
                return None

        return calendar
    def getTimezone(self, tzid):
        """
        Generate a PyCalendar containing the requested timezone.
        """
        # We will just use our existing TimezoneCache here
        calendar = Calendar()
        try:
            vtz = readVTZ(tzid)
            calendar.addComponent(vtz.getComponents()[0].duplicate())
        except TimezoneException:

            # Check if an alias exists and create data for that
            if tzid in self.aliases:
                try:
                    vtz = readVTZ(self.aliases[tzid])
                except TimezoneException:
                    log.error("Failed to find timezone data for alias: %s" % (tzid,))
                    return None
                else:
                    vtz = vtz.duplicate()
                    vtz.getComponents()[0].getProperties("TZID")[0].setValue(tzid)
                    addVTZ(tzid, vtz)
                    calendar.addComponent(vtz.getComponents()[0].duplicate())
            else:
                log.error("Failed to find timezone data for: %s" % (tzid,))
                return None

        return calendar
Beispiel #3
0
    def generateZoneinfoFiles(self, outputdir, minYear, maxYear=2018, links=True, windowsAliases=None, filterzones=None):

        # Empty current directory
        try:
            for root, dirs, files in os.walk(outputdir, topdown=False):
                for name in files:
                    os.remove(os.path.join(root, name))
                for name in dirs:
                    os.rmdir(os.path.join(root, name))
        except OSError:
            pass

        for zone in self.zones.itervalues():
            if filterzones and zone.name not in filterzones:
                continue
            cal = Calendar()
            vtz = zone.vtimezone(cal, self.rules, minYear, maxYear)
            cal.addComponent(vtz)

            icsdata = cal.getText()
            fpath = os.path.join(outputdir, zone.name + ".ics")
            if not os.path.exists(os.path.dirname(fpath)):
                os.makedirs(os.path.dirname(fpath))
            with open(fpath, "w") as f:
                f.write(icsdata)
            if self.verbose:
                print("Write path: %s" % (fpath,))

        if links:
            if windowsAliases is not None:
                self.parseWindowsAliases(windowsAliases)

            link_list = []
            for linkTo, linkFrom in sorted(self.links.iteritems(), key=lambda x: x[0]):

                # Check for existing output file
                fromPath = os.path.join(outputdir, linkFrom + ".ics")
                if not os.path.exists(fromPath):
                    print("Missing link from: %s to %s" % (linkFrom, linkTo,))
                    continue

                with open(fromPath) as f:
                    icsdata = f.read()
                icsdata = icsdata.replace(linkFrom, linkTo)

                toPath = os.path.join(outputdir, linkTo + ".ics")
                if not os.path.exists(os.path.dirname(toPath)):
                    os.makedirs(os.path.dirname(toPath))
                with open(toPath, "w") as f:
                    f.write(icsdata)
                if self.verbose:
                    print("Write link: %s" % (linkTo,))

                link_list.append("%s\t%s" % (linkTo, linkFrom,))

            # Generate link mapping file
            linkPath = os.path.join(outputdir, "links.txt")
            with open(linkPath, "w") as f:
                f.write("\n".join(link_list))
Beispiel #4
0
    def getTimezoneInCalendar(tzid):
        """
        Return a VTIMEZONE inside a valid VCALENDAR
        """

        tz = TimezoneDatabase.getTimezone(tzid)
        if tz is not None:
            from pycalendar.icalendar.calendar import Calendar
            cal = Calendar()
            cal.addComponent(tz.duplicate(cal))
            return cal
        else:
            return None
Beispiel #5
0
    def getTimezoneInCalendar(tzid):
        """
        Return a VTIMEZONE inside a valid VCALENDAR
        """

        tz = TimezoneDatabase.getTimezone(tzid)
        if tz is not None:
            from pycalendar.icalendar.calendar import Calendar
            cal = Calendar()
            cal.addComponent(tz.duplicate(cal))
            return cal
        else:
            return None
Beispiel #6
0
    def vtimezones(self, minYear, maxYear=2018, filterzones=None):
        """
        Generate iCalendar data for all VTIMEZONEs or just those specified
        """

        cal = Calendar()
        for zone in self.zones.itervalues():
            if filterzones and zone.name not in filterzones:
                continue
            vtz = zone.vtimezone(cal, self.rules, minYear, maxYear)
            cal.addComponent(vtz)

        return cal.getText()
Beispiel #7
0
    def vtimezones(self, minYear, maxYear=2018, filterzones=None):
        """
        Generate iCalendar data for all VTIMEZONEs or just those specified
        """

        cal = Calendar()
        for zone in self.zones.itervalues():
            if filterzones and zone.name not in filterzones:
                continue
            vtz = zone.vtimezone(cal, self.rules, minYear, maxYear)
            cal.addComponent(vtz)

        return cal.getText()
Beispiel #8
0
class TimezoneDatabase(object):
    """
    On demand timezone database cache. This scans a TZdb directory for .ics files matching a
    TZID and caches the component data in a calendar from whence the actual component is returned.
    """

    sTimezoneDatabase = None


    @staticmethod
    def createTimezoneDatabase(dbpath):
        TimezoneDatabase.sTimezoneDatabase = TimezoneDatabase()
        TimezoneDatabase.sTimezoneDatabase.setPath(dbpath)


    @staticmethod
    def clearTimezoneDatabase():
        if TimezoneDatabase.sTimezoneDatabase is not None:
            TimezoneDatabase.sTimezoneDatabase.clear()


    def __init__(self):
        from pycalendar.icalendar.calendar import Calendar
        self.dbpath = None
        self.calendar = Calendar()
        self.tzcache = {}
        self.stdtzcache = set()


    def setPath(self, dbpath):
        self.dbpath = dbpath


    def clear(self):
        from pycalendar.icalendar.calendar import Calendar
        self.calendar = Calendar()
        self.tzcache.clear()
        self.stdtzcache.clear()


    @staticmethod
    def getTimezoneDatabase():
        if TimezoneDatabase.sTimezoneDatabase is None:
            TimezoneDatabase.sTimezoneDatabase = TimezoneDatabase()
        return TimezoneDatabase.sTimezoneDatabase


    @staticmethod
    def getTimezone(tzid):
        return TimezoneDatabase.getTimezoneDatabase()._getTimezone(tzid)


    @staticmethod
    def getTimezoneInCalendar(tzid):
        """
        Return a VTIMEZONE inside a valid VCALENDAR
        """

        tz = TimezoneDatabase.getTimezone(tzid)
        if tz is not None:
            from pycalendar.icalendar.calendar import Calendar
            cal = Calendar()
            cal.addComponent(tz.duplicate(cal))
            return cal
        else:
            return None


    @staticmethod
    def getTimezoneOffsetSeconds(tzid, dt, relative_to_utc=False):
        # Cache it first
        tz = TimezoneDatabase.getTimezone(tzid)
        if tz is not None:
            return tz.getTimezoneOffsetSeconds(dt, relative_to_utc)
        else:
            return 0


    @staticmethod
    def getTimezoneDescriptor(tzid, dt):
        # Cache it first
        tz = TimezoneDatabase.getTimezone(tzid)
        if tz is not None:
            return tz.getTimezoneDescriptor(dt)
        else:
            return ""


    @staticmethod
    def isStandardTimezone(tzid):
        return TimezoneDatabase.getTimezoneDatabase()._isStandardTimezone(tzid)


    def cacheTimezone(self, tzid):
        """
        Load the specified timezone identifier's timezone data from a file and parse it
        into the L{Calendar} used to store timezones used by this object.

        @param tzid: the timezone identifier to load
        @type tzid: L{str}
        """

        if self.dbpath is None:
            return

        tzpath = os.path.join(self.dbpath, "%s.ics" % (tzid,))
        tzpath = os.path.normpath(tzpath)
        if tzpath.startswith(self.dbpath) and os.path.isfile(tzpath):
            try:
                with open(tzpath) as f:
                    self.calendar.parseComponent(f)
            except (IOError, InvalidData):
                raise NoTimezoneInDatabase(self.dbpath, tzid)
        else:
            raise NoTimezoneInDatabase(self.dbpath, tzid)


    def addTimezone(self, tz):
        """
        Add the specified VTIMEZONE component to this object's L{Calendar} cache. This component
        is assumed to be a non-standard timezone - i.e., not loaded from the timezone database.

        @param tz: the VTIMEZONE component to add
        @type tz: L{Component}
        """
        copy = tz.duplicate(self.calendar)
        self.calendar.addComponent(copy)
        self.tzcache[copy.getID()] = copy


    def _addStandardTimezone(self, tz):
        """
        Same as L{addTimezone} except that the timezone is marked as a standard timezone. This
        is only meant to be used for testing which happens int he absence of a real standard
        timezone database.

        @param tz: the VTIMEZONE component to add
        @type tz: L{Component}
        """
        if tz.getID() not in self.tzcache:
            self.addTimezone(tz)
        self.stdtzcache.add(tz.getID())


    def _isStandardTimezone(self, tzid):
        """
        Add the specified VTIMEZONE component to this object's L{Calendar} cache. This component
        is assumed to be a non-standard timezone - i.e., not loaded from the timezone database.

        @param tzid: the timezone identifier to lookup
        @type tzid: L{str}
        """
        return tzid in self.stdtzcache


    def _getTimezone(self, tzid):
        """
        Get a timezone matching the specified timezone identifier. Use this object's
        cache - if not in the cache try to load it from a tz database file and store in
        this object's calendar.

        @param tzid: the timezone identifier to lookup
        @type tzid: L{str}
        """
        if tzid not in self.tzcache:
            tz = self.calendar.getTimezone(tzid)
            if tz is None:
                try:
                    self.cacheTimezone(tzid)
                except NoTimezoneInDatabase:
                    pass
                tz = self.calendar.getTimezone(tzid)
            self.tzcache[tzid] = tz
            if tz is not None and tzid is not None:
                self.stdtzcache.add(tzid)

        return self.tzcache[tzid]


    @staticmethod
    def mergeTimezones(cal, tzs):
        """
        Merge each timezone from other calendar.
        """

        tzdb = TimezoneDatabase.getTimezoneDatabase()

        # Not if our own calendar
        if cal is tzdb.calendar:
            return

        # Merge each timezone from other calendar
        for tz in tzs:
            tzdb.mergeTimezone(tz)


    def mergeTimezone(self, tz):
        """
        If the supplied VTIMEZONE is not in our cache then store it in memory.
        """

        if self._getTimezone(tz.getID()) is None:
            self.addTimezone(tz)
Beispiel #9
0
class TimezoneDatabase(object):
    """
    On demand timezone database cache. This scans a TZdb directory for .ics files matching a
    TZID and caches the component data in a calendar from whence the actual component is returned.
    """

    sTimezoneDatabase = None

    @staticmethod
    def createTimezoneDatabase(dbpath):
        TimezoneDatabase.sTimezoneDatabase = TimezoneDatabase()
        TimezoneDatabase.sTimezoneDatabase.setPath(dbpath)

    @staticmethod
    def clearTimezoneDatabase():
        if TimezoneDatabase.sTimezoneDatabase is not None:
            TimezoneDatabase.sTimezoneDatabase.clear()

    def __init__(self):
        from pycalendar.icalendar.calendar import Calendar
        self.dbpath = None
        self.calendar = Calendar()
        self.tzcache = {}
        self.stdtzcache = set()

    def setPath(self, dbpath):
        self.dbpath = dbpath

    def clear(self):
        from pycalendar.icalendar.calendar import Calendar
        self.calendar = Calendar()
        self.tzcache.clear()
        self.stdtzcache.clear()

    @staticmethod
    def getTimezoneDatabase():
        if TimezoneDatabase.sTimezoneDatabase is None:
            TimezoneDatabase.sTimezoneDatabase = TimezoneDatabase()
        return TimezoneDatabase.sTimezoneDatabase

    @staticmethod
    def getTimezone(tzid):
        return TimezoneDatabase.getTimezoneDatabase()._getTimezone(tzid)

    @staticmethod
    def getTimezoneInCalendar(tzid):
        """
        Return a VTIMEZONE inside a valid VCALENDAR
        """

        tz = TimezoneDatabase.getTimezone(tzid)
        if tz is not None:
            from pycalendar.icalendar.calendar import Calendar
            cal = Calendar()
            cal.addComponent(tz.duplicate(cal))
            return cal
        else:
            return None

    @staticmethod
    def getTimezoneOffsetSeconds(tzid, dt, relative_to_utc=False):
        # Cache it first
        tz = TimezoneDatabase.getTimezone(tzid)
        if tz is not None:
            return tz.getTimezoneOffsetSeconds(dt, relative_to_utc)
        else:
            return 0

    @staticmethod
    def getTimezoneDescriptor(tzid, dt):
        # Cache it first
        tz = TimezoneDatabase.getTimezone(tzid)
        if tz is not None:
            return tz.getTimezoneDescriptor(dt)
        else:
            return ""

    @staticmethod
    def isStandardTimezone(tzid):
        return TimezoneDatabase.getTimezoneDatabase()._isStandardTimezone(tzid)

    def cacheTimezone(self, tzid):
        """
        Load the specified timezone identifier's timezone data from a file and parse it
        into the L{Calendar} used to store timezones used by this object.

        @param tzid: the timezone identifier to load
        @type tzid: L{str}
        """

        if self.dbpath is None:
            return

        tzpath = os.path.join(self.dbpath, "%s.ics" % (tzid, ))
        tzpath = os.path.normpath(tzpath)
        if tzpath.startswith(self.dbpath) and os.path.isfile(tzpath):
            try:
                with open(tzpath) as f:
                    self.calendar.parseComponent(f)
            except (IOError, InvalidData):
                raise NoTimezoneInDatabase(self.dbpath, tzid)
        else:
            raise NoTimezoneInDatabase(self.dbpath, tzid)

    def addTimezone(self, tz):
        """
        Add the specified VTIMEZONE component to this object's L{Calendar} cache. This component
        is assumed to be a non-standard timezone - i.e., not loaded from the timezone database.

        @param tz: the VTIMEZONE component to add
        @type tz: L{Component}
        """
        copy = tz.duplicate(self.calendar)
        self.calendar.addComponent(copy)
        self.tzcache[copy.getID()] = copy

    def _addStandardTimezone(self, tz):
        """
        Same as L{addTimezone} except that the timezone is marked as a standard timezone. This
        is only meant to be used for testing which happens int he absence of a real standard
        timezone database.

        @param tz: the VTIMEZONE component to add
        @type tz: L{Component}
        """
        if tz.getID() not in self.tzcache:
            self.addTimezone(tz)
        self.stdtzcache.add(tz.getID())

    def _isStandardTimezone(self, tzid):
        """
        Add the specified VTIMEZONE component to this object's L{Calendar} cache. This component
        is assumed to be a non-standard timezone - i.e., not loaded from the timezone database.

        @param tzid: the timezone identifier to lookup
        @type tzid: L{str}
        """
        return tzid in self.stdtzcache

    def _getTimezone(self, tzid):
        """
        Get a timezone matching the specified timezone identifier. Use this object's
        cache - if not in the cache try to load it from a tz database file and store in
        this object's calendar.

        @param tzid: the timezone identifier to lookup
        @type tzid: L{str}
        """
        if tzid not in self.tzcache:
            tz = self.calendar.getTimezone(tzid)
            if tz is None:
                try:
                    self.cacheTimezone(tzid)
                except NoTimezoneInDatabase:
                    pass
                tz = self.calendar.getTimezone(tzid)
            self.tzcache[tzid] = tz
            if tz is not None and tzid is not None:
                self.stdtzcache.add(tzid)

        return self.tzcache[tzid]

    @staticmethod
    def mergeTimezones(cal, tzs):
        """
        Merge each timezone from other calendar.
        """

        tzdb = TimezoneDatabase.getTimezoneDatabase()

        # Not if our own calendar
        if cal is tzdb.calendar:
            return

        # Merge each timezone from other calendar
        for tz in tzs:
            tzdb.mergeTimezone(tz)

    def mergeTimezone(self, tz):
        """
        If the supplied VTIMEZONE is not in our cache then store it in memory.
        """

        if self._getTimezone(tz.getID()) is None:
            self.addTimezone(tz)
Beispiel #10
0
    def generateZoneinfoFiles(self,
                              outputdir,
                              minYear,
                              maxYear=2018,
                              links=True,
                              windowsAliases=None,
                              filterzones=None):

        # Empty current directory
        try:
            for root, dirs, files in os.walk(outputdir, topdown=False):
                for name in files:
                    os.remove(os.path.join(root, name))
                for name in dirs:
                    os.rmdir(os.path.join(root, name))
        except OSError:
            pass

        for zone in self.zones.itervalues():
            if filterzones and zone.name not in filterzones:
                continue
            cal = Calendar()
            vtz = zone.vtimezone(cal, self.rules, minYear, maxYear)
            cal.addComponent(vtz)

            icsdata = cal.getText()
            fpath = os.path.join(outputdir, zone.name + ".ics")
            if not os.path.exists(os.path.dirname(fpath)):
                os.makedirs(os.path.dirname(fpath))
            with open(fpath, "w") as f:
                f.write(icsdata)
            if self.verbose:
                print("Write path: %s" % (fpath, ))

        if links:
            if windowsAliases is not None:
                self.parseWindowsAliases(windowsAliases)

            link_list = []
            for linkTo, linkFrom in sorted(self.links.iteritems(),
                                           key=lambda x: x[0]):

                # Check for existing output file
                fromPath = os.path.join(outputdir, linkFrom + ".ics")
                if not os.path.exists(fromPath):
                    print("Missing link from: %s to %s" % (
                        linkFrom,
                        linkTo,
                    ))
                    continue

                with open(fromPath) as f:
                    icsdata = f.read()
                icsdata = icsdata.replace(linkFrom, linkTo)

                toPath = os.path.join(outputdir, linkTo + ".ics")
                if not os.path.exists(os.path.dirname(toPath)):
                    os.makedirs(os.path.dirname(toPath))
                with open(toPath, "w") as f:
                    f.write(icsdata)
                if self.verbose:
                    print("Write link: %s" % (linkTo, ))

                link_list.append("%s\t%s" % (
                    linkTo,
                    linkFrom,
                ))

            # Generate link mapping file
            linkPath = os.path.join(outputdir, "links.txt")
            with open(linkPath, "w") as f:
                f.write("\n".join(link_list))