diff --git a/pandas/_libs/tslib.pyx b/pandas/_libs/tslib.pyx index ee3964b892e2e..39c8aab2ce5dc 100644 --- a/pandas/_libs/tslib.pyx +++ b/pandas/_libs/tslib.pyx @@ -595,7 +595,7 @@ cpdef array_to_datetime( continue elif is_raise: raise ValueError( - f"time data {val} doesn't match format specified" + f"time data \"{val}\" at position {i} doesn't match format specified" ) return values, tz_out @@ -607,11 +607,11 @@ cpdef array_to_datetime( # to check if all arguments have the same tzinfo tz = py_dt.utcoffset() - except (ValueError, OverflowError): + except (ValueError, OverflowError) as err: if is_coerce: iresult[i] = NPY_NAT continue - raise TypeError("invalid string coercion to datetime") + raise type(err)(f"invalid string coercion to datetime for \"{val}\" at position {i}") if tz is not None: seen_datetime_offset = True @@ -664,11 +664,11 @@ cpdef array_to_datetime( # Still raise OutOfBoundsDatetime, # as error message is informative. - raise + raise OutOfBoundsDatetime(f"Cannot convert \"{val}\" at position {i} to datetime") assert is_ignore return values, tz_out - raise + raise OutOfBoundsDatetime(f"Cannot convert \"{val}\" at position {i} to datetime") except OutOfBoundsDatetime: if is_raise: @@ -798,6 +798,7 @@ cdef _array_to_datetime_object( # We return an object array and only attempt to parse: # 1) NaT or NaT-like values # 2) datetime strings, which we return as datetime.datetime + # 3) special strings - "now" & "today" for i in range(n): val = values[i] if checknull_with_nat_and_na(val) or PyDateTime_Check(val): @@ -811,17 +812,24 @@ cdef _array_to_datetime_object( if len(val) == 0 or val in nat_strings: oresult[i] = 'NaT' continue + try: - oresult[i] = parse_datetime_string(val, dayfirst=dayfirst, + # Handling special case strings today & now + if val == "today": + oresult[i] = datetime.today() + elif val == "now": + oresult[i] = datetime.now() + else: + oresult[i] = parse_datetime_string(val, dayfirst=dayfirst, yearfirst=yearfirst) - pydatetime_to_dt64(oresult[i], &dts) - check_dts_bounds(&dts) - except (ValueError, OverflowError): + pydatetime_to_dt64(oresult[i], &dts) + check_dts_bounds(&dts) + except (ValueError, OverflowError) as err: if is_coerce: oresult[i] = NaT continue if is_raise: - raise + raise type(err)(f"Unable to parse string \"{val}\" at position {i}") return values, None else: if is_raise: diff --git a/pandas/_libs/tslibs/parsing.pyx b/pandas/_libs/tslibs/parsing.pyx index 5cb11436f6f45..50be534328334 100644 --- a/pandas/_libs/tslibs/parsing.pyx +++ b/pandas/_libs/tslibs/parsing.pyx @@ -261,7 +261,7 @@ def parse_datetime_string( datetime dt if not _does_string_look_like_datetime(date_string): - raise ValueError('Given date string not likely a datetime.') + raise ValueError(f'Given date string {date_string} not likely a datetime.') if does_string_look_like_time(date_string): # use current datetime as default, not pass _DEFAULT_DATETIME @@ -287,7 +287,7 @@ def parse_datetime_string( except TypeError: # following may be raised from dateutil # TypeError: 'NoneType' object is not iterable - raise ValueError('Given date string not likely a datetime.') + raise ValueError(f'Given date string {date_string} not likely a datetime.') return dt @@ -363,7 +363,7 @@ cdef parse_datetime_string_with_reso( int out_tzoffset if not _does_string_look_like_datetime(date_string): - raise ValueError('Given date string not likely a datetime.') + raise ValueError(f'Given date string {date_string} not likely a datetime.') parsed, reso = _parse_delimited_date(date_string, dayfirst) if parsed is not None: