date-parsing.rst 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. .. _advanced.date:
  2. Date Parsing
  3. ============
  4. Different feed types and versions use wildly different date formats.
  5. :program:`Universal Feed Parser` will attempt to auto-detect the date format
  6. used in any date element, and parse it into a standard :program:`Python`
  7. 9-tuple, as documented in `the Python time module <http://docs.python.org/lib/module-time.html>`_.
  8. The following elements are parsed as dates:
  9. - :ref:`reference.feed.updated` is parsed into :ref:`reference.feed.updated_parsed`.
  10. - :ref:`reference.entry.published` is parsed into :ref:`reference.entry.published_parsed`.
  11. - :ref:`reference.entry.updated` is parsed into :ref:`reference.entry.updated_parsed`.
  12. - :ref:`reference.entry.created` is parsed into :ref:`reference.entry.created_parsed`.
  13. - :ref:`reference.entry.expired` is parsed into :ref:`reference.entry.expired_parsed`.
  14. History of Date Formats
  15. -----------------------
  16. Here is a brief history of feed date formats:
  17. - :abbr:`CDF (Channel Definition Format)` states that all date values must
  18. conform to ISO 8601:1988. ISO 8601:1988 is not a freely
  19. available specification, but a brief (non-normative) description of the date
  20. formats it describes is available here: `ISO 8601:1988 Date/Time Representations <http://hydracen.com/dx/iso8601.htm>`_.
  21. - :abbr:`RSS (Rich Site Summary)` 0.90 has no date elements.
  22. - Netscape :abbr:`RSS (Rich Site Summary)` 0.91 does not specify a date format,
  23. but examples within the specification show :abbr:`RFC (Request For Comments)`
  24. 822-style dates with 4-digit years.
  25. - Userland :abbr:`RSS (Rich Site Summary)` 0.91 states, "All date-times in
  26. :abbr:`RSS (Rich Site Summary)` conform to the Date and Time Specification of
  27. :abbr:`RFC (Request For Comments)` 822." `RFC 822 <http://www.ietf.org/rfc/rfc822.txt>`_
  28. mandates 2-digit years; it does not allow 4-digit years.
  29. - :abbr:`RSS (Rich Site Summary)` 1.0 states that all date elements must
  30. conform to `W3CDTF <http://www.w3.org/TR/NOTE-datetime>`_,
  31. which is a profile of ISO 8601:1988.
  32. - :abbr:`RSS (Rich Site Summary)` 2.0 states, "All date-times in :abbr:`RSS (Rich Site Summary)` conform to the Date and Time Specification of RFC 822, with the exception that the year may be expressed with two characters or four characters (four preferred)."
  33. - Atom 0.3 states that all date elements must conform to
  34. `W3CDTF <http://www.w3.org/TR/NOTE-datetime>`_.
  35. - Atom 1.0 states that all date elements "MUST conform to the date-time
  36. production in `RFC 3339 <http://www.ietf.org/rfc/rfc3339.txt>`_.
  37. In addition, an uppercase T character MUST be used to separate date and time,
  38. and an uppercase Z character MUST be present in the absence of a numeric time
  39. zone offset."
  40. Recognized Date Formats
  41. -----------------------
  42. Here is a representative list of the formats that :program:`Universal Feed
  43. Parser` can recognize in any date element:
  44. Recognized Date Formats
  45. ============================================ ================================= =====================================
  46. Description Example Parsed Value
  47. ============================================ ================================= =====================================
  48. valid RFC 822 (2-digit year) Thu, 01 Jan 04 19:48:21 GMT (2004, 1, 1, 19, 48, 21, 3, 1, 0)
  49. valid RFC 822 (4-digit year) Thu, 01 Jan 2004 19:48:21 GMT (2004, 1, 1, 19, 48, 21, 3, 1, 0)
  50. invalid RFC 822 (no time) 01 Jan 2004 (2004, 1, 1, 0, 0, 0, 3, 1, 0)
  51. invalid RFC 822 (no seconds) 01 Jan 2004 00:00 GMT (2004, 1, 1, 0, 0, 0, 3, 1, 0)
  52. valid W3CDTF (numeric timezone) 2003-12-31T10:14:55-08:00 (2003, 12, 31, 18, 14, 55, 2, 365, 0)
  53. valid W3CDTF (UTC timezone) 2003-12-31T10:14:55Z (2003, 12, 31, 10, 14, 55, 2, 365, 0)
  54. valid W3CDTF (yyyy) 2003 (2003, 1, 1, 0, 0, 0, 2, 1, 0)
  55. valid W3CDTF (yyyy-mm) 2003-12 (2003, 12, 1, 0, 0, 0, 0, 335, 0)
  56. valid W3CDTF (yyyy-mm-dd) 2003-12-31 (2003, 12, 31, 0, 0, 0, 2, 365, 0)
  57. valid ISO 8601 (yyyymmdd) 20031231 (2003, 12, 31, 0, 0, 0, 2, 365, 0)
  58. valid ISO 8601 (-yy-mm) -03-12 (2003, 12, 1, 0, 0, 0, 0, 335, 0)
  59. valid ISO 8601 (-yymm) -0312 (2003, 12, 1, 0, 0, 0, 0, 335, 0)
  60. valid ISO 8601 (-yy-mm-dd) -03-12-31 (2003, 12, 31, 0, 0, 0, 2, 365, 0)
  61. valid ISO 8601 (yymmdd) 031231 (2003, 12, 31, 0, 0, 0, 2, 365, 0)
  62. valid ISO 8601 (yyyy-o) 2003-335 (2003, 12, 1, 0, 0, 0, 0, 335, 0)
  63. valid ISO 8601 (yyo) 03335 (2003, 12, 1, 0, 0, 0, 0, 335, 0)
  64. valid asctime Sun Jan 4 16:29:06 PST 2004 (2004, 1, 5, 0, 29, 6, 0, 5, 0)
  65. bogus RFC 822 (invalid day/month) Thu, 31 Jun 2004 19:48:21 GMT (2004, 7, 1, 19, 48, 21, 3, 183, 0)
  66. bogus RFC 822 (invalid month) Mon, 26 January 2004 16:31:00 EST (2004, 1, 26, 21, 31, 0, 0, 26, 0)
  67. bogus RFC 822 (invalid timezone) Mon, 26 Jan 2004 16:31:00 ET (2004, 1, 26, 21, 31, 0, 0, 26, 0)
  68. bogus W3CDTF (invalid hour) 2003-12-31T25:14:55Z (2004, 1, 1, 1, 14, 55, 3, 1, 0)
  69. bogus W3CDTF (invalid minute) 2003-12-31T10:61:55Z (2003, 12, 31, 11, 1, 55, 2, 365, 0)
  70. bogus W3CDTF (invalid second) 2003-12-31T10:14:61Z (2003, 12, 31, 10, 15, 1, 2, 365, 0)
  71. bogus (MSSQL) 2004-07-08 23:56:58.0 (2004, 7, 8, 14, 56, 58, 3, 190, 0)
  72. bogus (MSSQL-ish, without fractional second) 2004-07-08 23:56:58 (2004, 7, 8, 14, 56, 58, 3, 190, 0)
  73. bogus (Korean) 2004-05-25 오 11:23:17 (2004, 5, 25, 14, 23, 17, 1, 146, 0)
  74. bogus (Greek) Κυρ, 11 Ιούλ 2004 12:00:00 EST (2004, 7, 11, 17, 0, 0, 6, 193, 0)
  75. bogus (Hungarian) július-13T9:15-05:00 (2004, 7, 13, 14, 15, 0, 1, 195, 0)
  76. ============================================ ================================= =====================================
  77. :program:`Universal Feed Parser` recognizes all character-based timezone
  78. abbreviations defined in :abbr:`RFC (Request For Comments)` 822. In addition,
  79. :program:`Universal Feed Parser` recognizes the following invalid timezones:
  80. - ``AT`` is treated as ``AST``
  81. - ``ET`` is treated as ``EST``
  82. - ``CT`` is treated as ``CST``
  83. - ``MT`` is treated as ``MST``
  84. - ``PT`` is treated as ``PST``
  85. Supporting Additional Date Formats
  86. ----------------------------------
  87. :program:`Universal Feed Parser` supports many different date formats, but
  88. there are probably many more in the wild that are still unsupported. If you
  89. find other date formats, you can support them by registering them with
  90. ``registerDateHandler``. It takes a single argument, a callback function. The
  91. callback function should take a single argument, a string, and return a single
  92. value, a 9-tuple :program:`Python` date in UTC.
  93. Registering a third-party date handler
  94. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  95. ::
  96. import feedparser
  97. import re
  98. _my_date_pattern = re.compile(
  99. r'(\d{,2})/(\d{,2})/(\d{4}) (\d{,2}):(\d{2}):(\d{2})')
  100. def myDateHandler(aDateString):
  101. """parse a UTC date in MM/DD/YYYY HH:MM:SS format"""
  102. month, day, year, hour, minute, second = \
  103. _my_date_pattern.search(aDateString).groups()
  104. return (int(year), int(month), int(day), \
  105. int(hour), int(minute), int(second), 0, 0, 0)
  106. feedparser.registerDateHandler(myDateHandler)
  107. d = feedparser.parse(...)
  108. Your newly-registered date handler will be tried before all the other date
  109. handlers built into :program:`Universal Feed Parser`. (More specifically, all
  110. date handlers are tried in "last in, first out" order; i.e. the last handler to
  111. be registered is the first one tried, and so on in reverse order of
  112. registration.)
  113. If your date handler returns ``None``, or anything other than a
  114. :program:`Python` 9-tuple date, or raises an exception of any kind, the error
  115. will be silently ignored and the other registered date handlers will be tried
  116. in order. If no date handlers succeed, then the date is not parsed, and the
  117. \*_parsed value will not be present in the results dictionary. The original
  118. date string will still be available in the appropriate element in the results
  119. dictionary.
  120. .. tip::
  121. If you write a new date handler, you are encouraged (but not required) to
  122. `submit a patch <http://sourceforge.net/projects/feedparser/>`_ so it can be
  123. integrated into the next version of :program:`Universal Feed Parser`.