golang의 시간대와 신기한 시간.Parse

70363 단어 Golang
다음에서 시작합니다.https://www.jianshu.com/p/f809b06144f7

시간대


먼저 테스트 코드를 작성합니다.
const TIME_LAYOUT = "2006-01-02 15:04:05"

func parseWithLocation(name string, timeStr string) (time.Time, error) {
    locationName := name
    if l, err := time.LoadLocation(locationName); err != nil {
        println(err.Error())
        return time.Time{}, err
    } else {
        lt, _ := time.ParseInLocation(TIME_LAYOUT, timeStr, l)
        fmt.Println(locationName, lt)
        return lt, nil
    }
}
func testTime() {
    fmt.Println("0. now: ", time.Now())
    str := "2018-09-10 00:00:00"
    fmt.Println("1. str: ", str)
    t, _ := time.Parse(TIME_LAYOUT, str)
    fmt.Println("2. Parse time: ", t)
    tStr := t.Format(TIME_LAYOUT)
    fmt.Println("3. Format time str: ", tStr)
    name, offset := t.Zone()
    name2, offset2 := t.Local().Zone()
    fmt.Printf("4. Zone name: %v, Zone offset: %v
"
, name, offset) fmt.Printf("5. Local Zone name: %v, Local Zone offset: %v
"
, name2, offset2) tLocal := t.Local() tUTC := t.UTC() fmt.Printf("6. t: %v, Local: %v, UTC: %v
"
, t, tLocal, tUTC) fmt.Printf("7. t: %v, Local: %v, UTC: %v
"
, t.Format(TIME_LAYOUT), tLocal.Format(TIME_LAYOUT), tUTC.Format(TIME_LAYOUT)) fmt.Printf("8. Local.Unix: %v, UTC.Unix: %v
"
, tLocal.Unix(), tUTC.Unix()) str2 := "1969-12-31 23:59:59" t2, _ := time.Parse(TIME_LAYOUT, str2) fmt.Printf("9. str2:%v,time: %v, Unix: %v
"
, str2, t2, t2.Unix()) fmt.Printf("10. %v, %v
"
, tLocal.Format(time.ANSIC), tUTC.Format(time.ANSIC)) fmt.Printf("11. %v, %v
"
, tLocal.Format(time.RFC822), tUTC.Format(time.RFC822)) fmt.Printf("12. %v, %v
"
, tLocal.Format(time.RFC822Z), tUTC.Format(time.RFC822Z)) // parseWithLocation("America/Cordoba", str) parseWithLocation("Asia/Shanghai", str) parseWithLocation("Asia/Beijing", str) } testTime()

출력:
0. now:  2018-09-19 19:06:07.3642781 +0800 CST m=+0.005995601
1. str:  2018-09-10 00:00:00
2. Parse time:  2018-09-10 00:00:00 +0000 UTC
3. Format time str:  2018-09-10 00:00:00
4. Zone name: UTC, Zone offset: 0
5. Local Zone name: CST, Local Zone offset: 28800
6. t: 2018-09-10 00:00:00 +0000 UTC, Local: 2018-09-10 08:00:00 +0800 CST, UTC: 2018-09-10 00:00:00 +0000 UTC
7. t: 2018-09-10 00:00:00, Local: 2018-09-10 08:00:00, UTC: 2018-09-10 00:00:00
8. Local.Unix: 1536537600, UTC.Unix: 1536537600
9. str2:1969-12-31 23:59:59,time: 1969-12-31 23:59:59 +0000 UTC, Unix: -1
10. Mon Sep 10 08:00:00 2018, Mon Sep 10 00:00:00 2018
11. 10 Sep 18 08:00 CST, 10 Sep 18 00:00 UTC
12. 10 Sep 18 08:00 +0800, 10 Sep 18 00:00 +0000
America/Cordoba 2018-09-10 00:00:00 -0300 -03
Asia/Shanghai 2018-09-10 00:00:00 +0800 CST
cannot find Asia/Beijing in zip file C:\Go\/lib/time/zoneinfo.zip

상기 코드의 테스트 결과에서 몇 가지를 얻을 수 있다.
  • time.Now에서 얻은 현재 시간의 시간대는 컴퓨터의 현재 시간대와 같다.
  • time.Parse는 시간 문자열을 Time으로 변환합니다. 시간대는 UTC 시간대입니다.
  • Time 변수가 어떤 시간대에 저장되었든지 간에 유닉스 () 방법은 UTC 시간: 1970년 1월 1일 0시 0분 0초의 거리로 되돌아온다.
  • 유닉스()가 되돌아오는 초는 음수이며, 시간이 1970-01-01 00:00:00보다 작으면 음수이다.
  • Zone 방법은 변수의 시간대와 시간대와 UTC의 편이 초수를 얻을 수 있으며 여름철과 겨울철을 지원해야 한다.
  • time.LoadLocation은 시간대 이름에 따라 시간대 Location을 만들 수 있으며, 모든 시간대 이름은 $GOROOT/lib/time/zoneinfo에 있습니다.zip 파일에서 찾았습니다. zone info를 압축 풀었습니다.zip는 디렉터리와 파일을 한 무더기로 얻을 수 있습니다. 우리는 디렉터리와 파일의 이름만 필요로 합니다. 시간대 이름은 디렉터리 이름+파일 이름입니다. 예를 들어'아시아/Shanghai'입니다.중국의 시구명은'아시아/Shanghai'와'아시아/Chongqing'이고'아시아/베이징'은 없다.
  • time.ParseInLocation은 시간 문자열 및 시간대별 변환 시간을 지정할 수 있습니다.중국에 시구가 하나밖에 없고 여름철과 겨울철이 없을 때 무서운 미국에 무려 6개의 시구가 있다는 것은 생각만 해도 무섭다.

  • 신기한 시간.Parse


    처음 사용 시간.Parse는 이상한 레이아웃 파라미터 때문에 익숙하지 않습니다.golang에서 정의한 layout을 제외하고:
    const (
        ANSIC       = "Mon Jan _2 15:04:05 2006"
        UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
        RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
        RFC822      = "02 Jan 06 15:04 MST"
        RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
        RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
        RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
        RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
        RFC3339     = "2006-01-02T15:04:05Z07:00"
        RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
        Kitchen     = "3:04PM"
        // Handy time stamps.
        Stamp      = "Jan _2 15:04:05"
        StampMilli = "Jan _2 15:04:05.000"
        StampMicro = "Jan _2 15:04:05.000000"
        StampNano  = "Jan _2 15:04:05.000000000"
    )
    

    또한 다음과 같은 레이아웃을 사용자 정의할 수 있습니다.
    "2006-01-02 15:04:05"
    

    인터넷에서는 기본적으로 이 날이 golang 프로젝트가 창립된 시간이라고 전해지는데 생일을 기념하기 위해 이렇게 설계한 것은 사실 이것은 정말 터무니없는 말이다.
    인터넷 글에서 비교적 명확하게 말한 것을 찾지 못했는데, 다행히 원본 코드가 있어서, 시간을 열었다.Parse의 원본을 살펴보니 이 디자인이 매우 좋고 과학적인 것을 발견하였다.
    layout의 주요 코드는 nextStdChunk 방법에서 확인합니다.
    // nextStdChunk finds the first occurrence of a std string in
    // layout and returns the text before, the std string, and the text after.
    func nextStdChunk(layout string) (prefix string, std int, suffix string) {
        for i := 0; i < len(layout); i++ {
            switch c := int(layout[i]); c {
            case 'J': // January, Jan
                if len(layout) >= i+3 && layout[i:i+3] == "Jan" {
                    if len(layout) >= i+7 && layout[i:i+7] == "January" {
                        return layout[0:i], stdLongMonth, layout[i+7:]
                    }
                    if !startsWithLowerCase(layout[i+3:]) {
                        return layout[0:i], stdMonth, layout[i+3:]
                    }
                }
    
            case 'M': // Monday, Mon, MST
                if len(layout) >= i+3 {
                    if layout[i:i+3] == "Mon" {
                        if len(layout) >= i+6 && layout[i:i+6] == "Monday" {
                            return layout[0:i], stdLongWeekDay, layout[i+6:]
                        }
                        if !startsWithLowerCase(layout[i+3:]) {
                            return layout[0:i], stdWeekDay, layout[i+3:]
                        }
                    }
                    if layout[i:i+3] == "MST" {
                        return layout[0:i], stdTZ, layout[i+3:]
                    }
                }
    
            case '0': // 01, 02, 03, 04, 05, 06
                if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' {
                    return layout[0:i], std0x[layout[i+1]-'1'], layout[i+2:]
                }
    
            case '1': // 15, 1
                if len(layout) >= i+2 && layout[i+1] == '5' {
                    return layout[0:i], stdHour, layout[i+2:]
                }
                return layout[0:i], stdNumMonth, layout[i+1:]
    
            case '2': // 2006, 2
                if len(layout) >= i+4 && layout[i:i+4] == "2006" {
                    return layout[0:i], stdLongYear, layout[i+4:]
                }
                return layout[0:i], stdDay, layout[i+1:]
    
            case '_': // _2, _2006
                if len(layout) >= i+2 && layout[i+1] == '2' {
                    //_2006 is really a literal _, followed by stdLongYear
                    if len(layout) >= i+5 && layout[i+1:i+5] == "2006" {
                        return layout[0 : i+1], stdLongYear, layout[i+5:]
                    }
                    return layout[0:i], stdUnderDay, layout[i+2:]
                }
    
            case '3':
                return layout[0:i], stdHour12, layout[i+1:]
    
            case '4':
                return layout[0:i], stdMinute, layout[i+1:]
    
            case '5':
                return layout[0:i], stdSecond, layout[i+1:]
    
            case 'P': // PM
                if len(layout) >= i+2 && layout[i+1] == 'M' {
                    return layout[0:i], stdPM, layout[i+2:]
                }
    
            case 'p': // pm
                if len(layout) >= i+2 && layout[i+1] == 'm' {
                    return layout[0:i], stdpm, layout[i+2:]
                }
    
            case '-': // -070000, -07:00:00, -0700, -07:00, -07
                if len(layout) >= i+7 && layout[i:i+7] == "-070000" {
                    return layout[0:i], stdNumSecondsTz, layout[i+7:]
                }
                if len(layout) >= i+9 && layout[i:i+9] == "-07:00:00" {
                    return layout[0:i], stdNumColonSecondsTZ, layout[i+9:]
                }
                if len(layout) >= i+5 && layout[i:i+5] == "-0700" {
                    return layout[0:i], stdNumTZ, layout[i+5:]
                }
                if len(layout) >= i+6 && layout[i:i+6] == "-07:00" {
                    return layout[0:i], stdNumColonTZ, layout[i+6:]
                }
                if len(layout) >= i+3 && layout[i:i+3] == "-07" {
                    return layout[0:i], stdNumShortTZ, layout[i+3:]
                }
    
            case 'Z': // Z070000, Z07:00:00, Z0700, Z07:00,
                if len(layout) >= i+7 && layout[i:i+7] == "Z070000" {
                    return layout[0:i], stdISO8601SecondsTZ, layout[i+7:]
                }
                if len(layout) >= i+9 && layout[i:i+9] == "Z07:00:00" {
                    return layout[0:i], stdISO8601ColonSecondsTZ, layout[i+9:]
                }
                if len(layout) >= i+5 && layout[i:i+5] == "Z0700" {
                    return layout[0:i], stdISO8601TZ, layout[i+5:]
                }
                if len(layout) >= i+6 && layout[i:i+6] == "Z07:00" {
                    return layout[0:i], stdISO8601ColonTZ, layout[i+6:]
                }
                if len(layout) >= i+3 && layout[i:i+3] == "Z07" {
                    return layout[0:i], stdISO8601ShortTZ, layout[i+3:]
                }
    
            case '.': // .000 or .999 - repeated digits for fractional seconds.
                if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') {
                    ch := layout[i+1]
                    j := i + 1
                    for j < len(layout) && layout[j] == ch {
                        j++
                    }
                    // String of digits must end here - only fractional second is all digits.
                    if !isDigit(layout, j) {
                        std := stdFracSecond0
                        if layout[i+1] == '9' {
                            std = stdFracSecond9
                        }
                        std |= (j - (i + 1)) << stdArgShift
                        return layout[0:i], std, layout[j:]
                    }
                }
            }
        }
        return layout, 0, ""
    }
    

    레이아웃의 모든 대표 연월일 시분초, 심지어 시구의 값이 서로 다르다는 것을 발견할 수 있다.
    예를 들어 년도: 단기 06, 장기 2006, 월: 01, Jan, January 일: 02, 2,_2시: 15, 3, 03분: 04, 4초: 05, 5
    모두 같지 않기 때문에layout을 훑어보면 switchcase를 통해 모든 블록의 의미와 문자열의 위치를 해석할 수 있습니다. 이렇게 하면 대응하는 형식의 시간 문자열을 입력하면 순조롭게 해석할 수 있습니다.이렇게 하면 layout도 사용자 정의할 수 있고 순서가 임의입니다. 아래의 각 블록이 정의한 규칙에 부합하기만 하면 코드의 주석은 규칙 작성입니다.
    const (
        _                        = iota
        stdLongMonth             = iota + stdNeedDate  // "January"
        stdMonth                                       // "Jan"
        stdNumMonth                                    // "1"
        stdZeroMonth                                   // "01"
        stdLongWeekDay                                 // "Monday"
        stdWeekDay                                     // "Mon"
        stdDay                                         // "2"
        stdUnderDay                                    // "_2"
        stdZeroDay                                     // "02"
        stdHour                  = iota + stdNeedClock // "15"
        stdHour12                                      // "3"
        stdZeroHour12                                  // "03"
        stdMinute                                      // "4"
        stdZeroMinute                                  // "04"
        stdSecond                                      // "5"
        stdZeroSecond                                  // "05"
        stdLongYear              = iota + stdNeedDate  // "2006"
        stdYear                                        // "06"
        stdPM                    = iota + stdNeedClock // "PM"
        stdpm                                          // "pm"
        stdTZ                    = iota                // "MST"
        stdISO8601TZ                                   // "Z0700"  // prints Z for UTC
        stdISO8601SecondsTZ                            // "Z070000"
        stdISO8601ShortTZ                              // "Z07"
        stdISO8601ColonTZ                              // "Z07:00" // prints Z for UTC
        stdISO8601ColonSecondsTZ                       // "Z07:00:00"
        stdNumTZ                                       // "-0700"  // always numeric
        stdNumSecondsTz                                // "-070000"
        stdNumShortTZ                                  // "-07"    // always numeric
        stdNumColonTZ                                  // "-07:00" // always numeric
        stdNumColonSecondsTZ                           // "-07:00:00"
        stdFracSecond0                                 // ".0", ".00", ... , trailing zeros included
        stdFracSecond9                                 // ".9", ".99", ..., trailing zeros omitted
    
        stdNeedDate  = 1 << 8             // need month, day, year
        stdNeedClock = 2 << 8             // need hour, minute, second
        stdArgShift  = 16                 // extra argument in high bits, above low stdArgShift
        stdMask      = 1<

    시간대: 시간대 사용: MST 시간대 편이 사용-0700 또는 Z0700 등등.다음은 사용 시간대의 예입니다. Z0700 비교적 특수합니다. 입력 시간이 Z를 직접 사용할 때 UTC 시간대를 대표합니다.
    func testTimeParse() {
        t, _ := time.Parse("2006-01-02 15:04:05 -0700 MST", "2018-09-20 15:39:06 +0800 CST")
        fmt.Println(t)
        t, _ = time.Parse("2006-01-02 15:04:05 -0700 MST", "2018-09-20 15:39:06 +0000 CST")
        fmt.Println(t)
        t, _ = time.Parse("2006-01-02 15:04:05 Z0700 MST", "2018-09-20 15:39:06 +0800 CST")
        fmt.Println(t)
        t, _ = time.Parse("2006-01-02 15:04:05 Z0700 MST", "2018-09-20 15:39:06 Z GMT")
        fmt.Println(t)
        t, _ = time.Parse("2006-01-02 15:04:05 Z0700 MST", "2018-09-20 15:39:06 +0000 GMT")
        fmt.Println(t)
    }
    

    출력:
    2018-09-20 15:39:06 +0800 CST
    2018-09-20 15:39:06 +0000 CST
    2018-09-20 15:39:06 +0800 CST
    2018-09-20 15:39:06 +0000 UTC
    2018-09-20 15:39:06 +0000 GMT
    

    좋은 웹페이지 즐겨찾기