Pandas中字符串时间转换为日期时间时日期意外更改的解决方案


在pandas中将仅包含时间的字符串转换为`datetime`类型时,由于缺少日期信息,`pd.to_datetime`函数会默认填充当前系统日期,导致日期意外更改。本教程将深入解析此问题的原因,并提供两种主要解决方案:通过字符串拼接合并日期和时间,或通过结合`datetime`与`timedelta`对象来精确创建完整的日期时间信息,确保数据转换的准确性。

理解Pandas日期时间转换中的日期变更问题

在使用Pandas处理时间序列数据时,将字符串格式的日期和时间转换为datetime对象是常见的操作。然而,当数据集中日期和时间信息分别存储在不同的列中,并且尝试单独转换仅包含时间的列时,可能会遇到日期意外变更的问题。这是因为pd.to_datetime函数在处理不完整的日期时间字符串(例如,只包含时间的部分)时,会默认使用当前的系统日期来填充缺失的日期信息。

问题现象与复现

考虑以下初始DataFrame,其中order_date和order_time是单独的列:

import pandas as pd

data = {
    'order_details_id': [1, 2, 3, 4, 5],
    'order_id': [1, 2, 2, 2, 2],
    'order_date': ['1/1/23', '1/1/23', '1/1/23', '1/1/23', '1/1/23'],
    'order_time': ['11:38:36 AM', '11:57:40 AM', '11:57:40 AM', '11:57:40 AM', '11:57:40 AM'],
    'item_id': [109.0, 108.0, 124124.0, 117.0, 129.0]
}
df = pd.DataFrame(data)
print("初始DataFrame:")
print(df)
print("\n初始DataFrame数据类型:")
print(df.dtypes)

输出:

初始DataFrame:
   order_details_id  order_id order_date   order_time  item_id
0                 1         1     1/1/23  11:38:36 AM    109.0
1                 2         2     1/1/23  11:57:40 AM    108.0
2                 3         2     1/1/23  11:57:40 AM    124124.0
3                 4         2     1/1/23  11:57:40 AM    117.0
4                 5         2     1/1/23  11:57:40 AM    129.0

初始DataFrame数据类型:
order_details_id      int64
order_id              int64
order_date           object
order_time           object
item_id             float64
dtype: object

如果首先将order_date列转换为datetime类型,然后尝试将order_time列也转换为datetime类型:

df['order_date'] = pd.to_datetime(df['order_date'])
print("\n转换order_date后的DataFrame:")
print(df)

df['order_time'] = pd.to_datetime(df['order_time'])
print("\n转换order_time后的DataFrame:")
print(df)

你可能会观察到order_time列在转换为datetime后,其日期部分从2025-01-01变为了执行代码时的当前日期(例如2025-12-29)。这是因为"11:38:36 AM"这样的字符串本身不包含任何日期信息,pd.to_datetime在缺乏日期上下文时,会默认使用当前日期进行填充。

# 转换order_date后的DataFrame (示例输出)
#    order_details_id  order_id  order_date   order_time  item_id
# 0                 1         1  2025-01-01  11:38:36 AM    109.0
# ...

# 转换order_time后的DataFrame (示例输出,日期部分已更改)
#    order_details_id  order_id  order_date          order_time  item_id
# 0                 1         1  2025-01-01   2025-12-29 11:38:36    109.0
# ...

(注意:order_time列的日期部分会根据你运行代码的实际日期而变化,这里以2025-12-29为例。)

核心原理:pd.to_datetime的默认行为

当pd.to_datetime函数接收到一个只包含时间(如"HH:MM:SS AM/PM")的字符串时,它无法从该字符串中推断出日期信息。为了生成一个完整的datetime对象,Pandas会采用一个默认策略:将缺失的日期部分填充为函数执行时的当前系统日期。这就是导致日期意外变更的根本原因。

要避免这种问题,关键在于确保在创建datetime对象时,始终提供完整的日期和时间信息。

解决方案

解决此问题的核心思路是,在进行datetime转换之前,将日期和时间信息合并为一个完整的字符串或利用Pandas的日期时间操作功能。

方法一:字符串拼接

此方法通过将日期和时间字符串合并成一个完整的日期时间字符串,然后使用pd.to_datetime进行一次性转换。

# 重新加载初始数据以确保干净状态
df = pd.DataFrame(data)

# 将order_date和order_time列拼接成一个新的字符串列
df['order_datetime'] = pd.to_datetime(df['order_date'].astype(str) + ' ' + df['order_time'].astype(str))

print("\n方法一:字符串拼接后的DataFrame:")
print(df)
print("\n方法一:新列数据类型:")
print(df.dtypes)

输出:

方法一:字符串拼接后的DataFrame:
   order_details_id  order_id order_date   order_time  item_id      order_datetime
0                 1         1     1/1/23  11:38:36 AM    109.0 2025-01-01 11:38:36
1                 2         2     1/1/23  11:57:40 AM    108.0 2025-01-01 11:57:40
2                 3         2     1/1/23  11:57:40 AM    124124.0 2025-01-01 11:57:40
3                 4         2     1/1/23  11:57:40 AM    117.0 2025-01-01 11:57:40
4                 5         2     1/1/23  11:57:40 AM    129.0 2025-01-01 11:57:40

