Golang解析带毫秒的非标准时间戳格式

Golang解析带毫秒的非标准时间戳格式 我有以下时间戳需要解析:

2022.05.14-00.37.13:544

我尝试使用以下代码片段,但无法解析毫秒部分:

package main

import (
	"fmt"
	"time"
)

func main() {
	s := "2022.05.14-00.37.13:544"
	t, err := time.Parse("2006.01.02-15.04.05:000", s)

	fmt.Println(t)
	fmt.Println(err)
}

它失败并显示:

parsing time "2022.05.14-00.37.13:544" as "2006.01.02-15.04.05:000": cannot parse "544" as ":000"

我尝试了不同的方法,但都没有成功。 只有在移除毫秒部分时才能正常工作。 为了也能解析毫秒,正确的“参考字符串”应该是什么? 感谢所有提示。

这是包含上述代码片段的 Go Playground:

Go Playground - The Go Programming Language

Go Gopher


更多关于Golang解析带毫秒的非标准时间戳格式的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

一种解决方法是先将冒号替换为句点,然后使用布局 “2006.01.02-15.04.05.000” 进行解析。

Go Playground - The Go Programming Language

更多关于Golang解析带毫秒的非标准时间戳格式的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


如果我阅读了这个议题,我认为我上述的用例目前无法通过Go的时间解析器实现:

时间:小数秒中不支持十进制逗号

dmitri.m 提出:

重现问题的步骤是什么?
如果可能,请包含一个指向 play.golang.org 上程序的链接。
Go 的 time 包期望小数秒中的十进制标记始终是一个点。
尝试解析使用十进制逗号的时间字符串会导致错误:
http://play.golang.org/p/d8qQasN0z1

在许多地区,十进制逗号是标准用法,但目前如果时间字符串中小数部分由逗号分隔,则无法解析秒的小数部分。
https://en.wikipedia.org/wiki/Decimal_mark#Countries_using_Arabic_numerals_with_decimal_comma

期望的输出是什么?
如果提供的布局也使用十进制逗号,时间字符串应该能够被解析且不报错。

实际看到的是什么?
将时间 "2013-08-19 22:56:01,234" 解析为 "2006-01-02 15:04:05,000" 时出错:
无法将 "234" 解析为 ",000"

你使用的是哪个编译器(5g, 6g, 8g, gccgo)?
6g

你使用的是哪个操作系统?
OS X 10.8.4

你使用的是哪个版本?(运行 'go version')
go version devel +5037426bea2f Mon Aug 19 23:09:24 2013 +0400 darwin/amd64

请在下面提供任何额外的信息。
请注意,(*time.Time).Format() 目前可以很好地输出十进制逗号,因为它不将其视为特殊字符。但是,为了在 Parse() 中支持十进制逗号而进行直接的修改——通过将它们添加到 stdFracSecond{0,9} 类中——会破坏这一点,因为 formatNano() 中硬编码了 '.'。

对于解析带毫秒的非标准时间戳格式 2022.05.14-00.37.13:544,需要使用正确的布局字符串。毫秒部分(:544)对应参考时间中的 .000 部分,但需要注意分隔符匹配。

以下是正确的解析方式:

package main

import (
	"fmt"
	"time"
)

func main() {
	s := "2022.05.14-00.37.13:544"
	
	// 正确的布局字符串
	layout := "2006.01.02-15.04.05.000"
	
	// 先将冒号替换为点号,以匹配布局
	s = s[:len(s)-4] + "." + s[len(s)-3:]
	
	t, err := time.Parse(layout, s)
	
	fmt.Println("解析结果:", t)
	fmt.Println("错误信息:", err)
	fmt.Println("格式化输出:", t.Format("2006-01-02 15:04:05.000"))
}

如果不想修改原始字符串,可以使用更灵活的正则表达式方法:

package main

import (
	"fmt"
	"regexp"
	"strconv"
	"time"
)

func main() {
	s := "2022.05.14-00.37.13:544"
	
	// 使用正则表达式提取各个部分
	re := regexp.MustCompile(`(\d{4})\.(\d{2})\.(\d{2})-(\d{2})\.(\d{2})\.(\d{2}):(\d{3})`)
	matches := re.FindStringSubmatch(s)
	
	if matches != nil {
		year, _ := strconv.Atoi(matches[1])
		month, _ := strconv.Atoi(matches[2])
		day, _ := strconv.Atoi(matches[3])
		hour, _ := strconv.Atoi(matches[4])
		minute, _ := strconv.Atoi(matches[5])
		second, _ := strconv.Atoi(matches[6])
		millisecond, _ := strconv.Atoi(matches[7])
		
		t := time.Date(year, time.Month(month), day, hour, minute, second, millisecond*1e6, time.UTC)
		
		fmt.Println("解析结果:", t)
		fmt.Println("格式化输出:", t.Format("2006-01-02 15:04:05.000"))
	}
}

或者使用字符串分割的简单方法:

package main

import (
	"fmt"
	"strconv"
	"strings"
	"time"
)

func main() {
	s := "2022.05.14-00.37.13:544"
	
	// 分割日期和时间部分
	parts := strings.Split(s, "-")
	if len(parts) != 2 {
		fmt.Println("格式错误")
		return
	}
	
	// 解析日期部分
	dateParts := strings.Split(parts[0], ".")
	if len(dateParts) != 3 {
		fmt.Println("日期格式错误")
		return
	}
	
	year, _ := strconv.Atoi(dateParts[0])
	month, _ := strconv.Atoi(dateParts[1])
	day, _ := strconv.Atoi(dateParts[2])
	
	// 解析时间部分(包含毫秒)
	timeParts := strings.Split(parts[1], ":")
	if len(timeParts) != 2 {
		fmt.Println("时间格式错误")
		return
	}
	
	// 解析时分秒
	hmsParts := strings.Split(timeParts[0], ".")
	if len(hmsParts) != 3 {
		fmt.Println("时分秒格式错误")
		return
	}
	
	hour, _ := strconv.Atoi(hmsParts[0])
	minute, _ := strconv.Atoi(hmsParts[1])
	second, _ := strconv.Atoi(hmsParts[2])
	
	// 解析毫秒
	millisecond, _ := strconv.Atoi(timeParts[1])
	
	// 创建时间对象
	t := time.Date(year, time.Month(month), day, hour, minute, second, millisecond*1e6, time.UTC)
	
	fmt.Println("解析结果:", t)
	fmt.Println("格式化输出:", t.Format("2006-01-02 15:04:05.000"))
}

关键点在于Go的time.Parse函数要求布局字符串中的分隔符必须完全匹配。原始时间戳中的毫秒部分使用冒号分隔(:544),而标准布局使用点号(.000),因此需要先进行字符串替换或使用其他解析方法。

回到顶部