You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言使用excelize读取Excel日期解析错误的问题求助

解决Go中Excel日期解析的年份偏差问题

问题原因

你遇到的核心问题有两个:

  1. Excel日期的存储与显示差异:Excel的日期默认以**序列号(浮点数)**存储,显示的27/06/1905是格式化后的文本;而excelize读取时如果直接获取列文本,会按Excel的显示格式返回短年份版本27-06-05。
  2. Go time包的两位年份解析规则:time.Parse中,两位年份格式06的默认映射规则是:00-69对应2000-2069,70-99对应1970-1999。因此05会被解析为2005,而非目标的1905。

最优解决方案:读取Excel日期原始序列号(推荐)

直接读取Excel日期的原始序列号,再转换为Go的time.Time对象,这是最准确的方式,完全避免格式解析的歧义。

代码示例

package main

import (
    "fmt"
    "strconv"
    "time"

    "github.com/xuri/excelize/v2"
)

func excelSerialToTime(serial float64) time.Time {
    // Excel的起始日期是1899-12-30(兼容1900闰年bug)
    excelEpoch := time.Date(1899, time.December, 30, 0, 0, 0, 0, time.UTC)
    // 拆分整数(天数)和小数(时分秒)部分
    days := int(serial)
    hours := (serial - float64(days)) * 24
    minutes := (hours - float64(int(hours))) * 60
    seconds := (minutes - float64(int(minutes))) * 60

    return excelEpoch.AddDate(0, 0, days).Add(
        time.Duration(int(hours))*time.Hour +
            time.Duration(int(minutes))*time.Minute +
            time.Duration(int(seconds))*time.Second,
    )
}

func main() {
    excelFile, err := excelize.OpenFile("your_file.xlsx")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer excelFile.Close()

    // 读取日期单元格的原始数值(替换为你的单元格位置,比如"B2")
    cellValue, err := excelFile.GetCellValue("Asset Data", "B2")
    if err != nil {
        fmt.Println(err)
        return
    }

    // 转换为Excel日期序列号
    serial, err := strconv.ParseFloat(cellValue, 64)
    if err != nil {
        fmt.Println("单元格为文本格式,切换到文本解析逻辑")
        // 可插入下方备用方案的代码
        return
    }

    // 转换为Go时间对象
    date := excelSerialToTime(serial)
    fmt.Println(date.Format("02/01/2006")) // 输出:27/06/1905
}

备用方案:处理文本格式的日期

如果Excel日期是以纯文本存储的,可以手动修正年份解析逻辑:

代码示例

package main

import (
    "fmt"
    "time"
)

func parseExcelShortDate(dateStr string) (time.Time, error) {
    // 先按默认规则解析
    t, err := time.Parse("02-01-06", dateStr)
    if err != nil {
        return time.Time{}, err
    }

    // 修正年份:若解析结果为2000-2069区间,调整为1900-1969
    year := t.Year()
    if year >= 2000 && year <= 2069 {
        t = t.AddDate(-100, 0, 0)
    }
    return t, nil
}

func main() {
    // 模拟excelize读取到的短日期字符串
    dateStr := "27-06-05"
    date, err := parseExcelShortDate(dateStr)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(date.Format("02/01/2006")) // 输出:27/06/1905
}

注意事项

  • 优先使用序列号解析方案,文本格式的日期可能存在格式变体,稳定性远不如读取原始序列号。
  • Excel的1900闰年bug:Excel错误地将1900年视为闰年,上述excelSerialToTime函数已兼容此问题。

内容的提问来源于stack exchange,提问作者erwin-lovecraft

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 21:34:53