EP047 Date.FromText与Date.ToText:文本与日期动态双向转换(多格式日期清洗与报表格式重塑)

📘
💡 学员必读 · 随堂课件极速实操演练指南
打开课件表格是成果样式?手把手教您新建空白查询并注入 M 脚本复现全过程
👉 点击查看实操指南

专栏定位:系统拆解 Power Query M 语言底层核心逻辑,紧密围绕汽车零部件制造企业(Tier 1)财务管控、工时核算、工装模具与生产条码真实业务场景,输出工业级实操讲义与自动化解决方案。
文 / 老汪(汽车零部件财务与商业智能实战派)


大家好,我是老汪。

在咱们汽车零部件制造企业(Tier 1 一级供应商)月末开月度经营分析会前,往来会计与应收财务 BP 经常要面临一场“对账恶战”:主机厂(OEM)与各车间传上来的业务日期,格式乱得五花八门!

典型的真实场景就像这样: 咱们给比亚迪、特斯拉、吉利极氪、蔚来等多个主机厂同时供货(比如 800V 碳化硅电驱逆变器、一体化压铸车身件、电池托盘水冷板)。每个主机厂的采购结算周期不同,从各自 SRM 供应链系统、ERP 或金税系统导出的开票与对账清单里,录入的日期各显神通: – 比亚迪导出的过账单是 8 位纯数字:20261025; – 车间现场报检单用的是点号:2026.11.02; – 特斯拉 EDI 系统接口传回的是斜杠:2026/09/15; – 吉利结算有些只挂了结账月份:2026-10; – 更头疼的是,个别经办人在单元格里随手敲个 暂未定期 或 已验收 2026.10.15 结算完成。

很多新手会计直接在 Excel 里拿基准日去减这列数据,试图算“逾期天数”和“应收账款账龄(0-30天、31-60天、61-90天)”。结果大家都很清楚:全列瞬间报出一大片 #VALUE! 错误! 为什么?因为这些在人眼看来是日期,在电脑和 Power Query 引擎眼里,全都是没有任何算术运算能力的纯文本(Text)!

今天这节课,老汪就带大家彻底攻克 Power Query 里的“日期转换双雄”——Date.FromText(文本逆向解析为真日期) 与 Date.ToText(日期按需重塑为规范报表文本)。配合 try ... otherwise 容错护盾,不管上游系统甩给你多奇葩的混杂日期,你都能一键清洗为纯正的 Date 类型,精准计算逾期账龄,并优雅输出典雅的中文汇报看板!


一、 老汪白话底层逻辑:文本与真日期的“本质鸿沟”

在 Power Query M 语言的世界里,数据类型有着极其严格的铁律:

┌─────────────────────────────────────────────────────────────┐
│ 伪日期文本 (Text): "20261025" 或 "2026.11.02"               │
│ 特征:纯字符串,不可直接加减,不能计算账期、逾期天数与账龄   │
└──────────────────────────────┬──────────────────────────────┘
                               │  Date.FromText(...)
                               ▼
┌─────────────────────────────────────────────────────────────┐
│ 真正日期类型 (Date): #date(2026, 10, 25)                    │
│ 特征:具备时间序列属性,支持 Duration.Days 日期相减算账龄   │
└──────────────────────────────┬──────────────────────────────┘
                               │  Date.ToText(..., "yyyy年M月d日")
                               ▼
┌─────────────────────────────────────────────────────────────┐
│ 规范报表展示文本: "2026年10月25日" 或 "2026年10月"           │
│ 特征:满足向工厂总经理/财务总监汇报的中文视觉排版与月度归集   │
└─────────────────────────────────────────────────────────────┘

1. 核心函数语法剖析

① Date.FromText:文本转日期核心函数

Date.FromText(text as nullable text, optional options as any) as nullable date
  • 支持的丰富语法形态:
  • 标准连字符:"2026-11-12" ➔ #date(2026, 11, 12);
  • 纯 8 位紧凑数字串:"20261025" ➔ 自动识别为 2026 年 10 月 25 日;
  • 斜杠分隔:"2026/09/15" ➔ 识别为 2026 年 9 月 15 日;
  • 智能补全机制:如果文本只提供了年月 "2026-10",M 引擎会自动将其补全为该月的第一天(2026-10-01);如果只提供了年份 "2026",自动补全为元旦(2026-01-01),非常契合财务按月暂估核算的业务场景!
  • 重要铁律:必须符合“年-月-日”逻辑顺序。

