2ND
This commit is contained in:
84
app/utils/response.py
Normal file
84
app/utils/response.py
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
API 響應處理工具
|
||||
|
||||
Author: PANJIT IT Team
|
||||
Created: 2025-09-02
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Dict, Any, List, Union
|
||||
from app.utils.timezone import to_taiwan_time, format_taiwan_time
|
||||
|
||||
|
||||
def convert_datetime_to_taiwan(data: Union[Dict, List, Any]) -> Union[Dict, List, Any]:
|
||||
"""遞迴轉換資料中的 datetime 欄位為台灣時間
|
||||
|
||||
Args:
|
||||
data: 要轉換的資料(字典、列表或其他)
|
||||
|
||||
Returns:
|
||||
轉換後的資料
|
||||
"""
|
||||
if isinstance(data, dict):
|
||||
result = {}
|
||||
for key, value in data.items():
|
||||
if isinstance(value, datetime):
|
||||
# 將 datetime 轉換為台灣時間的 ISO 字符串
|
||||
taiwan_dt = to_taiwan_time(value)
|
||||
result[key] = taiwan_dt.isoformat()
|
||||
elif key in ['created_at', 'updated_at', 'completed_at', 'processing_started_at', 'last_login', 'timestamp']:
|
||||
# 特定的時間欄位
|
||||
if isinstance(value, str):
|
||||
try:
|
||||
# 嘗試解析 ISO 格式的時間字符串
|
||||
dt = datetime.fromisoformat(value.replace('Z', '+00:00'))
|
||||
taiwan_dt = to_taiwan_time(dt)
|
||||
result[key] = taiwan_dt.isoformat()
|
||||
except:
|
||||
result[key] = value
|
||||
else:
|
||||
result[key] = convert_datetime_to_taiwan(value)
|
||||
else:
|
||||
result[key] = convert_datetime_to_taiwan(value)
|
||||
return result
|
||||
elif isinstance(data, list):
|
||||
return [convert_datetime_to_taiwan(item) for item in data]
|
||||
else:
|
||||
return data
|
||||
|
||||
|
||||
def create_taiwan_response(success: bool = True, data: Any = None, message: str = '',
|
||||
error: str = '', **kwargs) -> Dict[str, Any]:
|
||||
"""創建包含台灣時區轉換的 API 響應
|
||||
|
||||
Args:
|
||||
success: 是否成功
|
||||
data: 響應資料
|
||||
message: 成功訊息
|
||||
error: 錯誤訊息
|
||||
**kwargs: 其他參數
|
||||
|
||||
Returns:
|
||||
包含台灣時區的響應字典
|
||||
"""
|
||||
response = {
|
||||
'success': success,
|
||||
'timestamp': format_taiwan_time(datetime.now(), "%Y-%m-%d %H:%M:%S")
|
||||
}
|
||||
|
||||
if data is not None:
|
||||
response['data'] = convert_datetime_to_taiwan(data)
|
||||
|
||||
if message:
|
||||
response['message'] = message
|
||||
|
||||
if error:
|
||||
response['error'] = error
|
||||
|
||||
# 加入其他參數
|
||||
for key, value in kwargs.items():
|
||||
response[key] = convert_datetime_to_taiwan(value)
|
||||
|
||||
return response
|
104
app/utils/timezone.py
Normal file
104
app/utils/timezone.py
Normal file
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
時區工具函數
|
||||
|
||||
Author: PANJIT IT Team
|
||||
Created: 2025-09-02
|
||||
"""
|
||||
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from typing import Optional
|
||||
|
||||
# 台灣時區 UTC+8
|
||||
TAIWAN_TZ = timezone(timedelta(hours=8))
|
||||
|
||||
|
||||
def now_taiwan() -> datetime:
|
||||
"""取得當前台灣時間(UTC+8)"""
|
||||
return datetime.now(TAIWAN_TZ)
|
||||
|
||||
|
||||
def now_utc() -> datetime:
|
||||
"""取得當前 UTC 時間"""
|
||||
return datetime.now(timezone.utc)
|
||||
|
||||
|
||||
def to_taiwan_time(dt: datetime) -> datetime:
|
||||
"""將 datetime 轉換為台灣時間
|
||||
|
||||
Args:
|
||||
dt: datetime 物件(可能是 naive 或 aware)
|
||||
|
||||
Returns:
|
||||
台灣時區的 datetime 物件
|
||||
"""
|
||||
if dt is None:
|
||||
return None
|
||||
|
||||
# 如果是 naive datetime,假設為 UTC
|
||||
if dt.tzinfo is None:
|
||||
dt = dt.replace(tzinfo=timezone.utc)
|
||||
|
||||
# 轉換為台灣時區
|
||||
return dt.astimezone(TAIWAN_TZ)
|
||||
|
||||
|
||||
def to_utc_time(dt: datetime) -> datetime:
|
||||
"""將 datetime 轉換為 UTC 時間
|
||||
|
||||
Args:
|
||||
dt: datetime 物件(可能是 naive 或 aware)
|
||||
|
||||
Returns:
|
||||
UTC 時區的 datetime 物件
|
||||
"""
|
||||
if dt is None:
|
||||
return None
|
||||
|
||||
# 如果是 naive datetime,假設為台灣時間
|
||||
if dt.tzinfo is None:
|
||||
dt = dt.replace(tzinfo=TAIWAN_TZ)
|
||||
|
||||
# 轉換為 UTC
|
||||
return dt.astimezone(timezone.utc)
|
||||
|
||||
|
||||
def format_taiwan_time(dt: datetime, format_str: str = "%Y-%m-%d %H:%M:%S") -> str:
|
||||
"""格式化台灣時間為字符串
|
||||
|
||||
Args:
|
||||
dt: datetime 物件
|
||||
format_str: 格式化字符串
|
||||
|
||||
Returns:
|
||||
格式化後的時間字符串
|
||||
"""
|
||||
if dt is None:
|
||||
return ""
|
||||
|
||||
taiwan_dt = to_taiwan_time(dt)
|
||||
return taiwan_dt.strftime(format_str)
|
||||
|
||||
|
||||
def parse_taiwan_time(time_str: str, format_str: str = "%Y-%m-%d %H:%M:%S") -> datetime:
|
||||
"""解析台灣時間字符串為 datetime
|
||||
|
||||
Args:
|
||||
time_str: 時間字符串
|
||||
format_str: 解析格式
|
||||
|
||||
Returns:
|
||||
台灣時區的 datetime 物件
|
||||
"""
|
||||
naive_dt = datetime.strptime(time_str, format_str)
|
||||
return naive_dt.replace(tzinfo=TAIWAN_TZ)
|
||||
|
||||
|
||||
# 為了向後兼容,提供替代 datetime.utcnow() 的函數
|
||||
def utcnow() -> datetime:
|
||||
"""取得當前 UTC 時間(替代 datetime.utcnow())
|
||||
|
||||
注意:新代碼建議使用 now_taiwan() 或 now_utc()
|
||||
"""
|
||||
return now_utc().replace(tzinfo=None) # 返回 naive UTC datetime 以保持兼容性
|
Reference in New Issue
Block a user