GO excelize 读取excel进行时间类型转换(自动转换)
GO excelize 读取excel进行时间类型转换(自动转换)
需求分析
需求:如何自动识别excel中的时间类型数据并转化成对应的 "Y-m-d H:i:s"类型数据。
分析:excelize在读取excel时,GetRows() 返回的都是字符串类型,并且有些时间类型的数据会进行转换,如果全部转化成 float64 格式,然后转换成对应的字符串,并且excelize提供函数
func ExcelDateToTime(excelDate float64, use1904Format bool) (time.Time, error) {...
}
可以将float64 转换成time.Time 类型,time.Time 很容易转化成对应"Y-m-d H:i:s"格式字符串类型数据。所以我们的难点就在于如何自动识别excel中时日期时间类型数据
excel 单元格格式
以下3月1日数据写入到excel中,excel都会识别成2024/3/1,但是对应单元格格式不同,转化为常规类型的话大部分都相同
- 2024年3月1日------------- yyyy"年"m"月"d"日"-------------453352
- 2024/3/1------------- yyyy/m/d-------------453352
- Mar-24------------- mmm-yy-------------453352
- 2024年3月------------- yyyy"年"m"月"-------------453352
- 2024/3/1 0:00-------------yyyy/m/d h:mm-------------453352
- '2024-03-01 00:00:00-------------通用-------------2024-03-01 00:00:00
- excelize 读取- func parseFileUrl(filePath string) ([]map[string]string, error) {f, err := excelize.OpenFile(filePath)if err != nil {return nil, err}sheetName := f.GetSheetName(0)rows, err := f.GetRows(sheetName)if err != nil {return nil, err}if len(rows) > 0 {for rowKey, cols := range rows {if len(cols) > 0 {for colKey, value := range cols {fmt.Println(rowKey, "-", colKey, ":", value)}}}}return nil, err }- 结果打印 - 0 - 0 : 45352 1 - 0 : 03-01-24 2 - 0 : Mar-24 3 - 0 : 45352 4 - 0 : 3/1/24 00:00 5 - 0 : 2024-03-01 00:00:00- 由此我们可以看出时间类型打印出来的内容不尽相同,这里我们可以想办法把他们全部转化成45352 
 这里我们就把他们转化成常规类型,常规类型的数据大部分都为45352- func parseFileUrl(filePath string) ([]map[string]string, error) {f, err := excelize.OpenFile(filePath)if err != nil {return nil, err}sheetName := f.GetSheetName(0)rows, err := f.GetRows(sheetName)if err != nil {return nil, err}//转化为常规类型,对应style NumFmt 0styleId, _ := f.NewStyle(&excelize.Style{NumFmt: 0})//示例例中都放入A列,所以将A列数据全部转化成对应的常规类型_ = f.SetColStyle(sheetName, "A", styleId)rows, err = f.GetRows(sheetName)if len(rows) > 0 {for rowKey, cols := range rows {if len(cols) > 0 {for colKey, value := range cols {fmt.Println(rowKey, "-", colKey, ":", value)}}}}return nil, err }- 再次进行打印 - 0 - 0 : 45352 1 - 0 : 45352 2 - 0 : 45352 3 - 0 : 45352 4 - 0 : 45352 5 - 0 : 2024-03-01 00:00:00- 这时我们就可以看到大部分数据都已经转化成了45352,所以接下来很简单将数据转化成float64类型,再转化成time.time类型,最后转化成我们想要的数据类型 - func parseFileUrl(filePath string) ([]map[string]string, error) {f, err := excelize.OpenFile(filePath)if err != nil {return nil, err}sheetName := f.GetSheetName(0)rows, err := f.GetRows(sheetName)if err != nil {return nil, err}styleId, _ := f.NewStyle(&excelize.Style{NumFmt: 0})_ = f.SetColStyle(sheetName, "A", styleId)rows, err = f.GetRows(sheetName)if len(rows) > 0 {for rowKey, cols := range rows {if len(cols) > 0 {for colKey, value := range cols {timeFloat, err := strconv.ParseFloat(value, 64)if err != nil {//err 说明无法转化成float64 那么有可能本身是字符串时间进行返回timeTime, err := time.Parse("2006-01-02 15:04:05", value)if err != nil {fmt.Println(rowKey, "-", colKey, ":", value)} else {value = timeTime.Format("2006-01-02 15:04:05")fmt.Println(rowKey, "-", colKey, ":", value)}break}timeTime, _ := excelize.ExcelDateToTime(timeFloat, false)value = timeTime.Format("2006-01-02 15:04:05")fmt.Println(rowKey, "-", colKey, ":", value)}}}}return nil, err }- 打印结果 - 0 - 0 : 2024-03-01 00:00:00 1 - 0 : 2024-03-01 00:00:00 2 - 0 : 2024-03-01 00:00:00 3 - 0 : 2024-03-01 00:00:00 4 - 0 : 2024-03-01 00:00:00 5 - 0 : 2024-03-01 00:00:00- 此时可以解决了我们的问题,指定对应的列,转化为常规类型,然后再转化为float64(针对无法转化的数据返回),再转化为time.time类型,最后转化成我们需要的类型 - 进阶- 那么如何自动进行转化?- 其实我们可以根据单元格自定义类型来进行转化,正如上面的例子,如当单元格自定义类型为: 
- yyyy"年"m"月"d"日"
- yyyy/m/d
- mmm-yy
- yyyy"年"m"月"
- yyyy/m/d h:mm
- ...
- 等类型的时候我们需要将他们转化成常规类型,然后根据后续操作转化成我们想要的类型。 - 如何自定类型判断呢?- 其实根据上述转化成常规类型的操作我们就可以知道是哪个字段来进行确定单元格格式类型 - styleId, _ := f.NewStyle(&excelize.Style{NumFmt: 0})- Style 中的 NumFmt 来进行决定 - 我们可以看下excelize 中 针对 NumFmt 的注释(在NewStyle方法上面有详细注释),这里我只粘贴部分注释代码 - // Index | Format String // -------+---------------------------------------------------- // 0 | General // 1 | 0 // 2 | 0.00 // 3 | #,##0 // 4 | #,##0.00 // 5 | ($#,##0_);($#,##0) // 6 | ($#,##0_);[Red]($#,##0) // 7 | ($#,##0.00_);($#,##0.00) // 8 | ($#,##0.00_);[Red]($#,##0.00) // 9 | 0% // 10 | 0.00% // 11 | 0.00E+00 // 12 | # ?/? // 13 | # ??/?? // 14 | m/d/yy // 15 | d-mmm-yy // 16 | d-mmm // 17 | mmm-yy // 18 | h:mm AM/PM // 19 | h:mm:ss AM/PM // 20 | h:mm // 21 | h:mm:ss // 22 | m/d/yy h:mm // ... | ... // 37 | (#,##0_);(#,##0) // 38 | (#,##0_);[Red](#,##0) // 39 | (#,##0.00_);(#,##0.00) // 40 | (#,##0.00_);[Red](#,##0.00) // 41 | _(* #,##0_);_(* (#,##0);_(* "-"_);_(@_) // 42 | _($* #,##0_);_($* (#,##0);_($* "-"_);_(@_) // 43 | _(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_) // 44 | _($* #,##0.00_);_($* (#,##0.00);_($* "-"??_);_(@_) // 45 | mm:ss // 46 | [h]:mm:ss // 47 | mm:ss.0 // 48 | ##0.0E+0 // 49 | @// Number format code in zh-cn language: // // Index | Symbol // -------+------------------------------------------- // 27 | yyyy"年"m"月" // 28 | m"月"d"日" // 29 | m"月"d"日" // 30 | m-d-yy // 31 | yyyy"年"m"月"d"日" // 32 | h"时"mm"分" // 33 | h"时"mm"分"ss"秒" // 34 | 上午/下午 h"时"mm"分" // 35 | 上午/下午 h"时"mm"分"ss"秒 // 36 | yyyy"年"m"月 // 50 | yyyy"年"m"月 // 51 | m"月"d"日 // 52 | yyyy"年"m"月 // 53 | m"月"d"日 // 54 | m"月"d"日 // 55 | 上午/下午 h"时"mm"分 // 56 | 上午/下午 h"时"mm"分"ss"秒 // 57 | yyyy"年"m"月 // 58 | m"月"d"日"- 我们可以知道NumFmt 对应的值代表着各种单元格格式,此时我们可以整理一下我们需要将其转化成常规类型的数据(只做参考,并没有全部实验,自己可以把常用的实验一下) - var ConversionTimeNumFmt = []int{14, //m/d/yy15, //d-mmm-yy17, //mmm-yy22, //m/d/yy h:mm27, // yyyy"年"m"月"30, //m-d-yy31, //yyyy"年"m"月"d"日"36, //yyyy"年"m"月50, //yyyy"年"m"月52, //yyyy"年"m"月57, //yyyy"年"m"月 }- 好了,现在我们要转换的单元格格式了,那么接下来我们就可以遍历一下excel的全部单元格格式类型,看一下哪些字段需要进行转化了,不过接下来问题又来了,如何知道excel里面对应的单元格格式呢 - 如何知道excel中单元格格式- excelize 中提供方法 GetCellStyle() 可以获取该单元格的所有样式对应的styleId - // GetCellStyle provides a function to get cell style index by given worksheet // name and cell reference. This function is concurrency safe. func (f *File) GetCellStyle(sheet, cell string) (int, error) {... }- 根据styleId 我们可以找到对应的所有样式配置 GetStyle() - // GetStyle provides a function to get style definition by given style index. func (f *File) GetStyle(idx int) (*Style, error) {... }- 单元格格式 就对应的是 style.NumFmt - 这时我们只需要知道每一个单元格的styleId 对应的 style.NumFmt 就可以将数据进行转化(这里做了三个循环,第一遍是获取了对应styleId, 第二遍是更改表样式,将指定类型转化为常规类型,第三遍就是获取对应的数据) - // parseFileUrl 解析文件流excel func parseFileUrl(filePath string) ([]map[string]string, error) {f, err := excelize.OpenFile(filePath)if err != nil {return nil, err}sheetName := f.GetSheetName(0)rows, err := f.GetRows(sheetName)if err != nil {return nil, err}//读取excel 所有styleId 数组styles := make([]int, 0)//所有需要更改单元格格式的 styleId 数组needChangeStyleIds := make([]int, 0)//所更改的cellsneedChangeCells := make([]string, 0)if len(rows) > 0 {//需要转化成的 style 对应style IdstyleIdZero, _ := f.NewStyle(&excelize.Style{NumFmt: 0})for rowKey, cols := range rows {if len(cols) > 0 {for colKey, _ := range cols {columnNumber, _ := excelize.CoordinatesToCellName(colKey+1, rowKey+1)styleId, _ := f.GetCellStyle(sheetName, columnNumber)if !arrayHelper.InArray(styles, styleId) {styles = append(styles, styleId)}}}}fmt.Println(styles)if len(styles) > 0 {for _, styleId := range styles {style, _ := f.GetStyle(styleId)if arrayHelper.InArray(ConversionTimeNumFmt, style.NumFmt) {needChangeStyleIds = append(needChangeStyleIds, styleId)}}}for rowKey, cols := range rows {if len(cols) > 0 {for colKey, _ := range cols {columnNumber, _ := excelize.CoordinatesToCellName(colKey+1, rowKey+1)styleId, _ := f.GetCellStyle(sheetName, columnNumber)if arrayHelper.InArray(needChangeStyleIds, styleId) {_ = f.SetCellStyle(sheetName, columnNumber, columnNumber, styleIdZero)needChangeCells = append(needChangeCells, columnNumber)}}}}rows, err = f.GetRows(sheetName)if err != nil {return nil, err}if len(rows) > 0 {for rowKey, cols := range rows {if len(cols) > 0 {for colKey, value := range cols {columnNumber, _ := excelize.CoordinatesToCellName(colKey+1, rowKey+1)if arrayHelper.InArray(needChangeCells, columnNumber) {timeFloat, err := strconv.ParseFloat(value, 64)if err != nil {//err 说明无法转化成float64 那么有可能本身是字符串时间进行返回timeTime, err := time.Parse("2006-01-02 15:04:05", value)if err != nil {fmt.Println(rowKey, "-", colKey, ":", value)} else {value = timeTime.Format("2006-01-02 15:04:05")fmt.Println(rowKey, "-", colKey, ":", value)}break}timeTime, _ := excelize.ExcelDateToTime(timeFloat, false)value = timeTime.Format("2006-01-02 15:04:05")fmt.Println(rowKey, "-", colKey, ":", value)}}}}}}return nil, err }var ConversionTimeNumFmt = []int{14, //m/d/yy15, //d-mmm-yy17, //mmm-yy22, //m/d/yy h:mm27, // yyyy"年"m"月"30, //m-d-yy31, //yyyy"年"m"月"d"日"36, //yyyy"年"m"月50, //yyyy"年"m"月52, //yyyy"年"m"月57, //yyyy"年"m"月 }- 其中InArray方法为 - // InArray 判断元素是否再数组内 func InArray[T int | float64 | string](array []T, value T) bool {for _, v := range array {if v == value {return true}}return false }- 通过三次遍历操作,自动转化了时间类型 
相关文章:
GO excelize 读取excel进行时间类型转换(自动转换)
GO excelize 读取excel进行时间类型转换(自动转换) 需求分析 需求:如何自动识别excel中的时间类型数据并转化成对应的 "Y-m-d H:i:s"类型数据。 分析:excelize在读取excel时,GetRows() 返回的都是字符串类…...
 
【算法与数据结构】二分查找思想
#1024程序员节|征文# 正文: 二分查找(binary search)是一种基于分治策略的高效搜索算法。它利用数据的有序性,每轮缩小一半搜索范围,直至找到目标元素或搜索区间为空为止,其实有时候数据没有序…...
PHP PDO:安全、灵活的数据持久层解决方案
PHP PDO:安全、灵活的数据持久层解决方案 PHP PDO(PHP Data Objects)是一个轻量级的、具有兼容接口的数据持久层抽象层。它提供了一个统一的API来访问多种数据库系统,如MySQL、PostgreSQL、SQLite、Oracle等。PDO扩展在PHP 5.1.0…...
九、Linux实战案例:项目部署全流程深度解析
Linux实战案例:项目部署全流程深度解析 在当今信息技术领域,Linux服务器凭借其卓越的稳定性、安全性以及强大的性能表现,被广泛应用于各类项目部署场景之中。本文将全面深入地介绍如何将一个项目成功部署至Linux服务器的完整流程,…...
 
GIS常见前端开发框架
#1024程序员节|征文# 伴随GIS的发展,陆续出现了众多开源地图框架,这些地图框架与众多行业应用融合,极大地拓展了GIS的生命力,这里介绍几个常见的GIS前端开发框架,排名不分先后。 1.Leaflet https://leafl…...
 
Java | Leetcode Java题解之第506题相对名次
题目: 题解: class Solution {public String[] findRelativeRanks(int[] score) {int n score.length;String[] desc {"Gold Medal", "Silver Medal", "Bronze Medal"};int[][] arr new int[n][2];for (int i 0; i &…...
 
数据结构 - 堆
今天我们将学习新的数据结构-堆。 01定义 堆是一种特殊的二叉树,并且满足以下两个特性: (1)堆是一棵完全二叉树; (2)堆中任意一个节点元素值都小于等于(或大于等于)左…...
 
html----图片按钮,商品展示
源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>图标</title><style>.box{width:…...
YOLOv11改进策略【卷积层】| ECCV-2024 小波卷积WTConv 增大感受野,降低参数量计算量,独家创新助力涨点
一、本文介绍 本文记录的是利用小波卷积WTConv模块优化YOLOv11的目标检测网络模型。WTConv的目的是在不出现过参数化的情况下有效地增加卷积的感受野,从而解决了CNN在感受野扩展中的参数膨胀问题。本文将其加入到深度可分离卷积中,有效降低模型参数量和计算量,并二次创新C3…...
redis高级篇之redis源码分析List类型quicklist底层演变 答疑159节
(1)ziplist压缩配置:list-compress-depth 0 表示一个quicklist两端不被压缩的节点个数。这里的节点是指quicklist双向链表的节点,而不是指ziplist里面的数据项个数参数list-compress-depth的取值含义如下: 0:是个特殊值,表示都不压缩。这是Redis的默认值…...
Elasticsearch 与 Lucene 的区别和联系
Elasticsearch 与 Lucene 的区别和联系 Elasticsearch 与 Lucene 的区别和联系一、知识背景Elasticsearch 简介Lucene 简介 二、Elasticsearch 和 Lucene 的区别适用场景性能优势和劣势架构设计的异同点 三、Elasticsearch和Lucene的联系四、Elasticsearch和Lucene的应用案例及…...
 
OpenCV视觉分析之运动分析(5)背景减除类BackgroundSubtractorMOG2的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 基于高斯混合模型的背景/前景分割算法。 该类实现了在文献[320]和[319]中描述的高斯混合模型背景减除。 cv::BackgroundSubtractorMOG2 类是 O…...
 
【SAP Hana】X-DOC:数据仓库ETL如何抽取SAP中的CDS视图数据
【SAP Hana】X-DOC:数据仓库ETL如何抽取SAP中的CDS视图数据 1、无参CDS对应数据库视图2、有参CDS对应数据库表函数3、封装有参CDS为无参CDS,从而对应数据库视图 1、无参CDS对应数据库视图 select * from ZFCML_REP_V where mandt 300;2、有参CDS对应数…...
WPF的UpdateSourceTrigger属性
在WPF中,UpdateSourceTrigger属性用于控制数据绑定中何时将绑定目标(通常是UI元素)的值更新回绑定源(通常是数据对象)。这个属性有以下几个值: Default:这是默认值,对于不同的绑定目…...
2024-09-25 环境变量,进程地址空间
一、认识常见的环境变量 1. echo $HOME 输出当前用户对应的家目录 当用户登录系统时,流程如下: (1)用户登录系统后,系统启动Shell程序。 (2)启动bash shell,准备接收用户指令。 &a…...
 
中国移动机器人将投入养老场景;华为与APUS共筑AI医疗多场景应用
AgeTech News 一周行业大事件 华为与APUS合作,共筑AI医疗多场景应用 中国移动展出人形机器人,预计投入养老等场景 作为科技与奥富能签约,共拓智能适老化改造领域 天与养老与香港科技园,共探智慧养老新模式 中山大学合作中国…...
青少年编程能力等级测评CPA C++ 四级试卷(1)
青少年编程能力等级测评CPA C 四级试卷(1) 一、单项选择题(共15题,每题3分,共45分) CP4_1_1.在面向对象程序设计中,与数据构成一个相互依存的整体的是( )。 A. 对数据…...
 
树上任意两点的距离
题目描述 给出 n 个点的一棵树,多次询问两点之间的最短距离。 注意:边是双向的。 输入描述 第一行为两个整数 n 和 m。n 表示点数,m 表示询问次数; 下来 n−1 行,每行三个整数 x,y,k,表示点 x 和点 y 之间…...
 
【 thinkphp8 】00008 thinkphp8数据查询,常用table,name方法,进行数据查询汇总
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【 t…...
Git的命令合集
关于Git的一些命令合集,会慢慢更新! 20241024程序员节开始写的,记录一下~~ git查看log、查看详细提交记录 会显示之前的提交记录 , 排序由近及远 git log log按q退出 git回退到某个commit命令: 退到/进到指定commit的sha码&…...
 
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了  先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
 
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
 
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
 
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
 
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
 
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...