② Date.ToText:日期转文本格式化输出

Date.ToText(date as nullable date, optional format as nullable text, optional culture as nullable text) as nullable text
  • 常用报表格式代码:
  • format = "yyyy-MM-dd":标准 ISO 格式(如 2026-11-12);
  • format = "yyyy年M月d日":中文报表标准呈现(如 2026年11月12日);
  • format = "yyyy年M月" 或 "yyyyMM":快速抽取结账月份归集维度;
  • format = "dddd":快速获取当天是星期几。

二、 业务实战:主机厂混杂结算账期清洗与应收账龄看板

1. 原始混乱业务台账

某汽车零部件制造企业(Tier 1)给各大新能源车企供货,月末导出的《主机厂开票结算对账台账》如下,开票日期五花八门:

结算单号 主机厂客户 供应零部件总成 开票结算原始日期(混杂) 应收金额(元) 约定账期
INV-2026-BYD-01 比亚迪汽车 800V碳化硅电驱总成 20261025 480,000 60天
INV-2026-BYD-02 比亚迪汽车 仰望U8一体化前舱总成 2026.11.02 320,000 60天
INV-2026-TSLA-01 特斯拉中国 Model Y一体压铸后地板 2026/09/15 560,000 45天
INV-2026-GEELY-02 吉利极氪 四驱双电机前副车架 2026-10 410,000 90天
INV-2026-XIAOMI-01 小米汽车 SU7一体化压铸大压铸件 暂未定期 620,000 60天

2. 清洗与建模实施路径

  1. 多格式弹性识别与容错:针对点号 . 格式(部分系统区域设置可能不识别),利用 Text.Replace(..., ".", "-") 规范化后再送入 Date.FromText;
  2. 非日期防崩兜底:使用 try ... otherwise null 结构,遇到 暂未定期 等非法字符直接赋为 null,绝不让整张表报废;
  3. 中文格式化:调用 Date.ToText([标准结算日期], "yyyy年M月d日") 呈现友好报告日期;
  4. 账期与账龄计算: – 到期日 = Date.AddDays([标准结算日期], [合同约定账期(天)]); – 逾期天数 = Duration.Days(基准日 - [到期日]); – 账龄区间划分:未到期、逾期0-30天、逾期31-60天、逾期61-90天、逾期90天以上。

三、 工业级 M 语言核心脚本(自适应动态路径版)

以下代码完全遵循 Q001 动态相对路径标准编写,学员解压课件包后可直接一键刷新演练:

