如果你用Python处理过时间,一定被datetime
的"反人类"设计折磨过:想加个小时要手动算timedelta
,处理时区得额外装pytz
,格式化字符串要记一堆%Y%m%d
符号......而**Arrow**库的出现,把时间处理变成了"一行代码的事"。
Arrow是Python中最流行的时间处理库之一,它基于datetime
封装,但API更简洁、功能更强大------内置时区支持、一键格式化、人类可读时间、时间差计算等,让你彻底告别"时间处理焦虑"。
今天这篇博客,我们从"基础到实战",用15+示例带你掌握Arrow的核心用法,让时间处理从此优雅高效。
一、为什么选Arrow?先看一组对比
同样是"获取当前上海时间,格式化为'2024-05-20 14:30:00'",看看datetime
和Arrow的差距:
用datetime实现(繁琐)
python
from datetime import datetime
import pytz # 需额外安装
# 1. 获取当前UTC时间,转换为上海时区
sh_tz = pytz.timezone('Asia/Shanghai')
now = datetime.utcnow().replace(tzinfo=pytz.UTC).astimezone(sh_tz)
# 2. 格式化输出
formatted = now.strftime('%Y-%m-%d %H:%M:%S')
print(formatted) # 2024-05-20 14:30:00
用Arrow实现(优雅)
python
import arrow
# 一行搞定:获取上海时间 + 格式化
formatted = arrow.now('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss')
print(formatted) # 2024-05-20 14:30:00
仅一行代码,无需额外依赖(Arrow内置时区数据库),API直观到"见名知意"------这就是Arrow的魅力。
二、环境准备:5秒搞定安装
Arrow是第三方库,安装极其简单,直接用pip:
bash
# 安装最新版Arrow
pip install arrow
验证安装是否成功:
python
import arrow
print(arrow.__version__) # 输出当前版本,如1.3.0(确保≥1.0.0,功能更全)
三、基础用法:创建与转换Arrow对象
Arrow的核心是Arrow
类,所有时间操作都围绕它展开。首先要掌握"如何创建Arrow对象",以及"如何转换为其他类型(如datetime、字符串、时间戳)"。
1. 创建Arrow对象(5种常用方式)
python
import arrow
# 1. 获取当前时间(带本地时区,默认系统时区)
local_now = arrow.now()
print("本地当前时间:", local_now) # 如 2024-05-20T14:35:22.123456+08:00(+08:00是时区)
# 2. 获取当前UTC时间(推荐用于存储,避免时区混乱)
utc_now = arrow.utcnow()
print("UTC当前时间:", utc_now) # 如 2024-05-20T06:35:22.123456+00:00(+00:00是UTC)
# 3. 从指定时区创建时间(常用场景:明确业务时区,如上海、纽约)
sh_now = arrow.now('Asia/Shanghai') # 上海时区(东八区)
ny_now = arrow.now('America/New_York') # 纽约时区(西五区)
print("上海时间:", sh_now)
print("纽约时间:", ny_now)
# 4. 从字符串创建(自动解析格式,无需手动指定strftime)
time_str1 = "2024-05-20 14:30:00"
arrow1 = arrow.get(time_str1)
print("从字符串创建1:", arrow1) # 2024-05-20T14:30:00+00:00(默认UTC,需手动指定时区)
# 带时区的字符串
time_str2 = "2024-05-20T14:30:00+08:00"
arrow2 = arrow.get(time_str2)
print("从字符串创建2:", arrow2) # 2024-05-20T14:30:00+08:00(自动识别时区)
# 5. 从datetime对象转换(无缝兼容datetime)
from datetime import datetime
dt = datetime(2024, 5, 20, 14, 30)
arrow_from_dt = arrow.Arrow.fromdatetime(dt, tzinfo='Asia/Shanghai')
print("从datetime创建:", arrow_from_dt) # 2024-05-20T14:30:00+08:00
关键提示 :时区名称需符合IANA时区数据库
(如Asia/Shanghai
而非Beijing
,America/New_York
而非NewYork
),可通过pytz.all_timezones
查看所有合法时区。
2. 类型转换:Arrow ↔ 字符串/时间戳/datetime
Arrow对象可轻松转换为日常开发中常用的类型,无需复杂处理:
python
import arrow
# 以"上海当前时间"为例
sh_now = arrow.now('Asia/Shanghai') # 2024-05-20T14:40:00.123456+08:00
# 1. 转换为字符串(默认ISO格式)
iso_str = sh_now.isoformat()
print("ISO格式字符串:", iso_str) # 2024-05-20T14:40:00.123456+08:00
# 2. 转换为自定义格式字符串(支持strftime所有格式符)
custom_str = sh_now.format('YYYY年MM月DD日 HH:mm:ss')
print("自定义格式:", custom_str) # 2024年05月20日 14:40:00
# 3. 转换为时间戳(秒级/毫秒级)
timestamp_sec = sh_now.timestamp() # 秒级时间戳(整数)
timestamp_ms = sh_now.timestamp_ms() # 毫秒级时间戳(整数)
print("秒级时间戳:", timestamp_sec) # 1716211200
print("毫秒级时间戳:", timestamp_ms) # 1716211200123
# 4. 转换为datetime对象(带时区)
dt_with_tz = sh_now.datetime
print("带时区datetime:", dt_with_tz) # 2024-05-20 14:40:00.123456+08:00
# 转换为 naive datetime(无时区,谨慎使用)
dt_naive = sh_now.naive
print("无时区datetime:", dt_naive) # 2024-05-20 14:40:00.123456
四、核心亮点:时区处理(Arrow的王牌功能)
datetime
处理时区需要依赖pytz
,且API繁琐;而Arrow**内置时区支持**,一行代码即可实现时区创建、转换、切换,彻底解决时区痛点。
1. 给Arrow对象添加时区
如果创建的Arrow对象是"无时区"的(如从字符串解析的默认UTC),可通过to()
或replace(tzinfo)
添加时区:
python
import arrow
# 1. 无时区对象(默认UTC)
arrow_utc = arrow.get("2024-05-20 14:30:00") # 2024-05-20T14:30:00+00:00
# 2. 转换为上海时区(本质:将UTC时间转换为上海时间,时间值会变)
arrow_sh = arrow_utc.to('Asia/Shanghai')
print("UTC→上海:", arrow_sh) # 2024-05-20T22:30:00+08:00(UTC14点=上海22点)
# 3. 直接添加时区(注意:不改变时间值,仅附加时区信息,谨慎使用)
arrow_naive = arrow.get("2024-05-20 14:30:00").naive # 先转为无时区
arrow_add_tz = arrow.Arrow.fromdatetime(arrow_naive, tzinfo='Asia/Shanghai')
print("添加上海时区:", arrow_add_tz) # 2024-05-20T14:30:00+08:00(时间值不变)
关键区别 :to()
是"时区转换"(时间值随时区变化),fromdatetime(..., tzinfo)
是"附加时区"(时间值不变),根据业务场景选择。
2. 时区之间的转换
任意两个时区之间的转换,只需调用to()
方法指定目标时区:
python
import arrow
# 1. 获取当前纽约时间
ny_now = arrow.now('America/New_York') # 如 2024-05-20T02:45:00-04:00(西四区)
# 2. 转换为上海时间
sh_now = ny_now.to('Asia/Shanghai')
print("纽约→上海:", sh_now) # 2024-05-20T14:45:00+08:00(纽约2点=上海14点,时差12小时)
# 3. 再转换为伦敦时间
london_now = sh_now.to('Europe/London')
print("上海→伦敦:", london_now) # 2024-05-20T06:45:00+00:00(上海14点=伦敦6点,时差8小时)
3. UTC与本地时区的快速切换
开发中常需要"存储用UTC,展示用本地时区",Arrow提供utcnow()
和now()
快速切换:
python
import arrow
# 1. 存储:获取UTC时间(推荐用于数据库存储,避免时区混乱)
utc_time = arrow.utcnow()
print("存储用UTC:", utc_time) # 2024-05-20T06:50:00+00:00
# 2. 展示:转换为本地时区(自动识别系统时区)
local_time = utc_time.to('local')
print("展示用本地时区:", local_time) # 2024-05-20T14:50:00+08:00(若系统是上海时区)
五、实用操作:时间格式化与解析
Arrow的格式化和解析功能比datetime
更灵活,支持自动识别格式、自定义格式,甚至非标准时间字符串。
1. 时间格式化(输出字符串)
除了前面提到的format()
,Arrow还支持常用格式的快捷方法:
python
import arrow
sh_now = arrow.now('Asia/Shanghai') # 2024-05-20T15:00:00+08:00
# 1. 标准格式
print("ISO格式:", sh_now.isoformat()) # 2024-05-20T15:00:00.123456+08:00
print("日期部分:", sh_now.date()) # 2024-05-20(返回date对象,可转字符串)
print("时间部分:", sh_now.time()) # 15:00:00.123456(返回time对象)
# 2. 自定义格式(支持所有strftime符号,且兼容Python和Arrow扩展符号)
print("年-月-日 时:分:秒:", sh_now.format('YYYY-MM-DD HH:mm:ss')) # 2024-05-20 15:00:00
print("带星期:", sh_now.format('YYYY-MM-DD HH:mm:ss dddd')) # 2024-05-20 15:00:00 星期一
print("12小时制(带AM/PM):", sh_now.format('YYYY-MM-DD hh:mm:ss A')) # 2024-05-20 03:00:00 PM
常用格式符 :YYYY
(4位年)、MM
(2位月)、DD
(2位日)、HH
(24小时制)、hh
(12小时制)、mm
(分)、ss
(秒)、dddd
(完整星期)、A
(AM/PM)。
2. 时间解析(字符串→Arrow对象)
Arrow的get()
方法能自动识别大多数时间格式,无需手动指定strftime
,极大简化解析流程:
python
import arrow
# 1. 自动识别标准格式(无需指定格式)
arrow1 = arrow.get("2024-05-20")
arrow2 = arrow.get("2024/05/20 15:30")
arrow3 = arrow.get("2024-05-20T15:30:00+08:00")
print("自动解析1:", arrow1) # 2024-05-20T00:00:00+00:00
print("自动解析2:", arrow2) # 2024-05-20T15:30:00+00:00
print("自动解析3:", arrow3) # 2024-05-20T15:30:00+08:00
# 2. 解析非标准格式(需指定格式符)
non_std_str = "2024年05月20日 15时30分"
arrow4 = arrow.get(non_std_str, 'YYYY年MM月DD日 HH时mm分')
print("解析非标准格式:", arrow4) # 2024-05-20T15:30:00+00:00
# 3. 解析时间戳(秒级/毫秒级)
timestamp_sec = 1716214200 # 对应2024-05-20 15:30:00(上海时区)
timestamp_ms = 1716214200123
arrow5 = arrow.get(timestamp_sec)
arrow6 = arrow.get(timestamp_ms)
print("解析秒级时间戳:", arrow5.to('Asia/Shanghai')) # 2024-05-20T15:30:00+08:00
print("解析毫秒级时间戳:", arrow6.to('Asia/Shanghai')) # 2024-05-20T15:30:00.123000+08:00
六、时间计算:加减、比较与差值
Arrow简化了时间的加减和比较操作,无需手动创建timedelta
,API更直观。
1. 时间加减(shift()方法)
用shift()
方法可轻松加减年、月、日、时、分、秒,支持多单位同时操作:
python
import arrow
now = arrow.now('Asia/Shanghai') # 2024-05-20T16:00:00+08:00
# 1. 加时间
one_hour_later = now.shift(hours=1) # 1小时后
three_days_later = now.shift(days=3) # 3天后
one_month_later = now.shift(months=1) # 1个月后(自动处理月份天数,如5月20日→6月20日)
print("1小时后:", one_hour_later) # 2024-05-20T17:00:00+08:00
print("3天后:", three_days_later) # 2024-05-23T16:00:00+08:00
print("1个月后:", one_month_later) # 2024-06-20T16:00:00+08:00
# 2. 减时间(传负数)
one_hour_ago = now.shift(hours=-1) # 1小时前
two_weeks_ago = now.shift(weeks=-2) # 2周前
print("1小时前:", one_hour_ago) # 2024-05-20T15:00:00+08:00
print("2周前:", two_weeks_ago) # 2024-05-06T16:00:00+08:00
# 3. 多单位同时加减
later = now.shift(days=1, hours=2, minutes=30) # 1天2小时30分钟后
print("1天2小时30分后:", later) # 2024-05-21T18:30:00+08:00
2. 时间比较(常规运算符)
Arrow对象支持直接用<
、>
、==
等运算符比较,无需转换为时间戳:
python
import arrow
time1 = arrow.get("2024-05-20 16:00:00", tzinfo='Asia/Shanghai')
time2 = arrow.get("2024-05-20 17:00:00", tzinfo='Asia/Shanghai')
time3 = arrow.get("2024-05-20 16:00:00", tzinfo='Asia/Shanghai')
# 1. 比较大小
print(time1 < time2) # True(time1早于time2)
print(time1 > time2) # False
print(time1 == time3) # True(时间和时区都相同)
# 2. 比较不同时区的时间(自动转换为同一时区后比较)
time4 = arrow.get("2024-05-20 08:00:00", tzinfo='UTC') # UTC8点=上海16点
print(time1 == time4) # True(自动转换时区后相等)
3. 计算时间差(total_seconds())
两个Arrow对象相减,得到arrow.arrow.Timedelta
对象,可转换为秒、分钟、小时等:
python
import arrow
start = arrow.get("2024-05-20 16:00:00", tzinfo='Asia/Shanghai')
end = arrow.get("2024-05-20 18:30:00", tzinfo='Asia/Shanghai')
# 1. 计算时间差
delta = end - start
print("时间差对象:", delta) # 0:2:30:00.000000(天:时:分:秒)
# 2. 转换为具体单位
print("总秒数:", delta.total_seconds()) # 9000.0(2.5小时=9000秒)
print("总分钟数:", delta.total_seconds() / 60) # 150.0
print("小时数:", delta.hours) # 2(注意:hours是整数部分,不包含分钟)
print("分钟数:", delta.minutes) # 30
七、实战工具:人类可读时间与时间取整
Arrow提供了很多"人性化"工具方法,比如生成"2小时前"的字符串、将时间取整到小时/天,这些在日志展示、数据统计中非常实用。
1. 人类可读时间(humanize())
humanize()
方法能将Arrow对象转换为"多久前/后"的人类可读字符串,支持多语言:
python
import arrow
now = arrow.now('Asia/Shanghai') # 2024-05-20T19:00:00+08:00
# 1. 过去的时间
one_hour_ago = now.shift(hours=-1)
three_days_ago = now.shift(days=-3)
print("1小时前:", one_hour_ago.humanize()) # an hour ago
print("3天前:", three_days_ago.humanize()) # 3 days ago
# 2. 未来的时间
two_weeks_later = now.shift(weeks=2)
print("2周后:", two_weeks_later.humanize()) # in 2 weeks
# 3. 中文支持(需指定locale参数)
print("1小时前(中文):", one_hour_ago.humanize(locale='zh')) # 1小时前
print("3天前(中文):", three_days_ago.humanize(locale='zh')) # 3天前
print("2周后(中文):", two_weeks_later.humanize(locale='zh')) # 2周后
支持的语言 :zh
(中文)、en
(英文)、ja
(日文)、fr
(法文)等,需确保系统安装对应语言包(一般默认支持中文)。
2. 时间取整(floor()/ceil())
将时间"向下取整"或"向上取整"到指定单位(如小时、天、月),常用于数据统计(如按小时汇总日志):
python
import arrow
now = arrow.now('Asia/Shanghai') # 2024-05-20T19:23:45+08:00
# 1. 向下取整(floor():取到当前单位的起始时间)
floor_hour = now.floor('hour') # 取整到小时
floor_day = now.floor('day') # 取整到天(当天0点)
floor_month = now.floor('month')# 取整到月(当月1号0点)
print("向下取整到小时:", floor_hour) # 2024-05-20T19:00:00+08:00
print("向下取整到天:", floor_day) # 2024-05-20T00:00:00+08:00
print("向下取整到月:", floor_month) # 2024-05-01T00:00:00+08:00
# 2. 向上取整(ceil():取到当前单位的结束时间)
ceil_hour = now.ceil('hour') # 取整到下一小时
ceil_day = now.ceil('day') # 取整到明天0点
print("向上取整到小时:", ceil_hour) # 2024-05-20T20:00:00+08:00
print("向上取整到天:", ceil_day) # 2024-05-21T00:00:00+08:00
八、进阶实战:用Arrow处理日志时间
假设你有一份日志文件,每行日志的时间格式是"2024-05-20 19:30:00"(无时区),需要:
-
解析日志时间并添加上海时区;
-
筛选出"2024-05-20 19:00-20:00"之间的日志;
-
计算每条日志与当前时间的差值,生成"XX分钟前"的备注。
用Arrow实现这一需求,代码简洁高效:
python
import arrow
# 模拟日志数据
logs = [
"2024-05-20 18:50:00 - 用户A登录",
"2024-05-20 19:15:00 - 用户B操作订单",
"2024-05-20 19:45:00 - 用户C退出",
"2024-05-20 20:10:00 - 用户D登录"
]
# 目标时间范围(2024-05-20 19:00-20:00 上海时区)
start_time = arrow.get("2024-05-20 19:00:00", tzinfo='Asia/Shanghai')
end_time = arrow.get("2024-05-20 20:00:00", tzinfo='Asia/Shanghai')
now = arrow.now('Asia/Shanghai')
# 处理日志
print("筛选出19:00-20:00的日志:")
for log in logs:
# 1. 提取日志时间字符串(前19个字符)
time_str = log[:19]
# 2. 解析时间并添加上海时区
log_time = arrow.get(time_str, tzinfo='Asia/Shanghai')
# 3. 筛选时间范围
if start_time <= log_time < end_time:
# 4. 计算与当前时间的差值(人类可读)
time_diff = log_time.humanize(now, locale='zh')
# 5. 输出结果
print(f"{log} - {time_diff}")
# 输出结果:
# 筛选出19:00-20:00的日志:
# 2024-05-20 19:15:00 - 用户B操作订单 - 45分钟前(假设当前是20:00)
# 2024-05-20 19:45:00 - 用户C退出 - 15分钟前
九、总结:为什么Arrow值得替代datetime?
-
API更简洁 :一行代码实现时间创建、时区转换、格式化,告别
datetime
的嵌套调用; -
时区原生支持 :无需依赖
pytz
,内置IANA时区数据库,轻松处理跨时区场景; -
功能更丰富:人类可读时间、时间取整、自动解析格式等实用功能,覆盖90%+时间处理场景;
-
兼容性强 :无缝转换为
datetime
、字符串、时间戳,可直接用于现有项目。
如果你还在为datetime
的繁琐而头疼,不妨试试Arrow------它会让你发现:处理时间原来可以这么优雅!
最后:常用操作速查表
|--------------------------|-------------------------------------------|
| 需求 | Arrow实现 |
| 获取上海当前时间 | arrow.now('Asia/Shanghai')
|
| UTC时间转上海时间 | arrow.utcnow().to('Asia/Shanghai')
|
| 时间格式化为"2024-05-20 14:30" | arrow_obj.format('YYYY-MM-DD HH:mm')
|
| 解析"2024年05月20日"为Arrow对象 | arrow.get("2024年05月20日", 'YYYY年MM月DD日')
|
| 计算1小时后时间 | arrow_obj.shift(hours=1)
|
| 生成"2小时前"的中文描述 | arrow_obj.humanize(locale='zh')
|
| 时间向下取整到小时 | arrow_obj.floor('hour')
|