首页
学习
活动
专区
圈层
工具
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Python时间日期模块time,datetime使用详解及高阶使用技巧

1. time模块解析

1.1 time模块核心函数剖析

time()函数

def time() -> float

功能

返回当前时间戳(1970纪元后经过的浮点秒数)

底层原理

调用系统级time()函数,精度通常达到微秒级

性能对比

import timeit

print(timeit.timeit('time.time()', setup='import time', number=1000000))

# 典型结果:???秒(百万次调用)

sleep()函数精度测试

def test_sleep_precision():

  durations = [0.001, 0.01, 0.1, 1]  # 测试不同休眠时长

  for d in durations:

      start = time.time()

      time.sleep(d)

      actual = time.time() - start

      print(f"请求休眠 {d:.3f}s, 实际休眠 {actual:.6f}s, 误差 {abs(actual-d)*1000:.3f}ms")

1.2 时间格式化高级技巧

strftime()格式符号扩展表

多语言时间格式化

import locale

import time

defmultilingual_time():

  locales = ['en_US', 'zh_CN', 'ja_JP', 'de_DE']

for loc in locales:

try:

          locale.setlocale(locale.LC_TIME, loc)

print(f"{loc}: {time.strftime('%c')}")

except locale.Error:

print(f"Locale {loc} not available")

# 输出示例:

# en_US: Fri Jul 15 15:30:45 2023

# zh_CN: 2023年07月15日 15时30分45秒

2. datetime模块高阶应用

2.1 时区处理深度解析

pytz时区陷阱与解决方案

from datetime import datetime

import pytz

# 错误示范(直接附加时区)

dt = datetime(2023,7,15,12,0)

tz = pytz.timezone('Asia/Shanghai')

try:

  dt.replace(tzinfo=tz)  # 会得到错误时区偏移

except Exception as e:

print(f"错误:{e}")

# 正确做法(使用localize)

proper_dt = tz.localize(datetime(2023,7,15,12,0))

print(f"正确时区时间:{proper_dt}")

# 夏令时处理示例

ny_tz = pytz.timezone('America/New_York')

dt_summer = ny_tz.localize(datetime(2023,7,15,12,0))

dt_winter = ny_tz.localize(datetime(2023,12,15,12,0))

print(f"纽约夏令时:{dt_summer} (UTC偏移:{dt_summer.utcoffset()})")

print(f"纽约冬令时:{dt_winter} (UTC偏移:{dt_winter.utcoffset()})")

2.2 高性能时间运算

datetime与numpy.datetime64性能对比

import numpy as np

from datetime import datetime, timedelta

import timeit

# 创建测试数据

n = 1000000

py_dates = [datetime(2023,1,1) + timedelta(days=i) for i inrange(n)]

np_dates = np.arange('2023-01-01', periods=n, dtype='datetime64[D]')

# 时间增量运算测试

defpy_test():

return [d + timedelta(days=30) for d in py_dates]

defnp_test():

return np_dates + np.timedelta64(30, 'D')

# 性能测试

print("Python datetime:")

%timeit py_test()

print("\nNumPy datetime64:")

%timeit np_test()

# 输出示例:

# Python datetime: 500-800ms

# NumPy datetime64: 5-20ms

3. 时间处理设计模式

3.1 时间工厂模式

from abc import ABC, abstractmethod

from datetime import datetime

import pytz

classTimeFactory(ABC):

  @abstractmethod

defnow(self):

pass

classUTCTimeFactory(TimeFactory):

defnow(self):

return datetime.now(pytz.UTC)

classLocalTimeFactory(TimeFactory):

def__init__(self, timezone='Asia/Shanghai'):

self.tz = pytz.timezone(timezone)

defnow(self):

return datetime.now(self.tz)

# 使用示例

deflog_event(factory: TimeFactory, message: str):

print(f"[{factory.now().isoformat()}] {message}")

# 测试不同工厂

log_event(UTCTimeFactory(), "系统事件1")

log_event(LocalTimeFactory(), "本地事件1")

log_event(LocalTimeFactory('America/New_York'), "纽约事件1")

3.2 时间范围处理模式