方法一:新列数据类型:
order_details_id             int64
order_id                     int64
order_date                  object
order_time                  object
item_id                    float64
order_datetime      datetime64[ns]
dtype: object

这种方法简单直观,尤其适用于日期和时间格式相对规整的情况。astype(str)确保了在拼接前所有元素都是字符串,避免潜在的类型错误。

方法二:结合datetime与timedelta

这种方法被认为是更优雅和健壮的方式,因为它避免了字符串操作可能带来的格式问题,而是利用了Pandas的日期时间算术功能。首先将日期列转换为datetime对象,然后将时间列转换为timedelta对象,最后将两者相加。

# 重新加载初始数据以确保干净状态
df = pd.DataFrame(data)

# 将order_date转换为datetime对象
# 使用pop()可以同时获取列并从DataFrame中删除它
order_date_dt = pd.to_datetime(df.pop('order_date'))

# 将order_time转换为timedelta对象
# 注意:pd.to_timedelta可以直接解析时间字符串
order_time_td = pd.to_timedelta(df.pop('order_time'))

# 将datetime和timedelta相加,得到完整的datetime对象
df['order_datetime'] = order_date_dt + order_time_td

print("\n方法二:结合datetime与timedelta后的DataFrame:")
print(df)
print("\n方法二:新列数据类型:")
print(df.dtypes)

输出:

方法二:结合datetime与timedelta后的DataFrame:
   order_details_id  order_id  item_id      order_datetime
0                 1         1    109.0 2025-01-01 11:38:36
1                 2         2    108.0 2025-01-01 11:57:40
2                 3         2    124124.0 2025-01-01 11:57:40
3                 4         2    117.0 2025-01-01 11:57:40
4                 5         2    129.0 2025-01-01 11:57:40

方法二:新列数据类型:
order_details_id             int64
order_id                     int64
item_id                    float64
order_datetime      datetime64[ns]
dtype: object

此方法在处理日期和时间格式复杂或需要进行进一步时间算术操作时显示出其优势。pd.to_timedelta能够智能地解析时间字符串,并将其转换为表示时间差的Timedelta对象。

方法三:处理预合并的日期时间字符串

在某些情况下,你可能从数据源获得的数据已经将日期和时间合并在一个字符串列中。在这种情况下,直接使用pd.to_datetime进行转换即可。

# 假设我们有一个预合并的日期时间列
df_combined = pd.DataFrame({
    'order_details_id': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5},
    'order_id': {0: 1, 1: 2, 2: 2, 3: 2, 4: 2},
    'order_date_time': {0: '1/1/23 11:38:36 AM',
                        1: '1/1/23 11:57:40 AM',
                        2: '1/1/23 11:57:40 AM',
                        3: '1/1/23 11:57:40 AM',
                        4: '1/1/23 11:57:40 AM'},
    'item_id': {0: 109.0, 1: 108.0, 2: 124124.0, 3: 117.0, 4: 129.0}
})

df_combined['order_dt'] = pd.to_datetime(df_combined['order_date_time'])

print("\n方法三:处理预合并日期时间字符串的DataFrame:")
print(df_combined)
print("\n方法三:新列数据类型:")
print(df_combined.dtypes)

输出:

方法三:处理预合并日期时间字符串的DataFrame:
   order_details_id  order_id     order_date_time  item_id            order_dt
0                 1         1  1/1/23 11:38:36 AM    109.0 2025-01-01 11:38:36
1                 2         2  1/1/23 11:57:40 AM    108.0 2025-01-01 11:57:40
2                 3         2  1/1/23 11:57:40 AM    124124.0 2025-01-01 11:57:40
3                 4         2  1/1/23 11:57:40 AM    117.0 2025-01-01 11:57:40
4                 5         2  1/1/23 11:57:40 AM    129.0 2025-01-01 11:57:40

方法三:新列数据类型:
order_details_id             int64
order_id                     int64
order_date_time             object
item_id                    float64
order_dt            datetime64[ns]
dtype: object

注意事项与最佳实践

  1. 始终提供完整的日期时间信息: 避免将仅有时间或仅有日期的字符串单独转换为datetime对象,除非你确实希望Pandas填充默认值。
  2. 明确指定格式(format参数): 如果你的日期时间字符串格式不标准或可能存在歧义,使用pd.to_datetime的format参数明确指定输入格式,例如pd.to_datetime(df['date_col'], format='%m/%d/%y %I:%M:%S %p')。这可以提高转换的效率和准确性。
  3. 错误处理(errors参数): 当数据中可能存在无法解析的日期时间字符串时,可以使用errors='coerce'参数。这会将无法解析的值转换为NaT(Not a Time),而不是引发错误,从而提高代码的健壮性。
  4. 数据类型检查: 转换后,务必使用df.dtypes或df['column'].dtype检查新列的数据类型,确保其为datetime64[ns]。
  5. 性能考量: 对于大型数据集,字符串拼接(方法一)可能比datetime与timedelta结合(方法二)略慢,因为字符串操作通常开销较大。在性能敏感的场景下,可以优先考虑方法二或预处理数据。

