欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

GO excelize讀取excel進(jìn)行時間類型轉(zhuǎn)換的示例代碼(自動轉(zhuǎn)換)

 更新時間:2024年10月25日 09:17:10   作者:chu_yubo  
我們經(jīng)常會遇到如何自動識別excel中的時間類型數(shù)據(jù)并轉(zhuǎn)化成對應(yīng)的 "Y-m-d H:i:s"類型數(shù)據(jù),本文小編給大家介紹了GO excelize讀取excel進(jìn)行時間類型轉(zhuǎn)換的示例代碼(自動轉(zhuǎn)換),需要的朋友可以參考下

需求分析

需求:如何自動識別excel中的時間類型數(shù)據(jù)并轉(zhuǎn)化成對應(yīng)的 "Y-m-d H:i:s"類型數(shù)據(jù)。

分析:excelize在讀取excel時,GetRows() 返回的都是字符串類型,并且有些時間類型的數(shù)據(jù)會進(jìn)行轉(zhuǎn)換,如果全部轉(zhuǎn)化成 float64 格式,然后轉(zhuǎn)換成對應(yīng)的字符串,并且excelize提供函數(shù)

func ExcelDateToTime(excelDate float64, use1904Format bool) (time.Time, error) {
    ...
}

可以將float64 轉(zhuǎn)換成time.Time 類型,time.Time 很容易轉(zhuǎn)化成對應(yīng)"Y-m-d H:i:s"格式字符串類型數(shù)據(jù)。所以我們的難點就在于如何自動識別excel中時日期時間類型數(shù)據(jù)

excel 單元格格式

以下3月1日數(shù)據(jù)寫入到excel中,excel都會識別成2024/3/1,但是對應(yīng)單元格格式不同,轉(zhuǎn)化為常規(guī)類型的話大部分都相同

  • 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
}

結(jié)果打印

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

由此我們可以看出時間類型打印出來的內(nèi)容不盡相同,這里我們可以想辦法把他們?nèi)哭D(zhuǎn)化成45352

這里我們就把他們轉(zhuǎn)化成常規(guī)類型,常規(guī)類型的數(shù)據(jù)大部分都為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
	}
    //轉(zhuǎn)化為常規(guī)類型,對應(yīng)style NumFmt 0
	styleId, _ := f.NewStyle(&excelize.Style{NumFmt: 0})
    //示例例中都放入A列,所以將A列數(shù)據(jù)全部轉(zhuǎn)化成對應(yīng)的常規(guī)類型
	_ = 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
}

再次進(jìn)行打印

0 - 0 : 45352
1 - 0 : 45352
2 - 0 : 45352
3 - 0 : 45352
4 - 0 : 45352
5 - 0 : 2024-03-01 00:00:00

這時我們就可以看到大部分?jǐn)?shù)據(jù)都已經(jīng)轉(zhuǎn)化成了45352,所以接下來很簡單將數(shù)據(jù)轉(zhuǎn)化成float64類型,再轉(zhuǎn)化成time.time類型,最后轉(zhuǎn)化成我們想要的數(shù)據(jù)類型

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 說明無法轉(zhuǎn)化成float64 那么有可能本身是字符串時間進(jìn)行返回
						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
}

打印結(jié)果

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

此時可以解決了我們的問題,指定對應(yīng)的列,轉(zhuǎn)化為常規(guī)類型,然后再轉(zhuǎn)化為float64(針對無法轉(zhuǎn)化的數(shù)據(jù)返回),再轉(zhuǎn)化為time.time類型,最后轉(zhuǎn)化成我們需要的類型

進(jìn)階

那么如何自動進(jìn)行轉(zhuǎn)化?

其實我們可以根據(jù)單元格自定義類型來進(jìn)行轉(zhuǎn)化,正如上面的例子,如當(dāng)單元格自定義類型為:

  • yyyy"年"m"月"d"日"
  • yyyy/m/d
  • mmm-yy
  • yyyy"年"m"月"
  • yyyy/m/d h:mm
  • ...
  • 等類型的時候我們需要將他們轉(zhuǎn)化成常規(guī)類型,然后根據(jù)后續(xù)操作轉(zhuǎn)化成我們想要的類型。

如何自定類型判斷呢?

其實根據(jù)上述轉(zhuǎn)化成常規(guī)類型的操作我們就可以知道是哪個字段來進(jìn)行確定單元格格式類型

styleId, _ := f.NewStyle(&excelize.Style{NumFmt: 0})

Style 中的 NumFmt 來進(jìn)行決定

我們可以看下excelize 中 針對 NumFmt 的注釋(在NewStyle方法上面有詳細(xì)注釋),這里我只粘貼部分注釋代碼

//	 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 對應(yīng)的值代表著各種單元格格式,此時我們可以整理一下我們需要將其轉(zhuǎn)化成常規(guī)類型的數(shù)據(jù)(只做參考,并沒有全部實驗,自己可以把常用的實驗一下)

var ConversionTimeNumFmt = []int{
	14, //m/d/yy
	15, //d-mmm-yy
	17, //mmm-yy
	22, //m/d/yy h:mm
	27, // yyyy"年"m"月"
	30, //m-d-yy
	31, //yyyy"年"m"月"d"日"
	36, //yyyy"年"m"月
	50, //yyyy"年"m"月
	52, //yyyy"年"m"月
	57, //yyyy"年"m"月
}

好了,現(xiàn)在我們要轉(zhuǎn)換的單元格格式了,那么接下來我們就可以遍歷一下excel的全部單元格格式類型,看一下哪些字段需要進(jìn)行轉(zhuǎn)化了,不過接下來問題又來了,如何知道excel里面對應(yīng)的單元格格式呢

如何知道excel中單元格格式