from dataclasses import dataclass

from datetime import datetime, timedelta

@dataclass

classTimeRange:

  start: datetime

  end: datetime

def__post_init__(self):

ifself.start > self.end:

raise ValueError("开始时间不能晚于结束时间")

defcontains(self, dt: datetime) -> bool:

returnself.start <= dt <= self.end

defoverlap(self, other: 'TimeRange') -> bool:

return (self.contains(other.start) or

self.contains(other.end) or

              other.contains(self.start))

defsplit(self, delta: timedelta) -> list['TimeRange']:

      ranges = []

      current = self.start

while current < self.end:

          next_dt = min(current + delta, self.end)

          ranges.append(TimeRange(current, next_dt))

          current = next_dt

return ranges

# 使用示例

tr = TimeRange(

  datetime(2023,7,1),

  datetime(2023,7,31)

)

print("7月包含15号:", tr.contains(datetime(2023,7,15)))

print("按周拆分:", tr.split(timedelta(weeks=1)))

4. 金融时间处理专题

4.1 交易日历处理

import pandas as pd

from pandas.tseries.holiday import AbstractHolidayCalendar, Holiday

from pandas.tseries.offsets import CustomBusinessDay

classChinaTradingCalendar(AbstractHolidayCalendar):

  rules = [

      Holiday('元旦', month=1, day=1),

      Holiday('春节', month=1, day=22),  # 示例日期

      Holiday('清明节', month=4, day=5),

      Holiday('劳动节', month=5, day=1),

      Holiday('端午节', month=6, day=22),

      Holiday('中秋节', month=9, day=29),

      Holiday('国庆节', month=10, day=1),

  ]

defget_trading_days(start, end):

  cal = ChinaTradingCalendar()

return pd.bdate_range(start, end, freq=CustomBusinessDay(calendar=cal))

# 使用示例

trading_days = get_trading_days('2023-01-01', '2023-12-31')

print(f"2023年交易日数量: {len(trading_days)}")

print("前5个交易日:", trading_days[:5])

4.2 时间序列重采样技巧

import pandas as pd

import numpy as np

# 创建高频交易数据

np.random.seed(42)

date_rng = pd.date_range('2023-07-15 09:30', '2023-07-15 15:00', freq='30s')

price = np.cumsum(np.random.randn(len(date_rng)) * 0.1 + 100)

volume = np.random.randint(100, 1000, len(date_rng))

df = pd.DataFrame({'price': price, 'volume': volume}, index=date_rng)

# 复杂重采样

defresample_tick_data(df):

# 1分钟K线

  ohlc = df['price'].resample('1T').ohlc()

  vol = df['volume'].resample('1T').sum()

# 添加VWAP(成交量加权平均价)

  df['price_vol'] = df['price'] * df['volume']

  vwap = df['price_vol'].resample('1T').sum() / vol

  result = pd.concat([ohlc, vol, vwap], axis=1)

  result.columns = ['open', 'high', 'low', 'close', 'volume', 'vwap']

return result.dropna()

# 应用重采样

kline_data = resample_tick_data(df)

print(kline_data.head())

5. 时间处理性能优化

5.1 Cython加速时间计算

# 文件:datetime_cy.pyx

import cython

from datetime import datetime, timedelta

@cython.boundscheck(False)

@cython.wraparound(False)

defprocess_dates(dates_list):

  cdef int i, n = len(dates_list)

  cdef list result = []

  cdef datetime dt, new_dt

for i inrange(n):

      dt = dates_list[i]

      new_dt = dt + timedelta(days=30)

      result.append(new_dt)

return result

# 编译后使用对比

import timeit

from datetime import datetime, timedelta

# Python原生实现

defpy_process(dates_list):

return [d + timedelta(days=30) for d in dates_list]

# 测试数据

dates = [datetime(2023,1,1) + timedelta(days=i) for i inrange(100000)]

# 性能对比

print("Python:", timeit.timeit('py_process(dates)', globals=globals(), number=100))

print("Cython:", timeit.timeit('process_dates(dates)', globals=globals(), number=100))

5.2 避免常见性能陷阱

陷阱1:频繁创建datetime对象

