
背景需求
微信理财通有一个“定期+”,

可以买2个月60天、3个月90天、4个月120天

到期可以自动退款零钱通


我觉得这个可以做一个“强制定期”
1、每月8日到期,金额取出还“银行信用卡”
2、每月20日到期,金额取出还“支付宝花呗”
买定期,就可以防止被其他用途占用
Deepseek代码设计


这是一个需要精确计算的问题,因为理财产品的赎回规则各不相同。要让资金在 2026年5月20日 当天到账,最稳妥的购买日期是2026年3月21日。
下面为你详细拆解计算过程和需要注意的关键点:
1. 核心计算公式
要实现“资金在指定日期当天到账”的目标,你需要倒推计算。通常的规则是:
购买日期 + 产品期限(60天) = 资金到账日期
-
产品期限:60天
-
目标到账日:2026年5月20日
-
计算购买日:2026年5月20日,往前倒数60天。
2. 关键变量:产品确认和赎回规则
“购买日期”并非一个模糊的概念,它具体指你成功提交购买申请,且份额得到确认的那一天。不同产品的规则差异很大,这是最需要注意的地方:
-
标准情况 (T+1确认,T+0/1到账):
-
这是最常见的规则。如果你在交易日当天(T日)15:00前购买,份额在下一个交易日(T+1日)确认并开始计息 -3-6。
-
产品到期后,资金通常在到期日当天(T+0)或下一个交易日(T+1)到账 -3-8。
-
计算方式:在这种情况下,你需要在 2026年3月21日(星期六) 购买。由于3月21日是周六,属于非交易日,你的购买申请会顺延到下一个交易日(3月23日,周一)才被受理并确认份额 -6-8。
-
确认日:2026年3月23日
-
到期日:2026年3月23日 + 60天 = 2026年5月22日。这已经晚于你的目标日期。
-
-
重要提示:因为周末的存在,你实际上无法在3月21日“购买”并让它在当天确认份额。为了精确控制在5月20日当天到账,你需要寻找那些在周末也能确认份额,或者有特殊规则的产品。最安全的做法是向前再推一个交易日,即在3月20日(周五)15:00前完成购买,这样:
-
确认日:2026年3月23日(周一)
-
到期日:2026年5月22日(到账日如果是T+0,则仍为5月22日,与目标差2天)
-
-
-
封闭期/开放期产品:
-
很多定期理财产品有固定的“开放期”,你只能在规定的几天内买入或赎回 -2-5-7。如果60天定期产品是这种类型,你必须确保2026年3月20日前后在产品的一个开放期内,否则无法购买。
-
3. 给你的行动建议
要确保万无一失,强烈建议你按照以下步骤操作:
锁定目标产品:先确定你要购买的具体是哪一款60天定期理财产品。
仔细阅读产品说明书:在说明书中找到关于“申购确认日”和“赎回到账日”的条款。这是最准确的依据。你需要弄清楚:
-
我购买的申请,几天后份额才正式确认并开始算收益?(通常是T+1)
-
产品到期后,钱是当天(T+0)就到账,还是下一个工作日(T+1)才到账?
模拟倒推计算:
-
假设产品是“T+1确认份额,到期日当天到账”。那么,要让5月20日到账,产品的“到期日”必须是5月20日。往前推60天,得到“份额确认日”应为3月21日。那么,你就需要在3月20日(周五)交易时间结束前(15:00前) 完成购买,这样份额才能在3月23日(周一)确认,并在5月22日到期。这比你的目标晚了2天。
-
假设产品是“T+1确认份额,到期日后一个工作日(T+1)到账”。要让5月20日到账,到期日就需是5月19日。往前推60天,份额确认日为3月20日。那么你就需要在3月19日(周四)交易时间结束前完成购买。
总结一下: 最理想的情况是找到一个“到期日当天到账”的产品,并在2026年3月20日(周五)15:00之前完成购买。这样,资金有较大概率在5月22日到账。要精准实现5月20日当天到账,市面上绝大多数标准T+1确认的产品都无法做到,除非是那些份额确认和赎回到账都有特殊“T+0”规则的产品。
由于不同产品的交易规则确实存在差异,方便告诉我你具体看中了哪一款理财产品吗?我可以帮你精确计算一下最合适的购买时间。


