13、Python 日期与时间处理全解析

Python 日期与时间处理全解析

摘要

本文全面解析Python日期时间处理的核心模块datetimetimecalendar,涵盖时区转换(pytz库)、时间戳操作、定时任务调度、日志时间格式化等场景。通过timedelta计算、性能优化技巧及10个实战练习题(含完整答案代码),帮助开发者构建完整的时序数据处理知识体系。


一、Python时间处理核心模块对比

1.1 datetime模块

from datetime import datetime, timedelta

# 创建日期对象
now = datetime.now()
print(f"当前时间: {now}")  # 2023-08-25 14:30:45.123456

# 时间运算
tomorrow = now + timedelta(days=1)
last_week = now - timedelta(weeks=1)

功能特性

  • 支持日期时间创建、格式化、解析
  • 提供timedelta进行时间差计算
  • 时区基础操作(需搭配pytz

1.2 time模块

import time

# 时间戳操作
timestamp = time.time()  # 1692964245.123456
local_time = time.localtime(timestamp)
gm_time = time.gmtime(timestamp)

# 格式化输出
print(time.strftime("%Y-%m-%d %H:%M:%S", local_time))  # 2023-08-25 14:30:45

功能特性

  • 基于C库的时间处理接口
  • 高效处理时间戳与时间元组
  • 无时区感知能力

1.3 calendar模块

import calendar

# 生成月历
cal = calendar.month(2023, 8)
print(f"2023年8月日历:\n{cal}")

# 闰年判断
print(calendar.isleap(2024))  # True

功能特性

  • 生成文本日历
  • 计算周数、月天数等元数据
  • 无时间计算功能

二、时区转换与时间戳操作

2.1 pytz时区处理

from datetime import datetime
import pytz

# 创建时区感知对象
utc_time = datetime.now(pytz.utc)
ny_tz = pytz.timezone('America/New_York')
ny_time = utc_time.astimezone(ny_tz)

print(f"UTC时间: {utc_time}")
print(f"纽约时间: {ny_time}")

注意事项

  • 避免直接加减时区偏移量
  • 优先使用pytz内置时区名称
  • 夏令时转换自动处理

2.2 时间戳高级操作

# 获取不同精度时间戳
ts_second = int(time.time())         # 秒级
ts_millis = int(time.time() * 1000)  # 毫秒级

# 时间戳互转
dt = datetime.fromtimestamp(ts_second)
ts = dt.timestamp()

三、实战应用场景

3.1 定时任务调度

import schedule
import time

def job():
    print(f"任务执行时间: {datetime.now().isoformat()}")

schedule.every(10).minutes.do(job)  # 每10分钟执行

while True:
    schedule.run_pending()
    time.sleep(1)

3.2 日志时间格式化

import logging

logging.basicConfig(
    format='%(asctime)s - %(message)s',
    datefmt='%Y-%m-%dT%H:%M:%SZ',
    level=logging.INFO
)

logging.info("用户登录成功") 
# 输出: 2023-08-25T14:30:45Z - 用户登录成功

四、性能优化技巧

4.1 对象复用提升效率

# 低效写法
for _ in range(10000):
    d = datetime.now()

# 高效写法(单次获取基准时间)
base_time = datetime.now()
for _ in range(10000):
    d = base_time + timedelta(seconds=_)

​ 注:这里仅演示对象复用,以上两个代码块中输出的结果不相同

4.2 时间解析速度对比

from timeit import timeit

def use_strptime():
    datetime.strptime("2023-08-25", "%Y-%m-%d")

def use_split():
    parts = "2023-08-25".split('-')
    datetime(int(parts[0]), int(parts[1]), int(parts[2]))

print("strptime:", timeit(use_strptime, number=10000))  # 约0.15秒
print("split:   ", timeit(use_split, number=10000))    # 约0.03秒

五、综合练习题与答案

练习题列表

  1. 计算两个日期之间的工作日天数
  2. 生成指定月份的所有周五日期
  3. 将含闰秒的时间戳转换为datetime
  4. 实现跨时区会议时间转换工具
  5. 优化海量日期解析性能
  6. 检测时间序列中的连续日期段
  7. 开发秒级精确的倒计时器
  8. 处理夏令时转换边界问题
  9. 实现支持多种格式的日期解析器
  10. 编写时间处理单元测试用例

以下是10个Python时间处理练习题的完整答案代码及解析:


题目1:计算两个日期之间的工作日天数

from datetime import datetime, timedelta

def workdays(start: str, end: str) -> int:
    start_dt = datetime.strptime(start, "%Y-%m-%d")
    end_dt = datetime.strptime(end, "%Y-%m-%d")
    
    if start_dt > end_dt:
        raise ValueError("开始日期不能晚于结束日期")
    
    delta = (end_dt - start_dt).days + 1
    weekends = 0
    
    for day in range(delta):
        current = start_dt + timedelta(days=day)
        if current.weekday() >= 5:  # 5=周六,6=周日
            weekends += 1
            
    return delta - weekends

print(workdays("2023-08-01", "2023-08-31"))  # 输出23

题目2:生成指定月份的所有周五日期

import calendar
from datetime import date

def get_fridays(year: int, month: int):
    cal = calendar.monthcalendar(year, month)
    fridays = []
    for week in cal:
        if week[4] != 0:  # 第5列是周五
            fridays.append(date(year, month, week[4]).strftime("%Y-%m-%d"))
    return fridays

print(get_fridays(2023, 8))
# ['2023-08-04', '2023-08-11', '2023-08-18', '2023-08-25']

题目3:将含闰秒的时间戳转换为datetime

from datetime import datetime, timedelta

def handle_leap_second(ts: float):
    base_time = datetime(2016, 12, 31, 23, 59, 59)
    leap_window_start = datetime(2016, 12, 31, 23, 59, 0).timestamp()
    
    if leap_window_start <= ts < leap_window_start + 3:
        return base_time + timedelta(seconds=ts - leap_window_start)
    else:
        return datetime.fromtimestamp(ts)

print(handle_leap_second(1483228790.5))  # 2016-12-31 23:59:59.500000

题目4:实现跨时区会议时间转换工具

from datetime import datetime
import pytz

def convert_meeting_time(original_time: datetime, from_tz: str, to_tz: str):
    from_zone = pytz.timezone(from_tz)
    to_zone = pytz.timezone(to_tz)
    
    localized = from_zone.localize(original_time)
    return localized.astimezone(to_zone)

origin = datetime(2023, 8, 25, 14, 30)
print(convert_meeting_time(origin, "Asia/Shanghai", "America/New_York"))
# 2023-08-25 02:30:00-04:00

题目5:优化海量日期解析性能

def bulk_parse_dates(date_strings):
    parsed = []
    for s in date_strings:
        parts = s.split('-')
        parsed.append(datetime(int(parts[0]), int(parts[1]), int(parts[2])))
    return parsed

dates = ["2023-08-01"] * 100000
%timeit bulk_parse_dates(dates)  # 比strptime快3倍

题目6:检测时间序列中的连续日期段

from datetime import datetime, timedelta

def find_continuous_periods(dates):
    sorted_dates = sorted(datetime.strptime(d, "%Y-%m-%d") for d in dates)
    periods = []
    current_start = sorted_dates[0]
    
    for i in range(1, len(sorted_dates)):
        if (sorted_dates[i] - sorted_dates[i-1]).days != 1:
            periods.append((current_start, sorted_dates[i-1]))
            current_start = sorted_dates[i]
    periods.append((current_start, sorted_dates[-1]))
    
    return periods

dates = ["2023-08-01", "2023-08-02", "2023-08-04"]
print(find_continuous_periods(dates))
# [(2023-08-01, 2023-08-02), (2023-08-04, 2023-08-04)]

题目7:开发秒级精确的倒计时器

import time

def countdown(seconds: int):
    end_time = time.time() + seconds
    while time.time() < end_time:
        remaining = int(end_time - time.time())
        print(f"剩余时间: {remaining}秒", end='\r')
        time.sleep(1)
    print("\n时间到!")

countdown(10)

题目8:处理夏令时转换边界问题

def test_dst_transition():
    tz = pytz.timezone('America/New_York')
    dt = datetime(2023, 3, 12, 1, 30)  # 夏令时开始时间
    try:
        print(tz.localize(dt, is_dst=None))
    except pytz.AmbiguousTimeError:
        print("检测到存在歧义时间")
    except pytz.NonExistentTimeError:
        print("检测到不存在的时间")

test_dst_transition()  # 输出不存在的时间异常

题目9:实现支持多种格式的日期解析器

from dateutil.parser import parse

def flexible_parser(date_str):
    formats = [
        "%Y-%m-%d",
        "%Y/%m/%d",
        "%d %B %Y",
        "%Y%m%d"
    ]
    for fmt in formats:
        try:
            return datetime.strptime(date_str, fmt)
        except ValueError:
            continue
    return parse(date_str)  # 使用dateutil作为后备方案

print(flexible_parser("2023-08-25"))   # 标准格式
print(flexible_parser("25 August 2023"))  # 备用格式

题目10:编写时间处理单元测试用例

import unittest
from datetime import datetime

class TestDateTime(unittest.TestCase):
    def test_timezone_conversion(self):
        dt = datetime(2023, 8, 25, 12, 0)
        converted = convert_meeting_time(dt, "UTC", "Asia/Shanghai")
        self.assertEqual(converted.hour, 20)
        
    def test_leap_year(self):
        self.assertTrue(calendar.isleap(2024))
        self.assertFalse(calendar.isleap(2023))
        
    def test_workdays(self):
        self.assertEqual(workdays("2023-08-01", "2023-08-05"), 5)

if __name__ == '__main__':
    unittest.main()

关键知识点总结

  1. 时区处理:始终使用pytz库进行时区转换,避免手动计算偏移量
  2. 性能优化:批量处理时优先使用数值计算替代对象创建
  3. 异常处理:特别注意夏令时转换期间的非法时间(2:00-3:00可能不存在)
  4. 格式兼容:使用dateutil库作为多种日期格式解析的备用方案
  5. 测试要点:必须覆盖闰年、时区转换、夏令时等边界条件

结语

本文从基础操作到高级应用系统梳理了Python时间处理技术栈,针对时区转换、性能优化等难点给出解决方案。通过结合10个典型场景的练习题,读者可快速提升时序数据处理能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wolf犭良

谢谢您的阅读与鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值