excel-date-to-text

👤 yyy 📦 v1.0.0 ⭐ 4.3 ⬇️ 148 下載
📄 辦公效率 免費

📖 技能介紹


name: excel-date-to-text description: | Scan all date columns in Excel and convert datetime values to user-specified text format (yyyymmdd, yyyy-mm-dd, yyyy/mm/dd, yyyy年mm月dd日, or any custom combination). Supports three output positions: insert new column on left, insert new column on right, or replace original column. New column headers can be customized, defaulting to "{original name}(text)". 掃描 Excel 中所有日期列,將 datetime 轉為使用者指定的文本格式(yyyymmdd、yyyy-mm-dd、yyyy/mm/dd、yyyy年mm月dd日 等任意組合)。支援三種輸出位置:左側插入新列、右側插入新列、替換原列。新列表頭可自定義,未指定時預設"{原列名}(文本)"。 Trigger keywords: "date to text" "yyyymmdd" "date format" "left of date column" "right of date column" "replace date column" "format date" 觸發詞包括"日期轉文本""yyyymmdd""日期格式""日期列左邊/右邊""替換日期列""格式化日期"。


This skill follows [[excel-safe-workflow]] four-step method. Must complete Requirement Parsing→Scout→Plan before execution, and Verify after. 本技能遵循 [[excel-safe-workflow]] 四步法。執行前必須完成 需求解析→勘察→規劃,執行後必須驗證。

Excel Date Column to Custom Text / Excel 日期列轉自定義文本

第零步:需求解析(先於勘察)

核心原則:從使用者原話中提取意圖,只問沒說的。使用者已經明確的內容不要再問。

解析三要素

從使用者的請求中提取以下三項,缺失時才追問:

要素 常見表述 預設值
日期格式 yyyymmddyyyy-mm-ddyyyy/mm/ddyyyy年mm月dd日yyyymd yyyymmdd
新列位置 "左邊插入""左側加一列""右邊""右側" → left/right;"替換""覆蓋原列""直接改" → replace left(左側插入)
新列表頭 "叫xxx""命名為xxx""表頭寫xxx" → 使用指定名稱;未提及 → 預設 "{原列名}(文本)" "{原列名}(文本)"

解析示例

使用者說 提取結果 需要追問?
"把日期列轉成 yyyymmdd 放在左邊" format=yyyymmdd, pos=left, header=預設
"日期改成 yyyy/mm/dd ,直接替換原資料" format=yyyy/mm/dd, pos=replace, header=N/A
"在日期列右邊加一列,叫'格式化日期'" format=yyyymmdd(預設), pos=right, header='格式化日期'
"把日期處理一下" 全缺 :追問格式、位置
"日期列左邊插入 yyyy-mm-dd 格式,命名為日期文本" format=yyyy-mm-dd, pos=left, header='日期文本'

追問模板(僅在資訊不足時使用)

勘察完成,發現 N 個日期列:
  - 列X: "公開(公告)日"
  - 列Y: "申請日"
  ...

請確認以下三項(直接回復即可,已有預設值):
1. 日期格式:預設 yyyymmdd(也可選 yyyy-mm-dd、yyyy/mm/dd、yyyy年mm月dd日 等)
2. 新列位置:預設左側插入(也可選 右側插入 / 替換原列)
3. 新列表頭:預設 "{原列名}(文本)"(也可自定義)

日期格式說明

使用者可通過自然語言描述想要的日期格式,常見對映:

使用者說 strftime 格式 示例輸出
yyyymmdd / 年月日緊湊 %Y%m%d 20260424
yyyy-mm-dd / 帶橫線 %Y-%m-%d 2026-04-24
yyyy/mm/dd / 斜線分隔 %Y/%m/%d 2026/04/24
yyyy年mm月dd日 / 中文 %Y年%m月%d日 2026年04月24日
yymmdd / 短年 %y%m%d 260424
mmdd / 僅月日 %m%d 0424
yyyymdd / 無補零月日 自定義函式 2026424
yyyy/m/d / 斜線無補零 自定義函式 2026/4/24

解析規則: - yyyy → 四位年份,yy → 兩位年份 - mm → 補零兩位月份,m → 不補零月份 - dd → 補零兩位日期,d → 不補零日期 - 其他字元(-/等)→ 原樣保留

