diff --git a/pandas/core/arrays/datetimes.py b/pandas/core/arrays/datetimes.py index 4ea6b9ceee833..0c90011d28a60 100644 --- a/pandas/core/arrays/datetimes.py +++ b/pandas/core/arrays/datetimes.py @@ -2134,7 +2134,7 @@ def objects_to_datetime64ns( dayfirst : bool yearfirst : bool utc : bool, default False - Whether to convert timezone-aware timestamps to UTC. + Whether to convert/localize timestamps to UTC. errors : {'raise', 'ignore', 'coerce'} require_iso8601 : bool, default False allow_object : bool diff --git a/pandas/core/tools/datetimes.py b/pandas/core/tools/datetimes.py index 9b59c9ea43e45..6a8c63fe8c5fe 100644 --- a/pandas/core/tools/datetimes.py +++ b/pandas/core/tools/datetimes.py @@ -38,7 +38,6 @@ AnyArrayLike, ArrayLike, DateTimeErrorChoices, - Timezone, npt, ) @@ -239,7 +238,7 @@ def _maybe_cache( def _box_as_indexlike( - dt_array: ArrayLike, utc: bool | None = None, name: Hashable = None + dt_array: ArrayLike, utc: bool = False, name: Hashable = None ) -> Index: """ Properly boxes the ndarray of datetimes to DatetimeIndex @@ -249,8 +248,8 @@ def _box_as_indexlike( ---------- dt_array: 1-d array Array of datetimes to be wrapped in an Index. - tz : object - None or 'utc' + utc : bool + Whether to convert/localize timestamps to UTC. name : string, default None Name for a resulting index @@ -290,10 +289,12 @@ def _convert_and_box_cache( from pandas import Series result = Series(arg).map(cache_array) - return _box_as_indexlike(result._values, utc=None, name=name) + return _box_as_indexlike(result._values, utc=False, name=name) -def _return_parsed_timezone_results(result: np.ndarray, timezones, tz, name) -> Index: +def _return_parsed_timezone_results( + result: np.ndarray, timezones, utc: bool, name +) -> Index: """ Return results from array_strptime if a %z or %Z directive was passed. @@ -303,8 +304,8 @@ def _return_parsed_timezone_results(result: np.ndarray, timezones, tz, name) -> int64 date representations of the dates timezones : ndarray pytz timezone objects - tz : object - None or pytz timezone object + utc : bool + Whether to convert/localize timestamps to UTC. name : string, default None Name for a DatetimeIndex @@ -315,9 +316,9 @@ def _return_parsed_timezone_results(result: np.ndarray, timezones, tz, name) -> tz_results = np.array( [Timestamp(res).tz_localize(zone) for res, zone in zip(result, timezones)] ) - if tz is not None: + if utc: # Convert to the same tz - tz_results = np.array([tz_result.tz_convert(tz) for tz_result in tz_results]) + tz_results = np.array([tz_result.tz_convert("utc") for tz_result in tz_results]) return Index(tz_results, name=name) @@ -326,7 +327,7 @@ def _convert_listlike_datetimes( arg, format: str | None, name: Hashable = None, - tz: Timezone | None = None, + utc: bool = False, unit: str | None = None, errors: DateTimeErrorChoices = "raise", infer_datetime_format: bool = False, @@ -344,8 +345,8 @@ def _convert_listlike_datetimes( date to be parsed name : object None or string for the Index name - tz : object - None or 'utc' + utc : bool + Whether to convert/localize timestamps to UTC. unit : str None or string of the frequency of the passed data errors : str @@ -368,11 +369,12 @@ def _convert_listlike_datetimes( arg_dtype = getattr(arg, "dtype", None) # these are shortcutable + tz = "utc" if utc else None if is_datetime64tz_dtype(arg_dtype): if not isinstance(arg, (DatetimeArray, DatetimeIndex)): return DatetimeIndex(arg, tz=tz, name=name) - if tz == "utc": - arg = arg.tz_convert(None).tz_localize(tz) + if utc: + arg = arg.tz_convert(None).tz_localize("utc") return arg elif is_datetime64_ns_dtype(arg_dtype): @@ -381,16 +383,16 @@ def _convert_listlike_datetimes( return DatetimeIndex(arg, tz=tz, name=name) except ValueError: pass - elif tz: + elif utc: # DatetimeArray, DatetimeIndex - return arg.tz_localize(tz) + return arg.tz_localize("utc") return arg elif unit is not None: if format is not None: raise ValueError("cannot specify both format and unit") - return _to_datetime_with_unit(arg, unit, name, tz, errors) + return _to_datetime_with_unit(arg, unit, name, utc, errors) elif getattr(arg, "ndim", 1) > 1: raise TypeError( "arg must be a string, datetime, list, tuple, 1-d array, or Series" @@ -427,12 +429,11 @@ def _convert_listlike_datetimes( if format is not None and not require_iso8601: res = _to_datetime_with_format( - arg, orig_arg, name, tz, format, exact, errors, infer_datetime_format + arg, orig_arg, name, utc, format, exact, errors, infer_datetime_format ) if res is not None: return res - utc = tz == "utc" result, tz_parsed = objects_to_datetime64ns( arg, dayfirst=dayfirst, @@ -451,14 +452,13 @@ def _convert_listlike_datetimes( dta = DatetimeArray(result, dtype=tz_to_dtype(tz_parsed)) return DatetimeIndex._simple_new(dta, name=name) - utc = tz == "utc" return _box_as_indexlike(result, utc=utc, name=name) def _array_strptime_with_fallback( arg, name, - tz, + utc: bool, fmt: str, exact: bool, errors: str, @@ -467,8 +467,6 @@ def _array_strptime_with_fallback( """ Call array_strptime, with fallback behavior depending on 'errors'. """ - utc = tz == "utc" - try: result, timezones = array_strptime(arg, fmt, exact=exact, errors=errors) except OutOfBoundsDatetime: @@ -498,7 +496,7 @@ def _array_strptime_with_fallback( return None else: if "%Z" in fmt or "%z" in fmt: - return _return_parsed_timezone_results(result, timezones, tz, name) + return _return_parsed_timezone_results(result, timezones, utc, name) return _box_as_indexlike(result, utc=utc, name=name) @@ -507,7 +505,7 @@ def _to_datetime_with_format( arg, orig_arg, name, - tz, + utc: bool, fmt: str, exact: bool, errors: str, @@ -531,17 +529,16 @@ def _to_datetime_with_format( "cannot convert the input to '%Y%m%d' date format" ) from err if result is not None: - utc = tz == "utc" return _box_as_indexlike(result, utc=utc, name=name) # fallback res = _array_strptime_with_fallback( - arg, name, tz, fmt, exact, errors, infer_datetime_format + arg, name, utc, fmt, exact, errors, infer_datetime_format ) return res -def _to_datetime_with_unit(arg, unit, name, tz, errors: str) -> Index: +def _to_datetime_with_unit(arg, unit, name, utc: bool, errors: str) -> Index: """ to_datetime specalized to the case where a 'unit' is passed. """ @@ -570,11 +567,11 @@ def _to_datetime_with_unit(arg, unit, name, tz, errors: str) -> Index: # result will be naive but in UTC result = result.tz_localize("UTC").tz_convert(tz_parsed) - if tz is not None: + if utc: if result.tz is None: - result = result.tz_localize(tz) + result = result.tz_localize("utc") else: - result = result.tz_convert(tz) + result = result.tz_convert("utc") return result @@ -657,7 +654,7 @@ def to_datetime( errors: DateTimeErrorChoices = ..., dayfirst: bool = ..., yearfirst: bool = ..., - utc: bool | None = ..., + utc: bool = ..., format: str | None = ..., exact: bool = ..., unit: str | None = ..., @@ -674,7 +671,7 @@ def to_datetime( errors: DateTimeErrorChoices = ..., dayfirst: bool = ..., yearfirst: bool = ..., - utc: bool | None = ..., + utc: bool = ..., format: str | None = ..., exact: bool = ..., unit: str | None = ..., @@ -691,7 +688,7 @@ def to_datetime( errors: DateTimeErrorChoices = ..., dayfirst: bool = ..., yearfirst: bool = ..., - utc: bool | None = ..., + utc: bool = ..., format: str | None = ..., exact: bool = ..., unit: str | None = ..., @@ -707,7 +704,7 @@ def to_datetime( errors: DateTimeErrorChoices = "raise", dayfirst: bool = False, yearfirst: bool = False, - utc: bool | None = None, + utc: bool = False, format: str | None = None, exact: bool = True, unit: str | None = None, @@ -756,7 +753,7 @@ def to_datetime( ``yearfirst=True`` is not strict, but will prefer to parse with year first. - utc : bool, default None + utc : bool, default False Control timezone-related parsing, localization and conversion. - If :const:`True`, the function *always* returns a timezone-aware @@ -1049,10 +1046,9 @@ def to_datetime( if origin != "unix": arg = _adjust_to_origin(arg, origin, unit) - tz = "utc" if utc else None convert_listlike = partial( _convert_listlike_datetimes, - tz=tz, + utc=utc, unit=unit, dayfirst=dayfirst, yearfirst=yearfirst, @@ -1065,11 +1061,11 @@ def to_datetime( if isinstance(arg, Timestamp): result = arg - if tz is not None: + if utc: if arg.tz is not None: - result = arg.tz_convert(tz) + result = arg.tz_convert("utc") else: - result = arg.tz_localize(tz) + result = arg.tz_localize("utc") elif isinstance(arg, ABCSeries): cache_array = _maybe_cache(arg, format, cache, convert_listlike) if not cache_array.empty: @@ -1078,7 +1074,7 @@ def to_datetime( values = convert_listlike(arg._values, format) result = arg._constructor(values, index=arg.index, name=arg.name) elif isinstance(arg, (ABCDataFrame, abc.MutableMapping)): - result = _assemble_from_unit_mappings(arg, errors, tz) + result = _assemble_from_unit_mappings(arg, errors, utc) elif isinstance(arg, Index): cache_array = _maybe_cache(arg, format, cache, convert_listlike) if not cache_array.empty: @@ -1145,7 +1141,7 @@ def to_datetime( } -def _assemble_from_unit_mappings(arg, errors: DateTimeErrorChoices, tz): +def _assemble_from_unit_mappings(arg, errors: DateTimeErrorChoices, utc: bool): """ assemble the unit specified fields from the arg (DataFrame) Return a Series for actual parsing @@ -1158,7 +1154,8 @@ def _assemble_from_unit_mappings(arg, errors: DateTimeErrorChoices, tz): - If :const:`'raise'`, then invalid parsing will raise an exception - If :const:`'coerce'`, then invalid parsing will be set as :const:`NaT` - If :const:`'ignore'`, then invalid parsing will return the input - tz : None or 'utc' + utc : bool + Whether to convert/localize timestamps to UTC. Returns ------- @@ -1221,7 +1218,7 @@ def coerce(values): + coerce(arg[unit_rev["day"]]) ) try: - values = to_datetime(values, format="%Y%m%d", errors=errors, utc=tz) + values = to_datetime(values, format="%Y%m%d", errors=errors, utc=utc) except (TypeError, ValueError) as err: raise ValueError(f"cannot assemble the datetimes: {err}") from err diff --git a/pandas/io/parsers/base_parser.py b/pandas/io/parsers/base_parser.py index e3fabf2edc288..b0f3754271894 100644 --- a/pandas/io/parsers/base_parser.py +++ b/pandas/io/parsers/base_parser.py @@ -1115,7 +1115,7 @@ def converter(*date_cols): try: return tools.to_datetime( ensure_object(strs), - utc=None, + utc=False, dayfirst=dayfirst, errors="ignore", infer_datetime_format=infer_datetime_format, diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 8c4f1c027fb0e..e3510f71bd0cd 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -91,7 +91,7 @@ def _process_parse_dates_argument(parse_dates): def _handle_date_column( - col, utc: bool | None = None, format: str | dict[str, Any] | None = None + col, utc: bool = False, format: str | dict[str, Any] | None = None ): if isinstance(format, dict): # GH35185 Allow custom error values in parse_dates argument of