let
    // 1. 动态自适应提取当前工作簿所在目录
    当前目录 = try 
        let 
            rawPath = Text.From(Excel.CurrentWorkbook(){[Name="当前路径"]}[Content]{0}[Column1]),
            cleanPath = Text.Trim(rawPath),
            fixedPath = if Text.EndsWith(cleanPath, "\") then cleanPath else cleanPath & "\"
        in 
            fixedPath
    otherwise 
        "./",

    // 2. 加载原始业务数据表
    数据源路径 = 当前目录 & "原始业务数据表.xlsx",
    源 = Excel.Workbook(File.Contents(数据源路径), null, true),
    目标Sheet = 源{[Item="主机厂开票结算对账台账", Kind="Sheet"]}[Data],
    提升标题 = Table.PromoteHeaders(目标Sheet, [PromoteAllScalars=true]),
    更改基础类型 = Table.TransformColumnTypes(提升标题,{
        {"结算单号", type text}, 
        {"主机厂客户", type text}, 
        {"供应零部件总成", type text}, 
        {"开票结算原始日期_格式混杂", type text}, 
        {"应收结算金额(元)", type number}, 
        {"合同约定账期(天)", Int64.Type}, 
        {"开票经办人", type text}
    }),

    // 3. 核心步骤 A:使用 Date.FromText 结合 try ... otherwise 容错解析多源日期
    添加标准日期列 = Table.AddColumn(更改基础类型, "标准结算日期", each 
        let
            原始文本 = Text.Trim(Text.From([#"开票结算原始日期_格式混杂"])),
            // 尝试直接转换;若遇点号则替换为横杠再转换;若仍失败返回 null
            转换结果 = try Date.FromText(原始文本) otherwise 
                       try Date.FromText(Text.Replace(原始文本, ".", "-")) otherwise null
        in
            转换结果,
        type date
    ),

    // 4. 核心步骤 B:使用 Date.ToText 生成典雅中文汇报日期与月度结账期归集列
    添加中文报表日期 = Table.AddColumn(添加标准日期列, "中文报表日期", each 
        if [标准结算日期] <> null then 
            Date.ToText([标准结算日期], "yyyy年M月d日") 
        else 
            "待核实", 
        type text
    ),

    添加结账月份归集 = Table.AddColumn(添加中文报表日期, "结账月份归集", each 
        if [标准结算日期] <> null then 
            Date.ToText([标准结算日期], "yyyy年M月") 
        else 
            "未入账", 
        type text
    ),

    // 5. 核心步骤 C:推算应收账款到期日
    添加到期日 = Table.AddColumn(添加结账月份归集, "到期日期", each 
        if [标准结算日期] <> null then 
            Date.AddDays([标准结算日期], [#"合同约定账期(天)"]) 
        else 
            null, 
        type date
    ),

    // 6. 核心步骤 D:以基准核算日计算逾期天数与账龄区间
    基准核算日 = #date(2026, 11, 12),
    添加逾期天数 = Table.AddColumn(添加到期日, "逾期天数", each 
        if [到期日期] <> null then 
            let
                diff = Duration.Days(基准核算日 - [到期日期])
            in
                if diff > 0 then diff else 0
        else 
            0, 
        Int64.Type
    ),

    添加账龄区间 = Table.AddColumn(添加逾期天数, "账龄区间", each 
        if [到期日期] = null then "待排期"
        else if [逾期天数] = 0 then "未到期"
        else if [逾期天数] <= 30 then "逾期0-30天"
        else if [逾期天数] <= 60 then "逾期31-60天"
        else if [逾期天数] <= 90 then "逾期61-90天"
        else "逾期90天以上", 
        type text
    ),

    // 7. 规整最终呈现列
    重命名原列 = Table.RenameColumns(添加账龄区间, {
        {"开票结算原始日期_格式混杂", "原始混杂录入"},
        {"应收结算金额(元)", "应收金额(元)"}
    }),
    选择列 = Table.SelectColumns(重命名原列, {
        "结算单号", "主机厂客户", "供应零部件总成", "原始混杂录入", "标准结算日期", 
        "中文报表日期", "结账月份归集", "应收金额(元)", "到期日期", "逾期天数", "账龄区间"
    })
in
    选择列

四、 老汪敲黑板:文本与日期转换三大避坑铁律

1. 警惕操作系统区域设置(Culture)暗坑

很多外资背景的汽车零部件供应商使用的是英文版 Windows 或 Office,日期格式默认是 MM/dd/yyyy(美式:月/日/年)。当使用 Date.FromText 处理 "05/06/2026" 时,系统可能会误判为 5 月 6 日而非 6 月 5 日。

老汪锦囊:对于带有斜杠的特殊日期,可在 Date.FromText 第二个参数中显式指定文化区域,例如:Date.FromText(x, [Format="yyyy/MM/dd", Culture="zh-CN"]),彻底锁死格式解析!

2. 纯数字字符串的类型识别陷阱

如果数据源里的日期纯粹是 8 位数字 20261025,导入 PQ 时系统经常自作聪明将其识别为【整数 Int64.Type】。如果直接对整数运行 Date.FromText(20261025),会报类型不匹配错误!

老汪锦囊:先用 Text.From(...) 将其强制转为文本格式,再丢给 Date.FromText 解析,两步走最稳妥。

3. 日期与文本双向闭环的意义

内部计算必须是 Date 类型(用于账期天数加减、排序、时间智能计算);外部展示则可转为 Text 文本(用于制作高管汇报中文看板、生成发票打印抬头)。“内算用日期,外看转文本”,这就是商业智能财务建模的核心规范!


五、 老汪结语与随堂课件下载

搞懂了文本与日期的双向转换,汽车零部件往来账期、工时签到考勤、设备维保周期等所有与时间相关的清洗难题便迎刃而解。

大家在阅读完讲义后,请务必在文末下载配套的随堂课件包。课件中已为大家预置好了《原始业务数据表.xlsx》和包含全部自适应查询的《最终完成版_带PQ查询.xlsx》,解压即可直接一键刷新演练!

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容