日期格式轉換函式

def build_format_fn(user_format):
    """根據使用者描述的格式,返回一個 datetime → 文本 的轉換函式。

    支援的模式(大小寫不敏感):
      yyyy → 四位年, yy → 兩位年
      mm → 補零月, m → 不補零月
      dd → 補零日, d → 不補零日
      其他字元原樣保留
    """
    import re

    fmt_lower = user_format.lower().strip()

    # 保護分隔符:將非模式字元標記出來
    # 替換順序:先長後短,避免 yyyy 被誤拆為 yy+yy
    replacements = [
        ('yyyy', '\x00'),   # 四位年佔位
        ('yy', '\x01'),     # 兩位年佔位
        ('mm', '\x02'),     # 補零月佔位
        ('dd', '\x03'),     # 補零日佔位
        ('m', '\x04'),      # 不補零月佔位
        ('d', '\x05'),      # 不補零日佔位
    ]

    for pattern, placeholder in replacements:
        fmt_lower = fmt_lower.replace(pattern, placeholder)

    # 剩餘字元是分隔符
    separators = fmt_lower

    # 重建格式序列
    format_seq = []
    i = 0
    tmp = fmt_lower
    while tmp:
        ch = tmp[0]
        if ch in '\x00\x01\x02\x03\x04\x05':
            format_seq.append(ch)
            tmp = tmp[1:]
        else:
            # 收集連續的分隔符
            sep = ''
            while tmp and tmp[0] not in '\x00\x01\x02\x03\x04\x05':
                sep += tmp[0]
                tmp = tmp[1:]
            format_seq.append(sep)

    def convert(dt):
        """將 datetime 轉為目標格式文本"""
        parts = []
        for token in format_seq:
            if token == '\x00':   # yyyy
                parts.append(f'{dt.year:04d}')
            elif token == '\x01':  # yy
                parts.append(f'{dt.year % 100:02d}')
            elif token == '\x02':  # mm
                parts.append(f'{dt.month:02d}')
            elif token == '\x03':  # dd
                parts.append(f'{dt.day:02d}')
            elif token == '\x04':  # m (不補零)
                parts.append(str(dt.month))
            elif token == '\x05':  # d (不補零)
                parts.append(str(dt.day))
            else:                  # 分隔符
                parts.append(token)
        return ''.join(parts)

    return convert

更多技能請訪問小蔥技能站7w4.net。

完整執行指令碼

以下指令碼集成了勘察→規劃→執行→驗證四步。使用前將 FORMAT 變數替換為使用者指定的格式

第一步:勘察

import os, sys
sys.stdout.reconfigure(encoding='utf-8')
from openpyxl import load_workbook
from datetime import datetime

FILE = '目標檔案.xlsx'

# 1. 檔案體量
size_mb = os.path.getsize(FILE) / 1024 / 1024
print(f'檔案大小: {size_mb:.1f} MB')

# 2. 載入並掃描結構
wb = load_workbook(FILE)
ws = wb.active
print(f'工作表: {ws.title}, 行: {ws.max_row}, 列: {ws.max_column}')

# 3. 掃描所有列,在第2-10行找 datetime 值
print('\n=== 日期列掃描 ===')
date_cols = []
for col_idx in range(1, ws.max_column + 1):
    header = ws.cell(row=1, column=col_idx).value
    for row_idx in range(2, min(12, ws.max_row + 1)):
        if isinstance(ws.cell(row=row_idx, column=col_idx).value, datetime):
            date_cols.append({'col': col_idx, 'header': header})
            print(f'  ✅ 列{col_idx}: "{header}" — 日期列')
            break

# 4. 雙重掃描確認非公式
print('\n=== data_only 對比(確認非公式)===')
wb2 = load_workbook(FILE, data_only=True)
ws2 = wb2.active
for dc in date_cols:
    v_raw = ws.cell(row=2, column=dc['col']).value
    v_data = ws2.cell(row=2, column=dc['col']).value
    same_type = type(v_raw) == type(v_data)
    print(f'  列{dc["col"]} "{dc["header"]}": raw={type(v_raw).__name__}, data_only={type(v_data).__name__} {"✓" if same_type else "⚠️ 公式!"}')
wb2.close()

print(f'\n共找到 {len(date_cols)} 個日期列')

