gpt4 book ai didi

date - 使用序号日期字段解析日期

转载 作者:IT王子 更新时间:2023-10-29 02:02:32 24 4
gpt4 key购买 nike

在 Golang 中,我如何解析一个月中有序数 日的日期?例如以下日期:

"Sunday 23rd January 2033 04:38:25 AM"

对于这个特定的日期,我可以对 rd 进行硬编码并在 time.Parse() 中使用此布局:

"Monday 02rd January 2006 15:04:05 PM"

但是如果这个月的一天是 21 号呢?

"Sunday 21st January 2033 04:38:25 AM"

(忽略这个日期不正确的事实)

以下内容适用于这种情况,但显然是错误的:

"Monday 02st January 2006 15:04:05 PM"

我一直在阅读 source code尚未证悟。

(我知道缺少时区也需要由程序逻辑来解决)。


这出现在我自己写的一组问题中,以改进我的日期解析。参见 https://github.com/soniah/date_practice如果你也需要练习!

最佳答案

如果你有一把锤子,一切看起来都像钉子。如果你有一个计算机程序员,一切看起来都像一个函数。


首先是序数函数的映射,

package main

import (
"fmt"
"strconv"
)

// generateOrdinalsMap generates map[ordinal]cardinal to stdout
// for the non-negative interval [min, max]
// as var name = map[string]string{}.
func generateOrdinalsMap(name string, min, max int) {
fmt.Printf("\nvar " + name + " = map[string]string{ // map[ordinal]cardinal\n")
for i := min; i >= 0 && i <= max; i++ {
var o string
switch i % 10 {
case 1:
o = "st"
case 2:
o = "nd"
case 3:
o = "rd"
default:
o = "th"
}
if 11 <= i && i <= 13 {
o = "th"
}
c := strconv.Itoa(i)
o = c + o
fmt.Printf(`"%s": "%s", `, o, c)
if (i)%5 == 0 || i == max {
fmt.Printf("\n")
}
}
fmt.Printf("}\n\n")
}

func main() {
// Generate ordinal map for days.
generateOrdinalsMap("dayOrdinals", 1, 31)
}

Playground :https://play.golang.org/p/W7Ad0pjjGu

输出:

var dayOrdinals = map[string]string{ // map[ordinal]cardinal
"1st": "1", "2nd": "2", "3rd": "3", "4th": "4", "5th": "5",
"6th": "6", "7th": "7", "8th": "8", "9th": "9", "10th": "10",
"11th": "11", "12th": "12", "13th": "13", "14th": "14", "15th": "15",
"16th": "16", "17th": "17", "18th": "18", "19th": "19", "20th": "20",
"21st": "21", "22nd": "22", "23rd": "23", "24th": "24", "25th": "25",
"26th": "26", "27th": "27", "28th": "28", "29th": "29", "30th": "30",
"31st": "31",
}

其次,一个 time.Parse 包装函数,它将 value 中的序数日转换为基数日,然后再使用基数日 layout,

package main

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

var dayOrdinals = map[string]string{ // map[ordinal]cardinal
"1st": "1", "2nd": "2", "3rd": "3", "4th": "4", "5th": "5",
"6th": "6", "7th": "7", "8th": "8", "9th": "9", "10th": "10",
"11th": "11", "12th": "12", "13th": "13", "14th": "14", "15th": "15",
"16th": "16", "17th": "17", "18th": "18", "19th": "19", "20th": "20",
"21st": "21", "22nd": "22", "23rd": "23", "24th": "24", "25th": "25",
"26th": "26", "27th": "27", "28th": "28", "29th": "29", "30th": "30",
"31st": "31",
}

// parseOrdinalDate parses a string time value using an ordinary package time layout.
// Before parsing, an ordinal day, [1st, 31st], is converted to a cardinal day, [1, 31].
// For example, "1st August 2017" is converted to "1 August 2017" before parsing, and
// "August 1st, 2017" is converted to "August 1, 2017" before parsing.
func parseOrdinalDate(layout, value string) (time.Time, error) {
const ( // day number
cardMinLen = len("1")
cardMaxLen = len("31")
ordSfxLen = len("th")
ordMinLen = cardMinLen + ordSfxLen
)

for k := 0; k < len(value)-ordMinLen; {
// i number start
for ; k < len(value) && (value[k] > '9' || value[k] < '0'); k++ {
}
i := k
// j cardinal end
for ; k < len(value) && (value[k] <= '9' && value[k] >= '0'); k++ {
}
j := k
if j-i > cardMaxLen || j-i < cardMinLen {
continue
}
// k ordinal end
// ASCII Latin (uppercase | 0x20) = lowercase
for ; k < len(value) && (value[k]|0x20 >= 'a' && value[k]|0x20 <= 'z'); k++ {
}
if k-j != ordSfxLen {
continue
}

// day ordinal to cardinal
for ; i < j-1 && (value[i] == '0'); i++ {
}
o := strings.ToLower(value[i:k])
c, ok := dayOrdinals[o]
if ok {
value = value[:i] + c + value[k:]
break
}
}

return time.ParseInLocation(layout, value, defaultLocation)
}

// Times without a timezone are Hong Kong times.
var defaultLocation = func(name string) *time.Location {
loc, err := time.LoadLocation(name)
if err != nil {
loc = time.UTC
}
return loc
}(`Asia/Hong_Kong`)

func main() {
var dates = []struct {
layout, value string
}{
{"Monday 02 January 2006 15:04:05 PM", "Friday 24th November 2017 13:14:07 PM"},
{"2 January 2006", "1st August 2017"}, // ISO
{"January 2, 2006", "August 1st, 2017"}, // USA
}
fmt.Println()
for _, d := range dates {
fmt.Printf("Layout: %q\n", d.layout)
fmt.Printf("Value: %q\n", d.value)
t, err := parseOrdinalDate(d.layout, d.value)
fmt.Printf("Time: %v Error: %v\n", t, err)
fmt.Printf("Unix: %v Error: %v\n", t, err)
fmt.Println()
}
}

Playground :https://play.golang.org/p/5INR83e66T

输出:

Layout: "Monday 02 January 2006 15:04:05 PM"
Value: "Friday 24th November 2017 13:14:07 PM"
Time: 2017-11-24 13:14:07 +0800 HKT Error: <nil>
Unix: 2017-11-24 13:14:07 +0800 HKT Error: <nil>

Layout: "2 January 2006"
Value: "1st August 2017"
Time: 2017-08-01 00:00:00 +0800 HKT Error: <nil>
Unix: 2017-08-01 00:00:00 +0800 HKT Error: <nil>

Layout: "January 2, 2006"
Value: "August 1st, 2017"
Time: 2017-08-01 00:00:00 +0800 HKT Error: <nil>
Unix: 2017-08-01 00:00:00 +0800 HKT Error: <nil>

第三,完成并运行您的date_practice 测试,

{
"wombat",
"Sunday 23rd January 2033 04:38:25 AM",
"Monday 2 January 2006 03:04:05 PM",
1990039105,
parseOrdinalDate,
nil,
},

{
"kangaroo",
"Tuesday 7th November 2017 03:18:25 PM",
"Monday 2 January 2006 03:04:05 PM",
1510039105,
parseOrdinalDate,
nil,
},

关于date - 使用序号日期字段解析日期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47471071/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com