excelize 中提供方法 GetCellStyle() 可以獲取該單元格的所有樣式對應(yīng)的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) {
    ...
}

根據(jù)styleId 我們可以找到對應(yīng)的所有樣式配置 GetStyle()

// GetStyle provides a function to get style definition by given style index.
func (f *File) GetStyle(idx int) (*Style, error) {
    ...
}

單元格格式 就對應(yīng)的是 style.NumFmt

這時我們只需要知道每一個單元格的styleId 對應(yīng)的 style.NumFmt 就可以將數(shù)據(jù)進(jìn)行轉(zhuǎn)化(這里做了三個循環(huán),第一遍是獲取了對應(yīng)styleId, 第二遍是更改表樣式,將指定類型轉(zhuǎn)化為常規(guī)類型,第三遍就是獲取對應(yīng)的數(shù)據(jù))

// 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 數(shù)組
	styles := make([]int, 0)
	//所有需要更改單元格格式的 styleId 數(shù)組
	needChangeStyleIds := make([]int, 0)
    //所更改的cells
	needChangeCells := make([]string, 0)
	if len(rows) > 0 {
		//需要轉(zhuǎn)化成的 style 對應(yīng)style Id
		styleIdZero, _ := 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 說明無法轉(zhuǎn)化成float64 那么有可能本身是字符串時間進(jìn)行返回
						    	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/yy
	15, //d-mmm-yy
	17, //mmm-yy
	22, //m/d/yy h:mm
	27, // yyyy"年"m"月"
	30, //m-d-yy
	31, //yyyy"年"m"月"d"日"
	36, //yyyy"年"m"月
	50, //yyyy"年"m"月
	52, //yyyy"年"m"月
	57, //yyyy"年"m"月
}

其中InArray方法為

// InArray 判斷元素是否再數(shù)組內(nèi)
func InArray[T int | float64 | string](array []T, value T) bool {
	for _, v := range array {
		if v == value {
			return true
		}
	}
	return false
}

通過三次遍歷操作,自動轉(zhuǎn)化了時間類型

以上就是GO excelize讀取excel進(jìn)行時間類型轉(zhuǎn)換的示例代碼(自動轉(zhuǎn)換)的詳細(xì)內(nèi)容,更多關(guān)于GO excelize excel時間類型轉(zhuǎn)換的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Golang中for循環(huán)的用法示例詳解

    Golang中for循環(huán)的用法示例詳解

    for循環(huán)就是讓一段代碼循環(huán)的執(zhí)行,接下來通過本文給大家講解Golang中for循環(huán)的用法,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-12-12
  • go實現(xiàn)base64編碼的四種方式

    go實現(xiàn)base64編碼的四種方式

    本文主要介紹了go實現(xiàn)base64編碼的四種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • golang trace view視圖詳解

    golang trace view視圖詳解

    在golang中可以使用go pprof的工具對golang程序進(jìn)行性能分析,其中通過go trace 命令生成的trace view視圖對于我們分析系統(tǒng)延遲十分有幫助,鑒于當(dāng)前對trace view視圖的介紹還是很少,在粗略的看過trace統(tǒng)計原理后,將對這部分做比較詳細(xì)的介紹
    2023-08-08
  • golang進(jìn)行xml文件解析的操作方法

    golang進(jìn)行xml文件解析的操作方法

    本文介紹了Go語言中解析XML文件的幾種方法:小文件解析、大文件流式解析和復(fù)雜結(jié)構(gòu)解析,對于小文件,使用標(biāo)準(zhǔn)庫中的encoding/xml包;對于大文件,采用流式解析以避免內(nèi)存溢出,對于復(fù)雜結(jié)構(gòu)的XML文件,推薦使用第三方庫github.com/beevik/etree
    2024-11-11
  • 一文帶你深入理解Golang Context包

    一文帶你深入理解Golang Context包

    在 Go 語言中,Context 包是一種非常常用的工具,它被用來管理 goroutine 之間的通信和取消。本文將深入探討Context 包的基本原理,包括使用場景、原理和一些最佳實踐,需要的可以參考下
    2023-05-05
  • Go結(jié)構(gòu)體指針引發(fā)的值傳遞思考分析

    Go結(jié)構(gòu)體指針引發(fā)的值傳遞思考分析

    這篇文章主要為大家介紹了Go結(jié)構(gòu)體指針引發(fā)的值傳遞思考分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 一文帶你熟悉Go語言中函數(shù)的使用

    一文帶你熟悉Go語言中函數(shù)的使用

    這篇文章主要和大家分享一下Go語言中的函數(shù)的使用,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Go語言有一定的幫助,需要的小伙伴可以參考一下
    2022-11-11
  • Go語言中使用反射的方法

    Go語言中使用反射的方法

    這篇文章主要介紹了Go語言中使用反射的方法,實例分析了Go語言實現(xiàn)反射的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02
  • 深入了解Golang?interface{}的底層原理實現(xiàn)

    深入了解Golang?interface{}的底層原理實現(xiàn)

    在?Go?語言沒有泛型之前,接口可以作為一種替代實現(xiàn),也就是萬物皆為的?interface。那到底?interface?是怎么設(shè)計的底層結(jié)構(gòu)呢?下面咱們透過底層分別看一下這兩種類型的接口原理。感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助
    2022-10-10
  • 一文帶你理解Golang中的Time結(jié)構(gòu)

    一文帶你理解Golang中的Time結(jié)構(gòu)

    根據(jù)golang的time包的文檔可以知道,golang的time結(jié)構(gòu)中存儲了兩種時鐘,一種是Wall?Clocks,一種是Monotonic?Clocks,下面我們就來簡單了解一下這兩種結(jié)構(gòu)吧
    2023-09-09

最新評論