总结

在Pandas中处理日期时间数据时,理解pd.to_datetime的默认行为至关重要。当将仅包含时间的字符串转换为datetime类型时,由于缺少日期信息,Pandas会默认填充当前系统日期,导致数据不准确。通过将日期和时间信息合并为一个完整的字符串进行转换,或利用datetime与timedelta对象的算术操作,可以有效地解决这一问题,确保生成正确的日期时间对象。选择哪种方法取决于原始数据的结构和个人偏好,但核心原则是:在创建datetime对象时,确保其包含完整的日期和时间上下文。


# ai  # pandas  # 数据类型  # format  # 字符串  # 对象  # column  # 转换为  # 串列  # 并为  # 这是因为  # 都是  # 加载  # 这一  # 这种方法  # 以确保  # 这就是 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 网络优化76771 】 【 技术知识130152 】 【 IDC云计算60162 】 【 营销推广131313 】 【 AI优化88182 】 【 百度推广37138 】 【 网站推荐60173 】 【 精选阅读31334


相关推荐: Python装饰器复用技巧_通用能力解析【教程】  Win11怎么设置默认浏览器Chrome_Windows11修改默认网页打开方式  Windows10如何删除恢复分区_Win10 Diskpart命令强制删除分区  Win11怎么开启上帝模式_创建Windows 11 God Mode全能文件夹【技巧】  如何用正则表达式精确匹配“start”到“end”之间最多含一个换行符的文本段  c++中explicit(bool)的用法 c++条件性explicit【C++20】  Python技术债务管理_长期维护解析【教程】  php嵌入式多设备通信怎么实现_php同时管理多个串口设备【操作】  Win11怎么关闭系统推荐内容_Windows11开始菜单布局设置  php转mp4怎么保留字幕_php处理带字幕视频转换说明【说明】  如何在Golang中实现WebSocket广播_使用Channel和协程分发消息  Laravel 查询 JSON 列:高效筛选包含数组中任意值的记录  PythonGIL机制理解_多线程限制解析【教程】  win11如何清理传递优化文件 Win11为C盘瘦身删除更新缓存【技巧】  TestNG的testng.xml配置文件怎么写  Windows电脑如何进入安全模式?(多种按键方法)  php条件判断怎么写_ifelse和switchcase的使用区别【对比】  XML的“混合内容”是什么 怎么用DTD或XSD定义  Go 中 defer 语句在 goroutine 内部不返回时不会执行  如何在Golang中实现微服务负载均衡_Golang负载均衡策略与实现示例  Win11怎么关闭通知消息_屏蔽Windows 11右下角弹窗通知设置【详解】  Bpmn 2.0的XML文件怎么画流程图  如何在Golang中捕获HTTP服务器错误_GolangHTTP Handler中error处理  C#如何使用Channel C#通道实现异步通信  Windows10系统怎么查看设备管理器_Win10快捷键Win+X菜单使用  c++如何获取map中所有的键_C++遍历键值对提取所有key的方法  如何在Golang中处理JSON字段缺失_Golangjson解析字段校验方法  Win10如何更改任务栏高度_Windows10解锁任务栏调整大小  Mac上的iMovie如何剪辑视频?(新手入门教程)  c++协程和线程的区别 c++异步编程模型对比【核心】  Go 中的 := 运算符:类型推导机制与使用边界详解  Win11怎么设置开机自动连接宽带_Windows11创建拨号连接计划任务  VSC里PHP变量未定义报错怎么解决_错误抑制技巧【解答】  GML (Geography Markup Language)是什么,它如何用XML来表示地理空间信息?  Linux如何安装JDK11_Linux环境变量配置与Java开发环境搭建【教程】  Win11怎么设置指纹解锁 Win11笔记本录入指纹登录【教程】  如何在 IIS 上为 ASP.NET 6 应用排除特定目录并交由 PHP 处理  Win11怎么设置默认图片查看器_Windows11照片应用关联设置  Win11怎么关闭VBS安全性_Windows11提升游戏性能关闭虚拟化安全  Win11怎么关闭任务栏小图标_Windows11任务栏角溢出设置  Python代码测试策略_质量保障解析【教程】  如何使用Golang捕获测试日志_Golang testing日志记录方法  C++中的协变与逆变是什么?C++函数指针与返回类型详解【类型系统】  如何使用Golang实现跨域请求支持_Golang CORS配置与处理方法  PHP 中如何在函数内持久化修改引用变量的指向  php后缀怎么变mp4能播放_让php伪装mp4正常播放的技巧【技巧】  Python面向对象实战讲解_类与设计模式深入理解  Windows 11无法安全删除U盘提示设备正在使用中怎么办_Windows 11找出占用设备进程  Windows11怎么自定义任务栏_Windows11任务栏自定义教程【步骤】  Win11快速助手怎么用_Win11远程协助连接教程【工具】 

 2025-11-18

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

致胜网络推广营销网


致胜网络推广营销网

致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。

 915688610

 17370845950

 915688610@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.