get_beijing_time.py•5.05 kB
import logging
from datetime import datetime, timezone, timedelta
from typing import Optional
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field
import requests
# 设置日志
router = APIRouter()
logger = logging.getLogger("get_beijing_time")
class BeijingTimeResponse(BaseModel):
"""北京时间响应模型"""
beijing_time: str = Field(..., description="北京时间,格式:YYYY-MM-DD HH:MM:SS")
timestamp: int = Field(..., description="Unix时间戳")
timezone: str = Field(..., description="时区信息")
source: str = Field(..., description="时间来源")
formatted_time: str = Field(..., description="格式化的时间显示")
def get_network_time() -> Optional[datetime]:
"""从网络获取准确时间"""
try:
# 尝试从世界时钟API获取时间
response = requests.get(
"http://worldtimeapi.org/api/timezone/Asia/Shanghai", timeout=5
)
if response.status_code == 200:
data = response.json()
# 解析ISO格式的时间字符串
time_str = data["datetime"]
# 移除时区信息后的部分,只保留到秒
if "+" in time_str:
time_str = time_str.split("+")[0]
elif "T" in time_str and "." in time_str:
# 处理包含毫秒的格式
time_str = time_str.split(".")[0]
return datetime.fromisoformat(time_str)
except Exception as e:
logger.warning(f"从worldtimeapi获取时间失败: {str(e)}")
try:
# 备用方案:从另一个时间API获取
response = requests.get(
"http://api.timezonedb.com/v2.1/get-time-zone?key=demo&format=json&by=zone&zone=Asia/Shanghai",
timeout=5,
)
if response.status_code == 200:
data = response.json()
timestamp = int(data["timestamp"])
return datetime.fromtimestamp(timestamp, tz=timezone(timedelta(hours=8)))
except Exception as e:
logger.warning(f"从timezonedb获取时间失败: {str(e)}")
return None
def get_local_beijing_time() -> datetime:
"""获取本地计算的北京时间"""
# 创建北京时区(UTC+8)
beijing_tz = timezone(timedelta(hours=8))
# 获取当前UTC时间并转换为北京时间
utc_now = datetime.now(timezone.utc)
beijing_time = utc_now.astimezone(beijing_tz)
return beijing_time
@router.get(
"/api/beijing_time",
response_model=BeijingTimeResponse,
operation_id="get_beijing_time",
tags=["时间服务"],
)
async def get_beijing_time():
"""
获取当前的北京时间
**功能说明:**
- 优先从网络时间服务获取准确的北京时间
- 如果网络获取失败,则使用本地系统时间计算北京时间
- 返回格式化的时间信息,包括时间戳和时区信息
**返回结果:**
- beijing_time: 北京时间字符串,格式:YYYY-MM-DD HH:MM:SS
- timestamp: Unix时间戳
- timezone: 时区信息
- source: 时间来源(网络或本地)
- formatted_time: 友好的格式化时间显示
**使用示例:**
```
GET /api/beijing_time
```
**响应示例:**
```json
{
"beijing_time": "2024-01-15 14:30:25",
"timestamp": 1705298425,
"timezone": "Asia/Shanghai (UTC+8)",
"source": "网络时间服务",
"formatted_time": "2024年01月15日 14时30分25秒"
}
```
"""
try:
# 尝试从网络获取时间
network_time = get_network_time()
if network_time:
# 网络时间获取成功
beijing_time = network_time
source = "网络时间服务"
logger.info("成功从网络获取北京时间")
else:
# 网络时间获取失败,使用本地时间
beijing_time = get_local_beijing_time()
source = "本地系统时间"
logger.info("网络时间获取失败,使用本地系统时间")
# 格式化时间
time_str = beijing_time.strftime("%Y-%m-%d %H:%M:%S")
timestamp = int(beijing_time.timestamp())
formatted_time = beijing_time.strftime("%Y年%m月%d日 %H时%M分%S秒")
return BeijingTimeResponse(
beijing_time=time_str,
timestamp=timestamp,
timezone="Asia/Shanghai (UTC+8)",
source=source,
formatted_time=formatted_time,
)
except Exception as e:
logger.error(f"获取北京时间时发生错误: {str(e)}")
raise HTTPException(
status_code=500,
detail={
"error_type": "时间获取错误",
"message": f"获取北京时间失败: {str(e)}",
"suggestions": [
"检查网络连接是否正常",
"确认系统时间设置正确",
"稍后重试",
],
},
)