Format: text/x-python
⬇ Download File (4.4 KB)
   1  # Copyright 2010-2023 Kurt McKee <contactme@kurtmckee.org>
   2  # Copyright 2002-2008 Mark Pilgrim
   3  # All rights reserved.
   4  #
   5  # This file is a part of feedparser.
   6  #
   7  # Redistribution and use in source and binary forms, with or without
   8  # modification, are permitted provided that the following conditions are met:
   9  #
  10  # * Redistributions of source code must retain the above copyright notice,
  11  #   this list of conditions and the following disclaimer.
  12  # * Redistributions in binary form must reproduce the above copyright notice,
  13  #   this list of conditions and the following disclaimer in the documentation
  14  #   and/or other materials provided with the distribution.
  15  #
  16  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
  17  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19  # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  20  # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  21  # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  22  # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  23  # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  24  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  25  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  26  # POSSIBILITY OF SUCH DAMAGE.
  27  
  28  import datetime
  29  
  30  timezonenames = {
  31      'ut': 0, 'gmt': 0, 'z': 0,
  32      'adt': -3, 'ast': -4, 'at': -4,
  33      'edt': -4, 'est': -5, 'et': -5,
  34      'cdt': -5, 'cst': -6, 'ct': -6,
  35      'mdt': -6, 'mst': -7, 'mt': -7,
  36      'pdt': -7, 'pst': -8, 'pt': -8,
  37      'a': -1, 'n': 1,
  38      'm': -12, 'y': 12,
  39  }
  40  # W3 date and time format parser
  41  # http://www.w3.org/TR/NOTE-datetime
  42  # Also supports MSSQL-style datetimes as defined at:
  43  # http://msdn.microsoft.com/en-us/library/ms186724.aspx
  44  # (basically, allow a space as a date/time/timezone separator)
  45  
  46  
  47  def _parse_date_w3dtf(datestr):
  48      if not datestr.strip():
  49          return None
  50      parts = datestr.lower().split('t')
  51      if len(parts) == 1:
  52          # This may be a date only, or may be an MSSQL-style date
  53          parts = parts[0].split()
  54          if len(parts) == 1:
  55              # Treat this as a date only
  56              parts.append('00:00:00z')
  57      elif len(parts) > 2:
  58          return None
  59      date = parts[0].split('-', 2)
  60      if not date or len(date[0]) != 4:
  61          return None
  62      # Ensure that `date` has 3 elements. Using '1' sets the default
  63      # month to January and the default day to the 1st of the month.
  64      date.extend(['1'] * (3 - len(date)))
  65      try:
  66          year, month, day = [int(i) for i in date]
  67      except ValueError:
  68          # `date` may have more than 3 elements or may contain
  69          # non-integer strings.
  70          return None
  71      if parts[1].endswith('z'):
  72          parts[1] = parts[1][:-1]
  73          parts.append('z')
  74      # Append the numeric timezone offset, if any, to parts.
  75      # If this is an MSSQL-style date then parts[2] already contains
  76      # the timezone information, so `append()` will not affect it.
  77      # Add 1 to each value so that if `find()` returns -1 it will be
  78      # treated as False.
  79      loc = parts[1].find('-') + 1 or parts[1].find('+') + 1 or len(parts[1]) + 1
  80      loc = loc - 1
  81      parts.append(parts[1][loc:])
  82      parts[1] = parts[1][:loc]
  83      time = parts[1].split(':', 2)
  84      # Ensure that time has 3 elements. Using '0' means that the
  85      # minutes and seconds, if missing, will default to 0.
  86      time.extend(['0'] * (3 - len(time)))
  87      if parts[2][:1] in ('-', '+'):
  88          try:
  89              tzhour = int(parts[2][1:3])
  90              tzmin = int(parts[2][4:])
  91          except ValueError:
  92              return None
  93          if parts[2].startswith('-'):
  94              tzhour = tzhour * -1
  95              tzmin = tzmin * -1
  96      else:
  97          tzhour = timezonenames.get(parts[2], 0)
  98          tzmin = 0
  99      try:
 100          hour, minute, second = [int(float(i)) for i in time]
 101      except ValueError:
 102          return None
 103      # Create the datetime object and timezone delta objects
 104      try:
 105          stamp = datetime.datetime(year, month, day, hour, minute, second)
 106      except ValueError:
 107          return None
 108      delta = datetime.timedelta(0, 0, 0, 0, tzmin, tzhour)
 109      # Return the date and timestamp in a UTC 9-tuple
 110      try:
 111          return (stamp - delta).utctimetuple()
 112      except (OverflowError, ValueError):
 113          # IronPython throws ValueErrors instead of OverflowErrors
 114          return None
 115