根据你提供的信息,这个情况属于非交易时间购买 + 自然日持有,计算逻辑如下:
结论: 你一共存了 65天(从确认日开始计算收益,持有至到期日)。
以下是详细的计算过程:
第一步:确认份额的时间
-
购买时间:3月7日(周六)15:10。
-
规则:如果你是在周末(非交易日)或者交易日15:00之后购买,通常会被视为下一个交易日的申请。
-
下一个交易日:假设3月9日(周一)是交易日。
-
确认日:大多数理财产品实行T+1确认,即3月9日申请,份额在 3月10日(周二) 确认,并从3月10日开始计算收益。
第二步:计算持有天数
由于产品期限是“60天定期”,这里的60天通常指的是自然日,从确认日次日凌晨开始计算。
-
起息日(持有第1天):3月10日
-
到期日(理论):3月10日 + 60天 = 5月9日(需要核对月份天数:3月10日到4月10日31天,4月10日到5月10日30天,合计61天?这里需要精确逐日计算,我们按日历推演一下)
精确日历推演:
3月:3月10日 – 3月31日,共 22天(包含10日,不包含31日?不,计算持有是从10日到9日为一个周期,我们按包含关系算:3月10日到4月9日是31天,但这里我们直接算到5月9日)
-
更准确的计算:3月剩余天数:3月10日到3月31日 = 22天(因为10日算第一天,31日算第22天?我们换一种算法,用日期差工具逻辑:3月10日到4月9日是31天,3月10日到5月9日是61天?我们来数一下:
-
3月10日——3月31日:22天(含10日)
-
4月1日——4月30日:30天
-
5月1日——5月9日:9天
-
合计:22+30+9 = 61天
-
第三步:理解“到期时5月11日24:00前”
你提到产品描述说“到期时5月11日24:00前”,这意味着该产品的实际到账日(资金回到你账户的时间)是5月11日。
-
这意味着什么? 说明该产品可能是 “到期日后一个交易日(T+1)到账” 的产品。
-
5月9日是周六(非工作日),通常顺延到下一个工作日(5月11日,周一)进行资金清算和划拨。
-
所以,虽然产品存了 61天(收益计算到5月9日),但资金实际可用是在5月11日。
总结
-
实际存期(用于计算收益):61天(从3月10日到5月9日)。
-
资金占用时间:从3月7日扣款到5月11日到账,占用了更长时间,但收益只算61天。
特别提示: 这个计算是基于“周末购买顺延至周一确认”的通用规则。不同的银行或理财平台可能会有细微差别(例如部分产品周末购买周一才扣款,周二才起息)。
为了确保完全准确,建议你查看该产品的具体说明书,找到“认购/申购确认日”和“到期日”的定义。如果你手头有产品的具体名称或条款,也可以告诉我,我帮你进一步核对。


基于你之前提供的购买规则(周末/非交易时间购买,份额T+1确认,资金T+1到账),要确保5月20日当天资金到账,最稳妥的购买时间是:
2026年3月20日(周五)15:00 之前
以下是详细的时间线推演,说明为什么是这个时间点:
精确时间线计算(倒推法)
要实现 5月20日(周三)资金到账,根据你的产品规则,我们需要倒着推算每一步:
最终目标: 5月20日(周三)资金到账。
规则前提: 你之前提到“到期时5月11日24:00前到账”,这表明产品是 “T+1到账”(即到期日后一个工作日资金才到账)。
-
因为资金要在5月20日(周三)到账,那么 产品的“到期日”必须是5月19日(周二)。
产品期限: 60天。
-
到期日是5月19日,往前推60天,得到 “份额确认日”应为3月20日。
份额确认规则: T+1确认。
-
要让份额在3月20日(周五)确认,那么你必须在 3月19日(周四)15:00 之前 完成购买。
为什么会建议3月20日(周五)15:00前?
你可能会问,为什么我建议的是3月20日,而计算出来的是3月19日?
这是因为“倒推法”是最理想化的数学计算,但在实际操作中,需要考虑周末顺延的影响。以下是两种可行的方案对比:
方案A(最精准):3月19日(周四)15:00前购买
-
购买日: 3月19日(周四)
-
确认日: 3月20日(周五)——持有第1天
-
到期日: 3月20日 + 60天 = 5月19日(周二)
-
到账日: 到期日 + 1个工作日 = 5月20日(周三)
-
结果: ✅ 完美达标
方案B(次优选,也是我最初推荐的):3月20日(周五)15:00前购买
-
购买日: 3月20日(周五)
-
确认日: 3月23日(周一)——因为周六日非工作日,顺延
-
到期日: 3月23日 + 60天 = 5月22日(周五)
-
到账日: 到期日 + 1个工作日。如果5月22日(周五)到期,T+1到账是指下一个工作日,即 5月25日(周一)。
-
结果: ❌ 晚了5天
为什么会有这样的偏差?
关键问题出在你之前提到的产品特性:“到期时5月11日24:00前”。 这个描述暗示了该产品在遇到周末或节假日时,到期日和到账日都会顺延。如果按照3月20日购买,确认日被周末顺延到了周一,整个持有周期就往后推了,导致到期日也顺延到了5月22日。
最终行动建议
首选方案:3月19日(周四)15:00前购买。
-
这是基于“T+1确认,T+1到账”规则得出的最精准时间点。
确认产品规则: 务必在购买前看一眼产品说明书,确认两个关键条款:
-
起息日(确认日): 是否是T+1?
-
到账日: 是否是“到期日后一个工作日”?
设置日历提醒: 3月19日(周四)定个闹钟,在下午3点前完成操作。
这样操作下来,你的资金大概率能在5月20日当天到账。
AI计算了购买日和到期日,也考虑了周五周六周日购买的延后性











AI写了好多次,最终获得正式版本

'''
微信定期储蓄60天、90天、120天,倒退测试买入时间,考虑周五周六周日购买要延后
每月8日取出换银行信用卡,每月20日到账取出支付宝花呗
Deepseek、阿夏
20260308
'''
from datetime import datetime, timedelta
import pandas as pd
from typing import Dict, List
import os
import re
from openpyxl.utils import get_column_letter
from openpyxl.styles import Alignment
class PurchaseDateCalculator:
"""理财产品购买日期计算器
基于以下规则:
– 产品期限:60天/90天/120天
– 份额确认:T+1(交易日确认)
– 资金到账:T+1(到期日后一个交易日到账)
– 购买时间:需在交易日15:00前
"""
def __init__(self, year: int = 2026):
"""
初始化计算器
Args:
year: 目标年份,默认为2026年
"""
self.year = year
# 生成该年的所有交易日(简化版:排除周末)
self.trading_days = self._generate_trading_days()
def _generate_trading_days(self) -> List[datetime]:
"""生成交易日列表(简化版:周一至周五为交易日)"""
start_date = datetime(self.year, 1, 1)
end_date = datetime(self.year, 12, 31)
trading_days = []
current = start_date
while current <= end_date:
# 周一至周五为交易日(0=周一,6=周日)
if current.weekday() < 5:
trading_days.append(current)
current += timedelta(days=1)
return trading_days
def _is_trading_day(self, date: datetime) -> bool:
"""判断是否为交易日"""
return date.weekday() < 5
def _get_next_trading_day(self, date: datetime) -> datetime:
"""获取下一个交易日"""
next_day = date + timedelta(days=1)
while not self._is_trading_day(next_day):
next_day += timedelta(days=1)
return next_day
def _get_previous_trading_day(self, date: datetime) -> datetime:
"""获取上一个交易日"""
prev_day = date – timedelta(days=1)
while not self._is_trading_day(prev_day):
prev_day -= timedelta(days=1)
return prev_day
def _parse_date_string(self, date_str: str) -> datetime:
"""
解析日期字符串,支持多种格式
支持的格式:
– "5月20日"
– "5/20"
– "5-20"
– "2026-5-20"
– "2026/5/20"
– "2026年5月20日"
"""
date_str = date_str.strip()
try:
# 尝试解析完整日期格式(包含年份)
if '年' in date_str and '月' in date_str and '日' in date_str:
# 格式:2026年5月20日
parts = date_str.replace('年', ' ').replace('月', ' ').replace('日', '').split()
if len(parts) == 3:
year, month, day = map(int, parts)
return datetime(year, month, day)
# 尝试解析带分隔符的完整日期
for separator in ['-', '/']:
if separator in date_str and len(date_str.split(separator)) == 3:
parts = date_str.split(separator)
if len(parts) == 3:
year, month, day = map(int, parts)
return datetime(year, month, day)
# 尝试解析只有月和日的格式
if '月' in date_str and '日' in date_str:
# 格式:5月20日
month, day = map(int, date_str.replace('月', ' ').replace('日', '').split())
return datetime(self.year, month, day)
# 尝试解析月/日或月-日格式
for separator in ['/', '-']:
if separator in date_str:
parts = date_str.split(separator)
if len(parts) == 2:
month, day = map(int, parts)
return datetime(self.year, month, day)
# 如果都失败,尝试直接分割
month, day = map(int, date_str.split())
return datetime(self.year, month, day)
except Exception as e:
raise ValueError(f"无法解析日期格式:{date_str},请使用如'5月20日'、'5/20'、'2026-5-20'等格式")
def _sanitize_filename(self, filename: str) -> str:
"""清理文件名,移除非法字符"""
# Windows文件名不能包含的字符:\\ / : * ? " < > |
illegal_chars = r'[\\\\/*?:"<>|]'
return re.sub(illegal_chars, '_', filename)
def _auto_adjust_column_width(self, worksheet):
"""
自动调整Excel列宽(基于工作表对象)
Args:
worksheet: openpyxl工作表对象
"""
for column in worksheet.columns:
max_length = 0
column_letter = get_column_letter(column[0].column)
for cell in column:
try:
if cell.value:
# 计算单元格内容的长度(中文字符算2个长度)
cell_value = str(cell.value)
length = 0
for char in cell_value:
if '\\u4e00' <= char <= '\\u9fff': # 中文字符范围
length += 2
else:
length += 1
if length > max_length:
max_length = length
except:
pass
# 设置最小宽度为10,最大宽度为60
adjusted_width = min(max(max_length + 2, 10), 60)
worksheet.column_dimensions[column_letter].width = adjusted_width
def _apply_center_alignment(self, worksheet):
"""
设置单元格居中对齐
Args:
worksheet: openpyxl工作表对象
"""
# 遍历所有行和列
for row in worksheet.iter_rows():
for cell in row:
# 设置水平和垂直居中对齐
cell.alignment = Alignment(horizontal='center', vertical='center')
def calculate_purchase_date(self, target_date_str: str, days: int) -> Dict:
"""
计算指定期限的最适合购买日期
Args:
target_date_str: 目标到账日期
days: 产品期限(60/90/120天)
Returns:
包含购买日期和相关信息的字典
"""
# 解析目标日期
target_date = self._parse_date_string(target_date_str)
# 步骤1:根据T+1到账规则,推算到期日
# 资金T+1到账,所以到账日 = 到期日 + 1个工作日
# 因此:到期日 = 到账日前一个工作日
maturity_date = self._get_previous_trading_day(target_date)
# 步骤2:根据产品期限,推算确认日
# 确认日 + days = 到期日
confirm_date = maturity_date – timedelta(days=days)
# 步骤3:根据确认日,推算购买日
# 份额T+1确认,所以确认日 = 购买日 + 1个工作日
# 因此:购买日 = 确认日前一个工作日
purchase_date = self._get_previous_trading_day(confirm_date)
# 生成完整的时间线
timeline = self._generate_timeline(purchase_date, confirm_date, maturity_date, target_date, days)
return {
'target_date': target_date.strftime('%Y年%m月%d日'),
'product_days': days,
'purchase_date': purchase_date.strftime('%Y年%m月%d日'),
'purchase_deadline': f"{purchase_date.strftime('%Y年%m月%d日')} 15:00前",
'confirm_date': confirm_date.strftime('%Y年%m月%d日'),
'maturity_date': maturity_date.strftime('%Y年%m月%d日'),
'arrival_date': target_date.strftime('%Y年%m月%d日'),
'timeline': timeline
}
def _generate_timeline(self, purchase_date: datetime, confirm_date: datetime,
maturity_date: datetime, arrival_date: datetime, days: int) -> List[Dict]:
"""生成详细的时间线"""
timeline = []
# 购买日
timeline.append({
'date': purchase_date.strftime('%m月%d日'),
'weekday': self._get_weekday_name(purchase_date),
'event': '购买日',
'note': '需在15:00前完成购买'
})
# 确认日
timeline.append({
'date': confirm_date.strftime('%m月%d日'),
'weekday': self._get_weekday_name(confirm_date),
'event': '份额确认日',
'note': f'开始计算收益,持有第1天'
})
# 中间检查点
mid_date = confirm_date + timedelta(days=days//2)
timeline.append({
'date': mid_date.strftime('%m月%d日'),
'weekday': self._get_weekday_name(mid_date),
'event': '持有中期',
'note': f'已持有约{days//2}天'
})
# 到期日
timeline.append({
'date': maturity_date.strftime('%m月%d日'),
'weekday': self._get_weekday_name(maturity_date),
'event': '到期日',
'note': f'停止计算收益,持有{days}天'
})
# 到账日
timeline.append({
'date': arrival_date.strftime('%m月%d日'),
'weekday': self._get_weekday_name(arrival_date),
'event': '资金到账日',
'note': '资金可用'
})
return timeline
def _get_weekday_name(self, date: datetime) -> str:
"""获取中文星期名称"""
weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
return weekdays[date.weekday()]
def calculate_all_periods(self, target_date_str: str) -> pd.DataFrame:
"""
计算所有期限(60/90/120天)的购买日期
Args:
target_date_str: 目标到账日期
Returns:
DataFrame包含各期限的计算结果
"""
periods = [60, 90, 120]
results = []
for days in periods:
result = self.calculate_purchase_date(target_date_str, days)
results.append({
'产品期限': f'{days}天',
'目标到账日': result['target_date'],
'建议购买日': result['purchase_date'],
'最晚购买时间': result['purchase_deadline'],
'份额确认日': result['confirm_date'],
'产品到期日': result['maturity_date'],
'资金到账日': result['arrival_date']
})
return pd.DataFrame(results)
def calculate_all_months(self, day: int = 20) -> pd.DataFrame:
"""
计算每个月指定日期的所有期限购买日期
Args:
day: 日期,默认为20号
Returns:
DataFrame包含所有月份和期限的计算结果
"""
months = range(1, 13) # 1月到12月
periods = [60, 90, 120]
results = []
for month in months:
target_date_str = f"{month}月{day}日"
try:
for days in periods:
result = self.calculate_purchase_date(target_date_str, days)
results.append({
'月份': f'{month}月',
'目标到账日': result['target_date'],
'产品期限': f'{days}天',
'建议购买日': result['purchase_date'],
'最晚购买时间': result['purchase_deadline'],
'份额确认日': result['confirm_date'],
'产品到期日': result['maturity_date'],
'资金到账日': result['arrival_date']
})
except Exception as e:
print(f"⚠️ 计算{month}月{day}日时出错:{e}")
continue
return pd.DataFrame(results)
def save_all_months_to_excel(self, day: int = 20, filename: str = None, folder: str = "123"):
"""
将所有月份的计算结果保存为Excel文件
Args:
day: 日期,默认为20号
filename: 保存的文件名,如果不指定则自动生成
folder: 保存的文件夹路径
Returns:
保存的文件路径
"""
# 创建文件夹(如果不存在)
if not os.path.exists(folder):
os.makedirs(folder)
print(f"📁 创建文件夹:{folder}")
# 生成默认文件名
if filename is None:
filename = f"20260303微信定期60 90 120购买建议_全年{day}号汇总_{self.year}.xlsx"
else:
filename = self._sanitize_filename(filename)
# 确保文件名有.xlsx后缀
if not filename.endswith('.xlsx'):
filename += '.xlsx'
# 组合完整的文件路径
full_filepath = os.path.join(folder, filename)
# 创建Excel writer
with pd.ExcelWriter(full_filepath, engine='openpyxl') as writer:
# 1. 保存全年汇总表格
df_all = self.calculate_all_months(day)
df_all.to_excel(writer, sheet_name='全年汇总', index=False)
# 2. 按月份分别保存详细数据
months = range(1, 13)
for month in months:
target_date_str = f"{month}月{day}日"
try:
# 创建该月份的详细数据
month_data = []
for days in [60, 90, 120]:
result = self.calculate_purchase_date(target_date_str, days)
month_data.append({
'产品期限': f'{days}天',
'目标到账日': result['target_date'],
'建议购买日': result['purchase_date'],
'最晚购买时间': result['purchase_deadline'],
'份额确认日': result['confirm_date'],
'产品到期日': result['maturity_date'],
'资金到账日': result['arrival_date']
})
df_month = pd.DataFrame(month_data)
df_month.to_excel(writer, sheet_name=f'{month}月', index=False)
except Exception as e:
print(f"⚠️ 保存{month}月数据时出错:{e}")
continue
# 3. 保存计算说明
instructions = pd.DataFrame({
'项目': ['计算规则', '份额确认', '资金到账', '购买时间', '统计日期', '备注'],
'说明': [
'T+1确认,T+1到账',
'交易日次日确认份额',
'到期日后第一个交易日到账',
'需在交易日15:00前完成购买',
f'每月{day}号',
'已考虑周末顺延,未考虑法定节假日'
]
})
instructions.to_excel(writer, sheet_name='计算说明', index=False)
# 在所有数据写入后,单独打开工作簿调整列宽和对齐方式
from openpyxl import load_workbook
# 重新加载工作簿
wb = load_workbook(full_filepath)
# 调整每个工作表的列宽和对齐方式
for sheet_name in wb.sheetnames:
worksheet = wb[sheet_name]
self._auto_adjust_column_width(worksheet)
self._apply_center_alignment(worksheet)
# 保存修改
wb.save(full_filepath)
print(f"✅ 已自动调整所有工作表的列宽,并设置居中对齐")
return full_filepath
def save_to_excel(self, target_date_str: str, filename: str = None, folder: str = "123"):
"""
将计算结果保存为Excel文件到指定文件夹
Args:
target_date_str: 目标到账日期
filename: 保存的文件名,如果不指定则自动生成
folder: 保存的文件夹路径
Returns:
保存的文件路径
"""
# 创建文件夹(如果不存在)
if not os.path.exists(folder):
os.makedirs(folder)
print(f"📁 创建文件夹:{folder}")
# 生成默认文件名
if filename is None:
# 将目标日期格式化为文件名友好格式
date_obj = self._parse_date_string(target_date_str)
filename = f"理财产品购买建议_{date_obj.strftime('%Y%m%d')}.xlsx"
else:
# 清理文件名中的非法字符
filename = self._sanitize_filename(filename)
# 确保文件名有.xlsx后缀
if not filename.endswith('.xlsx'):
filename += '.xlsx'
# 组合完整的文件路径
full_filepath = os.path.join(folder, filename)
# 创建Excel writer
with pd.ExcelWriter(full_filepath, engine='openpyxl') as writer:
# 1. 保存汇总表格
df_summary = self.calculate_all_periods(target_date_str)
df_summary.to_excel(writer, sheet_name='购买建议汇总', index=False)
# 2. 保存详细时间线
timeline_data = []
for days in [60, 90, 120]:
result = self.calculate_purchase_date(target_date_str, days)
for event in result['timeline']:
timeline_data.append({
'产品期限': f'{days}天',
'日期': event['date'],
'星期': event['weekday'],
'事件': event['event'],
'说明': event['note']
})
df_timeline = pd.DataFrame(timeline_data)
df_timeline.to_excel(writer, sheet_name='详细时间线', index=False)
# 3. 保存计算说明
instructions = pd.DataFrame({
'项目': ['目标到账日', '计算规则', '份额确认', '资金到账', '购买时间', '备注'],
'说明': [
target_date_str,
'T+1确认,T+1到账',
'交易日次日确认份额',
'到期日后第一个交易日到账',
'需在交易日15:00前完成购买',
'已考虑周末顺延,未考虑法定节假日'
]
})
instructions.to_excel(writer, sheet_name='计算说明', index=False)
# 在所有数据写入后,单独打开工作簿调整列宽和对齐方式
from openpyxl import load_workbook
# 重新加载工作簿
wb = load_workbook(full_filepath)
# 调整每个工作表的列宽和对齐方式
for sheet_name in wb.sheetnames:
worksheet = wb[sheet_name]
self._auto_adjust_column_width(worksheet)
self._apply_center_alignment(worksheet)
# 保存修改
wb.save(full_filepath)
print(f"✅ 已自动调整所有工作表的列宽,并设置居中对齐")
return full_filepath
def print_purchase_advice(self, target_date_str: str):
"""
打印详细的购买建议
Args:
target_date_str: 目标到账日期
"""
print(f"\\n{'='*60}")
print(f"目标到账日:{target_date_str}")
print(f"{'='*60}")
try:
for days in [60, 90, 120]:
result = self.calculate_purchase_date(target_date_str, days)
print(f"\\n【{days}天期产品购买建议】")
print(f"├─ 目标到账日:{result['target_date']}")
print(f"├─ 建议购买日:{result['purchase_date']}")
print(f"├─ 最晚购买时间:{result['purchase_deadline']}")
print(f"├─ 份额确认日:{result['confirm_date']}")
print(f"├─ 产品到期日:{result['maturity_date']}")
print(f"└─ 资金到账日:{result['arrival_date']}")
print(f"\\n 详细时间线:")
for i, event in enumerate(result['timeline'], 1):
print(f" {i}. {event['date']} ({event['weekday']}):{event['event']} – {event['note']}")
if days < 120:
print(f"\\n " + "-" * 40)
except Exception as e:
print(f"\\n❌ 计算错误:{e}")
def print_all_months_advice(self, day: int = 20):
"""
打印所有月份的购买建议
Args:
day: 日期,默认为20号
"""
print(f"\\n{'='*60}")
print(f"全年每月{day}日理财产品购买建议")
print(f"{'='*60}")
months = range(1, 13)
for month in months:
target_date_str = f"{month}月{day}日"
try:
print(f"\\n【{month}月{day}日】")
for days in [60, 90, 120]:
result = self.calculate_purchase_date(target_date_str, days)
print(f" {days}天期:{result['purchase_date']} (最晚 {result['purchase_deadline']})")
print(f" " + "-" * 40)
except Exception as e:
print(f" ⚠️ 计算{month}月{day}日时出错")
# ==================== 主程序入口 ====================
if __name__ == "__main__":
try:
print("\\n" + "="*60)
print("理财产品购买日期计算器 – 全年统计版")
print("="*60)
print("\\n【使用说明】")
print("• 8日:银行信用卡还款")
print("• 20日:支付宝花呗还款")
print("• 请输入数字(1-31之间)")
print("-" * 60)
# 清空输入缓冲区
import sys
try:
# 尝试清空输入缓冲区
import msvcrt
while msvcrt.kbhit():
msvcrt.getch()
except:
pass
# 获取用户输入,添加更严格的验证
while True:
user_input = input('请输入每月几日还款(例如:8 或 20):\\n').strip()
# 如果输入为空,继续等待
# if not user_input:
# print("⏳ 请输入数字…")
# continue
# # 检查是否包含字母和特殊字符
# if not user_input.isdigit():
# # 尝试提取数字部分
# import re
# numbers = re.findall(r'\\d+', user_input)
# if numbers:
# # 如果找到数字,使用第一个数字
# user_input = numbers[0]
# print(f"📝 从输入中提取到数字:{user_input}")
# else:
# print(f"❌ 输入 '{user_input}' 包含无效字符,请输入纯数字(1-31)")
# continue
# try:
# day = int(user_input)
# if 1 <= day <= 31:
# break
# else:
# print("❌ 日期必须在1-31之间,请重新输入")
# except ValueError:
# print("❌ 请输入有效的数字,不要输入其他字符")
# 20日还掉支付宝花呗、8日换掉银行信用卡
print(f"\\n📅 您选择的还款日是每月 {day} 日")
if day == 8:
print("💳 银行信用卡还款日")
elif day == 20:
print("💰 支付宝花呗还款日")
else:
print("📝 自定义还款日")
# 创建计算器实例(使用2026年)
calculator = PurchaseDateCalculator(year=2026)
print("\\n" + "="*60)
print("请选择功能:")
print("1. 统计单个月份的还款日")
print("2. 统计全年12个月的还款日")
print("3. 自定义日期(如5月20日)")
print("-" * 60)
while True:
choice = input("\\n请输入选项(1/2/3):").strip()
if choice in ['1', '2', '3']:
break
else:
print("❌ 请输入 1、2 或 3")
if choice == '1':
# 统计单个月份
while True:
month = input("请输入月份(1-12):").strip()
try:
month = int(month)
if 1 <= month <= 12:
target_date = f"{month}月{day}日"
calculator.print_purchase_advice(target_date)
break
else:
print("❌ 月份必须在1-12之间")
except ValueError:
print("❌ 请输入有效的数字")
# 询问是否保存为Excel
print("\\n" + "-" * 60)
save_excel = input("\\n是否保存为Excel文件?(y/n):").strip().lower()
if save_excel == 'y':
try:
save_path = r'D:\\test\\20桌面素材'
if not os.path.exists(save_path):
os.makedirs(save_path)
custom_filename = f"{month}月{day}日"
filename = calculator.save_to_excel(target_date, custom_filename, save_path)
print(f"\\n✅ Excel文件已保存:{filename}")
except Exception as e:
print(f"❌ 保存Excel文件失败:{e}")
elif choice == '2':
# 统计全年12个月
print(f"\\n正在计算全年12个月的{day}号…")
# 打印简表
calculator.print_all_months_advice(day)
# 询问是否保存为Excel
print("\\n" + "-" * 60)
save_excel = input("\\n是否保存为Excel文件?(y/n):").strip().lower()
if save_excel == 'y':
try:
save_path = r'D:\\test\\20桌面素材'
if not os.path.exists(save_path):
os.makedirs(save_path)
filename = calculator.save_all_months_to_excel(day, folder=save_path)
print(f"\\n✅ 全年汇总Excel文件已保存:{filename}")
except Exception as e:
print(f"❌ 保存Excel文件失败:{e}")
elif choice == '3':
# 自定义日期
target_date = input("\\n请输入目标到账日期(例如:5月20日):\\n").strip()
if not target_date:
print("❌ 日期不能为空!")
else:
calculator.print_purchase_advice(target_date)
print("\\n" + "-" * 60)
save_excel = 'y'
# input("\\n是否保存为Excel文件?(y/n):").strip().lower()
if save_excel == 'y':
try:
save_path = r'D:\\test\\20桌面素材'
if not os.path.exists(save_path):
os.makedirs(save_path)
custom_filename = target_date
filename = calculator.save_to_excel(target_date, custom_filename, save_path)
print(f"\\n✅ Excel文件已保存:{filename}")
except Exception as e:
print(f"❌ 保存Excel文件失败:{e}")
except KeyboardInterrupt:
print("\\n\\n👋 程序已退出")
except Exception as e:
print(f"\\n❌ 程序运行错误:{e}")
print("\\n" + "="*60)
print("感谢使用!")
print("按回车键退出…")
# input()



如果20日取出,计算可以买的时间

今天是3月8日,最近购买日期是3月18日
这是总表

最近的两月 每月取出1次,取出2次,后面7-12可以取出3次,如果每笔买入1000元,差不多是每月还3000元。

这是“花呗”还款每月表

记录可以做到手机里,到时提示
同理做8日的信用卡






验证正确性


到期日时5月7日,倒退看看买入日