# 5. 確認:展示給使用者確認後再繼續
for dc in date_cols:
    print(f'  列{dc["col"]}: {dc["header"]} → 將在左側插入 "{dc["header"]}(文本)"')
print('\n請確認以上操作,確認後繼續執行第二步...')

第二步:規劃

勘察完成後確認: - 日期列集合、列號、原始表頭名 - 所有列為 datetime 硬值(非公式) - 處理順序:從右到左(列號降序) - left/right 模式 → 委託給 [[excel-insert]] 建列,本技能填充格式化日期 - replace 模式 → 委託給 [[excel-replace]],傳入日期格式化函式

第三步:執行

本技能只做日期專精的事:掃描 + 格式轉換。列的插入/替換委託給通用技能。

# ===== 使用者配置(從需求解析步驟獲取)=====
FORMAT = 'yyyymmdd'        # 日期格式
POSITION = 'left'           # left / right / replace
HEADER_NAME = None          # None=自動"{原列名}(文本)"
# =========================================

fmt_fn = build_format_fn(FORMAT)
print(f'日期格式: {FORMAT} | 輸出位置: {POSITION}')
print(f'共 {len(date_cols)} 個日期列: {[dc["header"] for dc in date_cols]}')

# 從右到左逐個處理
for dc in sorted(date_cols, key=lambda x: x['col'], reverse=True):
    name = dc['header']
    new_header = HEADER_NAME if HEADER_NAME else f'{name}(文本)'
    print(f'\n--- {name} ---')

    if POSITION in ('left', 'right'):
        # 委託 excel-insert:建列(空列)
        # 然後本技能:逐行填入格式化的日期文本
        pass  # 見下方具體實現

    elif POSITION == 'replace':
        # 委託 excel-replace:
        #   TARGET_COL=dc['col'], MODE='transform', transform=日期格式化
        pass  # 見下方具體實現

left/right 模式實現(本技能負責:建列 + 填格式化日期):

import time
t0 = time.time()

wb = load_workbook(FILE)
ws = wb.active
total_rows = ws.max_row

from openpyxl.styles import Font

for dc in sorted(date_cols, key=lambda x: x['col'], reverse=True):
    col = dc['col']
    name = dc['header']
    new_header = HEADER_NAME if HEADER_NAME else f'{name}(文本)'

    # --- 以下邏輯等同於 excel-insert ---
    if POSITION == 'left':
        ws.insert_cols(col)
        write_col, read_col = col, col + 1
    else:  # right
        ws.insert_cols(col + 1)
        write_col, read_col = col + 1, col

    ws.cell(row=1, column=write_col).value = new_header
    ws.cell(row=1, column=write_col).font = Font(name='Arial', size=10, bold=True)
    # --- 插入完成 ---

    # 本技能核心:逐行填入格式化的日期
    count = 0
    for row in range(2, total_rows + 1):
        dt = ws.cell(row=row, column=read_col).value
        if isinstance(dt, datetime):
            ws.cell(row=row, column=write_col).value = fmt_fn(dt)
            count += 1
        if row % 50000 == 0:
            print(f'  進度: {row}/{total_rows}')

    print(f'  {name} → {new_header}: 寫入 {count} 行')

wb.save(FILE)
print(f'完成,耗時 {time.time()-t0:.1f}s')

replace 模式實現(本技能只定義轉換邏輯,委託 excel-replace 執行):

# replace 模式:定義日期格式化函式,交給 excel-replace 執行
from datetime import datetime

def date_transform(val):
    """日期→文本轉換函式,供 excel-replace 呼叫"""
    if isinstance(val, datetime):
        return fmt_fn(val)
    return val  # 非日期值保持不變

import time
t0 = time.time()
wb = load_workbook(FILE)
ws = wb.active
total_rows = ws.max_row

for dc in sorted(date_cols, key=lambda x: x['col'], reverse=True):
    col = dc['col']
    name = dc['header']
    new_header = HEADER_NAME if HEADER_NAME else f'{name}(文本)'
    print(f'\n替換 "{name}" → "{new_header}"')

    # 改表頭(如果需要)
    if new_header != name:
        ws.cell(row=1, column=col).value = new_header

    # 逐行替換
    count = 0
    for row in range(2, total_rows + 1):
        val = ws.cell(row=row, column=col).value
        if isinstance(val, datetime):
            ws.cell(row=row, column=col).value = fmt_fn(val)
            count += 1
        if row % 50000 == 0:
            print(f'  進度: {row}/{total_rows}')

    print(f'  替換 {count} 行')

