{"id":246,"library":"python-dateutil","title":"python-dateutil","description":"python-dateutil provides powerful extensions to Python's standard datetime module, including flexible date/time string parsing, relative delta arithmetic, recurrence rules (RFC 2445 superset), and rich timezone support via tzfile, TZ strings, and Windows registry. Current version is 2.9.0.post0 (released 2024-03-01). The project is considered functionally stable but upstream activity is slow; Fedora has flagged it as unmaintained. The PyPI install name (python-dateutil) differs from the importable name (dateutil).","status":"maintenance","version":"2.9.0.post0","language":"python","source_language":"en","source_url":"https://github.com/dateutil/dateutil","tags":["datetime","date-parsing","timezone","relativedelta","rrule","time"],"install":[{"cmd":"pip install python-dateutil","lang":"bash","label":"pip"}],"dependencies":[{"reason":"Python 2/3 compatibility shim; still a hard runtime dependency in 2.9.x even on Python 3","package":"six","optional":false},{"reason":"IANA timezone database on platforms without /usr/share/zoneinfo (e.g. Windows); needed for dateutil.tz.gettz() to resolve IANA names reliably","package":"tzdata","optional":true}],"imports":[{"note":"Always import the submodule explicitly for clarity. The top-level lazy-import shortcut (PEP 562, added in 2.9.0) only works on Python 3.7+.","wrong":"import dateutil; dateutil.parser.parse('2024-01-15')  # works on 3.7+ via lazy import but not guaranteed in all environments","symbol":"parser.parse","correct":"from dateutil import parser; parser.parse('2024-01-15')"},{"note":"Use isoparse() for strict ISO 8601 strings instead of parse(); parse() is more permissive and may silently misinterpret ambiguous ISO strings.","symbol":"parser.isoparse","correct":"from dateutil.parser import isoparse"},{"note":"Wildcard import pulls in weekday constants (MO, TU, ...) that can shadow calendar/rrule symbols; prefer explicit import.","wrong":"from dateutil.relativedelta import *","symbol":"relativedelta","correct":"from dateutil.relativedelta import relativedelta"},{"note":"Frequency constants (DAILY, WEEKLY, etc.) must be imported from dateutil.rrule; they are not available at the top-level dateutil namespace.","symbol":"rrule / DAILY / WEEKLY / MONTHLY / YEARLY","correct":"from dateutil.rrule import rrule, DAILY, WEEKLY, MONTHLY, YEARLY, rruleset"},{"note":"gettz() returns None (not an exception) when the timezone name is unrecognized — always check for None before using the result.","symbol":"gettz","correct":"from dateutil.tz import gettz, tzutc, tzlocal"},{"note":"Since 2.8.1 parse() raises ParserError (a ValueError subclass) on failure. Catching only ValueError still works but catching ParserError is more precise.","wrong":"except ValueError","symbol":"ParserError","correct":"from dateutil.parser import ParserError"}],"quickstart":{"code":"from datetime import datetime\nfrom dateutil import parser\nfrom dateutil.relativedelta import relativedelta\nfrom dateutil.tz import gettz, tzutc\n\n# 1. Flexible string parsing\ndt = parser.parse(\"March 15, 2024 3:30 PM\")\nprint(\"Parsed:\", dt)\n\n# 2. ISO 8601 with timezone\ndt_aware = parser.isoparse(\"2024-03-15T15:30:00+05:30\")\nprint(\"ISO aware:\", dt_aware)\n\n# 3. Relative delta arithmetic (month-aware)\nnow = datetime(2024, 1, 31, tzinfo=tzutc())\none_month_later = now + relativedelta(months=1)\nprint(\"One month later:\", one_month_later)  # 2024-02-29 (leap year)\n\n# 4. Timezone-aware datetime\nnyc = gettz(\"America/New_York\")\nif nyc is None:\n    raise RuntimeError(\"Could not resolve timezone; install tzdata package\")\ndt_nyc = datetime(2024, 3, 15, 12, 0, tzinfo=nyc)\nprint(\"NYC time:\", dt_nyc)\n\n# 5. Ambiguous date: always set dayfirst/yearfirst explicitly\nambiguous = parser.parse(\"04/05/2024\", dayfirst=False)  # May 4\nprint(\"MM/DD:\", ambiguous.date())\n","lang":"python","description":"Demonstrates flexible string parsing, isoparse, relativedelta month arithmetic, timezone handling with gettz, and explicit dayfirst flag for ambiguous dates."},"warnings":[{"fix":"Always pass dayfirst=True for DD/MM/YYYY input, or use isoparse() for unambiguous ISO 8601 strings.","message":"parser.parse() silently guesses ambiguous dates like '04/05/2024' using dayfirst=False (MM/DD) by default. Non-US date strings will be parsed incorrectly unless dayfirst=True is set explicitly.","severity":"gotcha","affected_versions":"all"},{"fix":"Check dt.tzinfo after parsing, or pass a default timezone via the tzinfos parameter, or use dateutil.tz.tzutc() to attach UTC explicitly.","message":"parser.parse() returns a timezone-naive datetime when no timezone is present in the input string, which can silently cause incorrect comparisons with aware datetimes.","severity":"gotcha","affected_versions":"all"},{"fix":"Catch ParserError for precision: from dateutil.parser import ParserError; except ParserError: ...","message":"Since 2.8.1 parse() raises dateutil.parser.ParserError (a ValueError subclass) instead of plain ValueError. Code catching ValueError still works, but catching only the base Exception may need updating.","severity":"breaking","affected_versions":">=2.8.1"},{"fix":"Use fuzzy=False (default) or fuzzy_with_tokens=True and inspect the ignored tokens tuple to validate what was consumed.","message":"fuzzy=True parsing can silently extract numbers from arbitrary strings as date components (e.g. parse('lbl2vec at 7pm', fuzzy=True) extracts '2' as a day). This makes fuzzy parsing unsafe for untrusted or unexpected input.","severity":"gotcha","affected_versions":"all"},{"fix":"To include dtstart unconditionally, use rruleset and add dtstart with ruleset.rdate(dtstart).","message":"rrule dtstart is NOT included as the first occurrence unless it independently satisfies the recurrence rule — this diverges from RFC 2445 behavior.","severity":"gotcha","affected_versions":"all"},{"fix":"Always assert the result: tz = gettz('America/New_York'); assert tz is not None. Install tzdata package on Windows/Docker environments.","message":"gettz() returns None silently when a timezone name cannot be resolved (e.g. on Windows without the tzdata package installed). Passing None as tzinfo produces a naive datetime without error.","severity":"gotcha","affected_versions":"all"},{"fix":"For pure timezone handling on Python 3.9+, prefer zoneinfo.ZoneInfo from the stdlib. For relativedelta on Python 3, evaluate whether stdlib timedelta suffices for your use case.","message":"The project still ships the six compatibility shim as a hard dependency. Fedora has flagged the project as effectively unmaintained upstream with possible unaddressed security issues. New greenfield projects should consider zoneinfo (Python 3.9+ stdlib) + dateutil only for relativedelta/rrule features.","severity":"deprecated","affected_versions":"<=2.9.0.post0"}],"env_vars":null,"last_verified":"2026-05-12T12:18:40.039Z","next_check":"2026-06-25T00:00:00.000Z","problems":[{"fix":"pip install python-dateutil","cause":"The 'python-dateutil' package, which provides the 'dateutil' module, is not installed in the Python environment.","error":"ModuleNotFoundError: No module named 'dateutil'"},{"fix":"Provide date strings in clear, standard formats, use 'parser.isoparse' for ISO 8601, or pass 'dayfirst=True' / 'yearfirst=True' to 'parser.parse' for ambiguous formats.","cause":"The 'dateutil.parser.parse' function could not interpret the provided date string because its format was ambiguous or not recognized.","error":"ValueError: Unknown string format"},{"fix":"Import the 'parser' submodule explicitly, e.g., 'from dateutil import parser' or 'import dateutil.parser'.","cause":"The 'parse' function is located within the 'dateutil.parser' submodule, but the user attempted to call it directly from the top-level 'dateutil' module.","error":"AttributeError: module 'dateutil' has no attribute 'parse'"},{"fix":"Convert the 'datetime.date' object to a 'datetime.datetime' object before adding the 'relativedelta', or ensure you are working with 'datetime.datetime' objects from the start.","cause":"The 'relativedelta' object is being added to a 'datetime.date' object, which does not support direct arithmetic with 'relativedelta'; it only works with 'datetime.datetime' objects.","error":"TypeError: unsupported operand type(s) for +: 'datetime.date' and 'relativedelta'"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":80,"quickstart_tag":"verified","pypi_latest":null,"install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.5,"disk_size":"18.6M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.02,"mem_mb":1.5,"disk_size":"19M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.05,"mem_mb":1.8,"disk_size":"20.6M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.8,"disk_size":"21M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.4,"disk_size":"12.4M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.4,"disk_size":"13M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.6,"disk_size":"12.1M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.4,"disk_size":"13M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":1.9,"disk_size":"18.1M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.03,"mem_mb":1.9,"disk_size":"19M"}]},"quickstart_checks":{"last_tested":"2026-04-23","tag":"verified","tag_description":"quickstart runs on critical runtimes, recently tested","results":[{"runtime":"python:3.10-alpine","exit_code":0},{"runtime":"python:3.10-slim","exit_code":0},{"runtime":"python:3.11-alpine","exit_code":0},{"runtime":"python:3.11-slim","exit_code":0},{"runtime":"python:3.12-alpine","exit_code":0},{"runtime":"python:3.12-slim","exit_code":0},{"runtime":"python:3.13-alpine","exit_code":0},{"runtime":"python:3.13-slim","exit_code":0},{"runtime":"python:3.9-alpine","exit_code":0},{"runtime":"python:3.9-slim","exit_code":0}]}}