diff --git a/user_management/gmail_integration.py b/user_management/gmail_integration.py index 986941d..f5a2efe 100644 --- a/user_management/gmail_integration.py +++ b/user_management/gmail_integration.py @@ -588,15 +588,48 @@ class GmailIntegration: elif header['name'] == 'From': email_data['from'] = header['value'] elif header['name'] == 'Date': + date_value = header['value'] + logger.info(f"原始邮件日期字符串: '{date_value}'") + try: - date = parser.parse(header['value']) - # 转换为与Django时区一致的格式 - if hasattr(settings, 'USE_TZ') and settings.USE_TZ: - date = timezone.make_aware(date) + # 打印原始日期字符串信息 + import dateutil.parser as date_parser + import pytz + from django.utils import timezone + + # 先尝试解析日期 + date = date_parser.parse(date_value) + logger.info(f"解析后的日期对象: {date}, 是否有时区: {date.tzinfo is not None}") + + # 处理时区问题 + if date.tzinfo is not None: + # 已有时区的日期,转换为系统时区 + if hasattr(settings, 'TIME_ZONE'): + system_tz = pytz.timezone(settings.TIME_ZONE) + date = date.astimezone(system_tz) + logger.info(f"转换到系统时区后: {date}") + + # 如果需要naive datetime,删除时区信息 + if hasattr(settings, 'USE_TZ') and not settings.USE_TZ: + date = date.replace(tzinfo=None) + logger.info(f"移除时区信息后: {date}") + else: + # 无时区的日期,如果系统使用时区,添加时区信息 + if hasattr(settings, 'USE_TZ') and settings.USE_TZ: + try: + date = timezone.make_aware(date) + logger.info(f"添加时区信息后: {date}") + except Exception as tz_error: + logger.warning(f"添加时区信息失败: {str(tz_error)}") + + # 格式化为字符串 email_data['date'] = date.strftime('%Y-%m-%d %H:%M:%S') + logger.info(f"最终日期字符串: {email_data['date']}") + except Exception as e: - logger.error(f"解析日期失败: {str(e)}") - email_data['date'] = header['value'] + logger.error(f"解析日期失败: {str(e)}, 原始值: '{date_value}'") + # 保留原始值 + email_data['date'] = date_value # 定义一个递归函数来处理所有部分和附件 def process_parts(parts): @@ -843,10 +876,24 @@ class GmailIntegration: # 解析邮件日期为datetime对象 try: - date_obj = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S') - except ValueError: + # 先检查是否是时间戳格式 + if isinstance(date_str, str) and date_str.isdigit(): + # 如果是时间戳,直接转换 + date_obj = datetime.fromtimestamp(int(date_str)) + else: + # 尝试标准格式解析 + try: + date_obj = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S') + except ValueError: + # 如果标准格式解析失败,使用dateutil更灵活的解析 + import dateutil.parser as date_parser + date_obj = date_parser.parse(date_str) + # 如果解析出的日期有时区信息,转换为不带时区的日期 + if date_obj.tzinfo is not None: + date_obj = date_obj.replace(tzinfo=None) + except (ValueError, TypeError) as e: # 如果解析失败,使用当前时间 - logger.warning(f"无法解析邮件日期: {date_str},使用当前时间") + logger.warning(f"无法解析邮件日期: {date_str},错误: {str(e)},使用当前时间") date_obj = datetime.now() # 查找parent_id(查找日期早于当前邮件且最接近的消息) @@ -860,7 +907,20 @@ class GmailIntegration: # 保存消息到聊天历史,使用邮件实际日期 from django.utils import timezone - aware_date = timezone.make_aware(date_obj) if not timezone.is_aware(date_obj) else date_obj + + # 确保时区处理正确 + try: + # 检查date_obj是否已经是aware + if timezone.is_aware(date_obj): + aware_date = date_obj + logger.info(f"日期已经包含时区信息: {aware_date}") + else: + # 将naive转换为aware + aware_date = timezone.make_aware(date_obj) + logger.info(f"日期添加时区信息后: {aware_date}") + except Exception as tz_error: + logger.warning(f"时区转换失败: {str(tz_error)},使用当前时间") + aware_date = timezone.now() # 创建消息记录 chat_message = ChatHistory.objects.create( @@ -1013,14 +1073,28 @@ class GmailIntegration: # 从消息详情中提取时间戳 internal_date = message_detail.get('internalDate') if internal_date: - # 转换毫秒时间戳为datetime,不使用timezone-aware - email_date = datetime.fromtimestamp(int(internal_date)/1000) - # 如果系统设置了USE_TZ,再转换为timezone-aware - if hasattr(timezone, 'is_aware') and not timezone.is_aware(email_date): - email_date = timezone.make_aware(email_date) - date_str = email_date.strftime('%Y-%m-%d %H:%M:%S') + try: + # 转换毫秒时间戳为datetime + email_date = datetime.fromtimestamp(int(internal_date)/1000) + logger.info(f"从时间戳解析的日期: {email_date}") + + # 处理时区 + from django.utils import timezone + if hasattr(settings, 'USE_TZ') and settings.USE_TZ and not timezone.is_aware(email_date): + email_date = timezone.make_aware(email_date) + logger.info(f"添加时区信息后: {email_date}") + + date_str = email_date.strftime('%Y-%m-%d %H:%M:%S') + logger.info(f"最终格式化日期: {date_str}") + except Exception as tz_error: + logger.warning(f"处理邮件时间戳失败: {str(tz_error)},使用当前时间") + from django.utils import timezone + email_date = timezone.now() + date_str = email_date.strftime('%Y-%m-%d %H:%M:%S') else: - email_date = datetime.now() + logger.warning("邮件没有时间戳,使用当前时间") + from django.utils import timezone + email_date = timezone.now() date_str = email_date.strftime('%Y-%m-%d %H:%M:%S') except Exception as e: logger.warning(f"获取邮件时间戳失败: {str(e)}, 使用当前时间") @@ -1297,9 +1371,24 @@ class GmailIntegration: # 转换时间戳为datetime expiration_time = None if expiration: - # 将毫秒时间戳转换为timezone-aware的datetime - naive_time = datetime.fromtimestamp(int(expiration)/1000) - expiration_time = timezone.make_aware(naive_time) + try: + # 将毫秒时间戳转换为datetime + naive_time = datetime.fromtimestamp(int(expiration)/1000) + logger.info(f"从时间戳解析的日期: {naive_time}") + + # 如果系统使用时区,添加时区信息 + if hasattr(settings, 'USE_TZ') and settings.USE_TZ: + try: + expiration_time = timezone.make_aware(naive_time) + logger.info(f"添加时区信息后: {expiration_time}") + except Exception as tz_error: + logger.warning(f"添加时区信息失败: {str(tz_error)}") + expiration_time = naive_time + else: + expiration_time = naive_time + except Exception as conv_error: + logger.error(f"转换时间戳失败: {str(conv_error)}") + expiration_time = None credential.last_history_id = history_id credential.watch_expiration = expiration_time @@ -1608,15 +1697,55 @@ class GmailIntegration: logger.info(f"邮件已处理过,跳过: {message_id}") return True - # 解析邮件日期 - 使用普通datetime而非timezone-aware + # 解析邮件日期 date_str = email_data.get('date', '') + logger.info(f"开始解析邮件日期: '{date_str}'") + try: - date_obj = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S') + # 先检查是否是时间戳格式 + if isinstance(date_str, str) and date_str.isdigit(): + # 如果是时间戳,直接转换 + date_obj = datetime.fromtimestamp(int(date_str)) + logger.info(f"从时间戳解析的日期: {date_obj}") + else: + # 尝试标准格式解析 + try: + date_obj = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S') + logger.info(f"从标准格式解析的日期: {date_obj}") + except ValueError: + # 如果标准格式解析失败,使用dateutil更灵活的解析 + import dateutil.parser as date_parser + date_obj = date_parser.parse(date_str) + logger.info(f"从灵活格式解析的日期: {date_obj}, 是否有时区: {date_obj.tzinfo is not None}") + + # 如果解析出的日期有时区信息且系统不使用时区,转换为不带时区的日期 + if date_obj.tzinfo is not None and hasattr(settings, 'USE_TZ') and not settings.USE_TZ: + date_obj = date_obj.replace(tzinfo=None) + logger.info(f"移除时区信息后: {date_obj}") + # 确保时区处理正确 from django.utils import timezone - aware_date = timezone.make_aware(date_obj) if not timezone.is_aware(date_obj) else date_obj - except (ValueError, TypeError): - logger.warning(f"无法解析邮件日期: {date_str},使用当前时间") + try: + # 检查date_obj是否已经是aware + if timezone.is_aware(date_obj): + aware_date = date_obj + logger.info(f"日期已经包含时区信息: {aware_date}") + else: + # 如果系统使用时区且日期没有时区信息,添加时区 + if hasattr(settings, 'USE_TZ') and settings.USE_TZ: + aware_date = timezone.make_aware(date_obj) + logger.info(f"日期添加时区信息后: {aware_date}") + else: + # 如果系统不使用时区,保持naive状态 + aware_date = date_obj + logger.info(f"保持日期不带时区: {aware_date}") + except Exception as tz_error: + logger.warning(f"时区转换失败: {str(tz_error)},使用当前时间") + aware_date = timezone.now() + + except (ValueError, TypeError) as e: + logger.warning(f"无法解析邮件日期: '{date_str}',错误: {str(e)},使用当前时间") + from django.utils import timezone aware_date = timezone.now() # 查找适合的parent_id: 使用创建时间排序