EventAggregator

Change of EventAggregatorSupport.py

93:3b719c63fd17
EventAggregatorSupport.py
     1.1 --- a/EventAggregatorSupport.py	Sun Mar 14 02:32:51 2010 +0100
     1.2 +++ b/EventAggregatorSupport.py	Sun Mar 14 21:06:15 2010 +0100
     1.3 @@ -45,12 +45,12 @@
     1.4  
     1.5  # Value parsing.
     1.6  
     1.7 -country_code_regexp = re.compile(ur'(?:^|\s)(?P<code>[A-Z]{2})(?:$|\s)', re.UNICODE)
     1.8 +country_code_regexp = re.compile(ur'(?:^|\W)(?P<code>[A-Z]{2})(?:$|\W+$)', re.UNICODE)
     1.9  
    1.10  month_regexp_str = ur'(?P<year>[0-9]{4})-(?P<month>[0-9]{2})'
    1.11  date_regexp_str = ur'(?P<year>[0-9]{4})-(?P<month>[0-9]{2})-(?P<day>[0-9]{2})'
    1.12  time_regexp_str = ur'(?P<hour>[0-2][0-9]):(?P<minute>[0-5][0-9])(?::(?P<second>[0-6][0-9]))?'
    1.13 -timezone_regexp_str = ur'(?P<zone>[A-Z]{3,}|[a-zA-Z]+/[-_a-zA-Z]+)'
    1.14 +timezone_regexp_str = ur'(?P<zone>[A-Z]{3,}|[a-zA-Z]+/[-_a-zA-Z]+|[-+][0-9]{1,4})'
    1.15  datetime_regexp_str = date_regexp_str + ur'(?:\s+' + time_regexp_str + ur'(?:\s+' + timezone_regexp_str + ur')?)?'
    1.16  
    1.17  month_regexp = re.compile(month_regexp_str, re.UNICODE)
    1.18 @@ -828,6 +828,9 @@
    1.19      def __str__(self):
    1.20          return "%04d-%02d" % self.as_tuple()[:2]
    1.21  
    1.22 +    def as_datetime(self, day, hour, minute, second, zone):
    1.23 +        return DateTime(self.as_tuple() + (day, hour, minute, second, zone))
    1.24 +
    1.25      def as_date(self, day):
    1.26          return Date(self.as_tuple() + (day,))
    1.27  
    1.28 @@ -911,6 +914,9 @@
    1.29      def __str__(self):
    1.30          return "%04d-%02d-%02d" % self.as_tuple()[:3]
    1.31  
    1.32 +    def as_datetime(self, hour, minute, second, zone):
    1.33 +        return DateTime(self.as_tuple() + (hour, minute, second, zone))
    1.34 +
    1.35      def as_date(self):
    1.36          return self
    1.37  
    1.38 @@ -960,7 +966,6 @@
    1.39  
    1.40      def __init__(self, data):
    1.41          Date.__init__(self, data)
    1.42 -        self.utc_offset = None
    1.43  
    1.44      def __str__(self):
    1.45          if self.has_time():
    1.46 @@ -975,6 +980,9 @@
    1.47  
    1.48          return Date.__str__(self) + time_str
    1.49  
    1.50 +    def as_datetime(self):
    1.51 +        return self
    1.52 +
    1.53      def as_date(self):
    1.54          return Date(self.data[:3])
    1.55  
    1.56 @@ -987,9 +995,8 @@
    1.57      def time_zone(self):
    1.58          return self.data[6]
    1.59  
    1.60 -    def set_time_zone(self, value, utc_offset=None):
    1.61 +    def set_time_zone(self, value):
    1.62          self.data[6] = value
    1.63 -        self.utc_offset = utc_offset
    1.64  
    1.65      def padded(self):
    1.66  
    1.67 @@ -998,53 +1005,139 @@
    1.68          data = map(lambda x: x or 0, self.data[:6]) + self.data[6:]
    1.69          return DateTime(data)
    1.70  
    1.71 +    def to_utc(self):
    1.72 +
    1.73 +        """
    1.74 +        Return this object converted to UTC, or None if such a conversion is not
    1.75 +        defined.
    1.76 +        """
    1.77 +
    1.78 +        offset = self.utc_offset()
    1.79 +        if offset:
    1.80 +            hours, minutes = offset
    1.81 +
    1.82 +            # Invert the offset to get the correction.
    1.83 +
    1.84 +            hours, minutes = -hours, -minutes
    1.85 +
    1.86 +            # Get the components.
    1.87 +
    1.88 +            hour, minute, second, zone = self.as_tuple()[3:]
    1.89 +            date = self.as_date()
    1.90 +
    1.91 +            # Add the minutes and hours.
    1.92 +
    1.93 +            minute += minutes
    1.94 +            if minute < 0:
    1.95 +                hour -= 1
    1.96 +                minute += 60
    1.97 +            elif minute > 59:
    1.98 +                hour += 1
    1.99 +                minute -= 60
   1.100 +
   1.101 +            hour += hours
   1.102 +            if hour < 0:
   1.103 +                date = date.previous_day()
   1.104 +                hour += 24
   1.105 +            elif hour > 23:
   1.106 +                date = date.next_day()
   1.107 +                hour -= 24
   1.108 +
   1.109 +            return date.as_datetime(hour, minute, second, "UTC")
   1.110 +        else:
   1.111 +            return None
   1.112 +
   1.113 +    def utc_offset(self):
   1.114 +
   1.115 +        "Return the UTC offset in hours and minutes."
   1.116 +
   1.117 +        zone = self.time_zone()
   1.118 +
   1.119 +        # Only attempt to return a UTC offset where an explicit offset has been
   1.120 +        # set.
   1.121 +
   1.122 +        if zone and zone[0] in "-+":
   1.123 +            digits = zone[1:]
   1.124 +            if zone[0] == "-":
   1.125 +                sign = -1
   1.126 +            else:
   1.127 +                sign = 1
   1.128 +
   1.129 +            if 1 <= len(digits) <= 2:
   1.130 +                return int(digits) * sign, 0
   1.131 +            elif len(digits) == 3:
   1.132 +                hours = int(digits[:1]) * sign
   1.133 +                minutes = int(digits[1:]) * sign
   1.134 +                return hours, minutes
   1.135 +            elif len(digits) == 4:
   1.136 +                hours = int(digits[:2]) * sign
   1.137 +                minutes = int(digits[2:]) * sign
   1.138 +                return hours, minutes
   1.139 +
   1.140 +        return None
   1.141 +
   1.142      def apply_location(self, location):
   1.143  
   1.144          """
   1.145 -        Apply 'location' information, setting the time zone if none is already
   1.146 -        set.
   1.147 +        Apply 'location' information, setting the time zone if none has already
   1.148 +        been set.
   1.149          """
   1.150  
   1.151          if not self.time_zone():
   1.152 -
   1.153 -            # Only try and set a time zone if pytz is present and able to
   1.154 -            # suggest one.
   1.155 +            zone = getTimeZone(location)
   1.156 +            if zone:
   1.157 +                self.set_time_zone(zone)
   1.158  
   1.159 -            if pytz is not None:
   1.160 +def getTimeZone(location):
   1.161  
   1.162 -                # Find a country code in the location.
   1.163 +    "Find a time zone for the specified 'location'."
   1.164 +
   1.165 +    # Only try and find a time zone if pytz is present and able to suggest one.
   1.166  
   1.167 -                match = country_code_regexp.search(location)
   1.168 +    if pytz is None:
   1.169 +        return None
   1.170  
   1.171 -                if match:
   1.172 +    code = getCountry(location)
   1.173  
   1.174 -                    # Attempt to discover zones for that country.
   1.175 +    if code is None:
   1.176 +        return None
   1.177  
   1.178 -                    try:
   1.179 -                        zones = pytz.country_timezones(match.group("code"))
   1.180 +    try:
   1.181 +        zones = pytz.country_timezones(code)
   1.182 +    except KeyError:
   1.183 +        return None
   1.184  
   1.185 -                        # Unambiguous choice of zone.
   1.186 +    # No zones...
   1.187  
   1.188 -                        if len(zones) == 1:
   1.189 -                            self.set_time_zone(zones[0], pytz.timezone(zones[0]).utcoffset(None))
   1.190 +    if not zones:
   1.191 +        return None
   1.192 +
   1.193 +    # Many potential zones.
   1.194  
   1.195 -                        # Many potential zones.
   1.196 +    if len(zones) > 1:
   1.197 +        for zone in zones:
   1.198 +            continent, city = zone.split("/")
   1.199  
   1.200 -                        elif len(zones) > 1:
   1.201 -                            for zone in zones:
   1.202 -                                continent, city = zone.split("/")
   1.203 +            # If the specific city is mentioned, choose the
   1.204 +            # zone.
   1.205 +
   1.206 +            if location.find(city) != -1:
   1.207 +                return zone
   1.208  
   1.209 -                                # If the specific city is mentioned, choose the
   1.210 -                                # zone.
   1.211 +    # Otherwise choose the first or only zone.
   1.212 +
   1.213 +    return zones[0]
   1.214 +
   1.215 +def getCountry(s):
   1.216  
   1.217 -                                if location.find(city) != -1:
   1.218 -                                    self.set_time_zone(zone, pytz.timezone(zone).utcoffset(None))
   1.219 -                                    break
   1.220 -                            else:
   1.221 -                                self.set_time_zone(zones[0], pytz.timezone(zones[0]).utcoffset(None))
   1.222 +    "Find a country code in the given string 's'."
   1.223 +
   1.224 +    match = country_code_regexp.search(s)
   1.225  
   1.226 -                    except KeyError:
   1.227 -                        pass
   1.228 +    if match:
   1.229 +        return match.group("code")
   1.230 +    else:
   1.231 +        return None
   1.232  
   1.233  def getDate(s):
   1.234