# 错误做法

defslow_function(count):

  result = []

for i inrange(count):

      result.append(datetime.now())  # 每次循环都创建新对象

return result

# 优化方案

deffast_function(count):

  now = datetime.now  # 先获取函数引用

return [now() for _ inrange(count)]  # 减少属性查找开销

陷阱2:不必要的时区转换

# 错误做法

defconvert_many_times(dt):

  tz_sh = pytz.timezone('Asia/Shanghai')

  tz_ny = pytz.timezone('America/New_York')

for _ inrange(1000):

      sh_dt = dt.astimezone(tz_sh)

      ny_dt = dt.astimezone(tz_ny)

# ...

# 优化方案

defconvert_once(dt):

  tz_sh = pytz.timezone('Asia/Shanghai')

  tz_ny = pytz.timezone('America/New_York')

  sh_dt = dt.astimezone(tz_sh)

  ny_dt = dt.astimezone(tz_ny)

for _ inrange(1000):

# 使用已转换的时间

pass

6. 时间处理测试策略

6.1 时间模拟测试框架

import time

from datetime import datetime, timedelta

from unittest import TestCase, mock

classTimeMachine:

def__init__(self, initial_time=None):

self._now = initial_time or datetime.now()

deftravel(self, days=0, seconds=0):

self._now += timedelta(days=days, seconds=seconds)

defnow(self):

returnself._now

classTestTimeSensitive(TestCase):

defsetUp(self):

self.tm = TimeMachine(datetime(2023,7,15))

# 模拟datetime.now

self.datetime_patcher = mock.patch('datetime.datetime')

      mock_datetime = self.datetime_patcher.start()

      mock_datetime.now.side_effect = self.tm.now

# 模拟time.time

self.time_patcher = mock.patch('time.time')

      mock_time = self.time_patcher.start()

      mock_time.side_effect = lambda: self.tm.now().timestamp()

deftearDown(self):

self.datetime_patcher.stop()

self.time_patcher.stop()

deftest_time_based_logic(self):

from myapp import check_deadline  # 被测函数

# 测试截止日期前

self.assertTrue(check_deadline())

# 时间旅行到截止日期后

self.tm.travel(days=1)

self.assertFalse(check_deadline())

6.2 时间模糊测试

import random

from datetime import datetime, timedelta

from hypothesis import given, strategies as st

# 定义时间生成策略

defdatetime_strategy():

return st.datetimes(

      min_value=datetime(1970,1,1),

      max_value=datetime(2100,1,1),

      timezones=st.timezones()

  )

@given(dt1=datetime_strategy(), dt2=datetime_strategy())

deftest_datetime_arithmetic(dt1, dt2):

# 测试时间差计算

  delta = dt2 - dt1

assert dt1 + delta == dt2

# 测试时间比较

if dt1 < dt2:

assert dt1 + timedelta(seconds=1) <= dt2

# 运行测试

if __name__ == "__main__":

  test_datetime_arithmetic()

7. 时间处理实践总结

时区黄金法则

存储:始终使用UTC时间存储

转换:只在显示时转换为本地时间

处理:使用aware datetime对象(带时区)

性能关键点

批量操作使用numpy.datetime64

避免在循环中重复创建时间对象

缓存频繁使用的时间计算结果

代码健壮性

处理闰秒、夏令时等边界情况

验证时间范围有效性(如2月30日)

使用try/except处理时区转换异常

测试策略

使用freezegun或模拟对象测试时间敏感代码

包含跨时区、跨夏令时的测试用例

对时间计算进行模糊测试

架构设计

采用时间工厂模式统一时间获取

定义明确的时间范围处理类

隔离时间相关代码以便测试和维护

通过掌握这些技巧,我们将能够处理各种复杂的时间日期场景,构建出健壮、高效且易于维护的时间相关代码。

更新日期:2025-05-11

交流讨论:欢迎在评论区留言!

重要提示:本文主要是记录自己的学习与实践过程,所提内容或者观点仅代表个人意见,只是我以为的,不代表完全正确,不喜请勿关注。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OuAwArl8O335zz9wfIF0Y5rg0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券