欢迎光临
我们一直在努力

【理财类-01-02】20260607“微信”定期60天、90天、120天,在每月8日和每月20日准时到账还信用卡和花呗(消费贷)倒退计算最适合买入的日期

背景需求

微信理财通有一个“定期+”,

可以买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日,倒退看看买入日

    结果正确,的确是3月6日15点前买入,然后5月7日24:00前到账

    赞(0)
    未经允许不得转载:171主机测评 » 【理财类-01-02】20260607“微信”定期60天、90天、120天,在每月8日和每月20日准时到账还信用卡和花呗(消费贷)倒退计算最适合买入的日期
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址