wb.save(FILE)
print(f'完成,耗時 {time.time()-t0:.1f}s')

第四步:驗證

驗證邏輯取決於位置模式,與 [[excel-insert]] 或 [[excel-replace]] 的驗證對齊。

wb = load_workbook(FILE, read_only=True, data_only=True)
ws = wb.active
fmt_fn = build_format_fn(FORMAT)

check_rows = [2, 3, 4, ws.max_row // 2, ws.max_row - 2, ws.max_row]

for dc in date_cols:
    new_header = HEADER_NAME if HEADER_NAME else f'{dc["header"]}(文本)'

    if POSITION == 'replace':
        # 替換模式:驗證列值變為文本格式
        col = dc['col']
        actual_header = ws.cell(row=1, column=col).value
        ok = True
        for row in check_rows:
            v = ws.cell(row=row, column=col).value
            if v and isinstance(v, str) and len(v) >= 6:
                print(f'  列{col}行{row}: ✓ "{v}"')
            elif v is None:
                print(f'  列{col}行{row}: ✓ (空)')
            else:
                print(f'  列{col}行{row}: ⚠️ {v}')
                ok = False
        print(f'  [{new_header}] 表頭: "{actual_header}" {"✓" if actual_header == new_header else "⚠️"}')
        print(f'  {"✅" if ok else "❌"}')

    else:
        # left/right 模式:找文本列位置,對比源日期列
        text_col = None
        for col_idx in range(1, ws.max_column + 1):
            if ws.cell(row=1, column=col_idx).value == new_header:
                text_col = col_idx
                break

        if text_col is None:
            print(f'  ❌ 未找到文本列 "{new_header}"')
            continue

        # 日期列在文本列右側(left)或左側(right)
        date_col = text_col + 1 if POSITION == 'left' else text_col - 1

        ok = True
        for row in check_rows:
            v_text = ws.cell(row=row, column=text_col).value
            v_date = ws.cell(row=row, column=date_col).value
            if v_date and hasattr(v_date, 'strftime'):
                expected = fmt_fn(v_date)
                ok = ok and (v_text == expected)
        print(f'  [{new_header}] ← [{dc["header"]}] {"✅" if ok else "❌"}')

wb.close()

注意事項

  1. 必須從右到左處理:多個日期列時按列號降序處理,每次 insert 後源資料自動移到 col+1 位置
  2. 空值處理:datetime 為空(如"授權公告日"僅已授權專利有值)時,文本列保持空白,這是正確行為
  3. 檔案大小:大檔案(>100MB)載入和儲存各需幾分鐘,中斷前確認 timeout 足夠
  4. 操作前必備份:遵循 [[excel-safe-workflow]] 第零步——操作前自動備份(時間戳命名),成功後保留最新3份,失誤後立即刪除損壞檔案並從備份恢復
  5. ⚠️ 禁止用 XML 數字範圍猜測日期:Excel 的 <v> 元素可能是日期序列號(如 46154=2026-05-15),也可能是普通數字(金額、編號等)。不要20000 < serial < 100000 這種範圍判斷——金額和編號會落在同一範圍,導致資料被錯誤轉為日期文本。日期轉換必須通過 isinstance(val, datetime)(openpyxl)或 pd.api.types.is_datetime64_any_dtype()(pandas)來判斷列型別。
  6. 如需加速大規模日期轉換:先通過 pandas 取樣確認列型別是日期,然後在 XML 層只在已確認的日期列上做數字→文本轉換

🤖 AI 評測

這個 Skill 質量中等偏上,核心功能(日期轉文本)做得紮實,格式選項豐富,操作步驟清晰。但缺少示例和測試資料,初次使用可能不好理解。文件說明詳細,但純文字形式不夠直觀。適合有經驗的 Excel 使用者,新手建議配合更多示例學習。

📊 多維度評分

適應性4.3
規範性4.1
有效性4.5
可靠性4
可信度5

📁 包含檔案 (1 個)

📄 SKILL.md 15.3 KB