Home Download Docs Code Community
     1	//go:build linux
     2	
     3	/*
     4	Copyright 2013 The Perkeep Authors
     5	
     6	Licensed under the Apache License, Version 2.0 (the "License");
     7	you may not use this file except in compliance with the License.
     8	You may obtain a copy of the License at
     9	
    10	     http://www.apache.org/licenses/LICENSE-2.0
    11	
    12	Unless required by applicable law or agreed to in writing, software
    13	distributed under the License is distributed on an "AS IS" BASIS,
    14	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15	See the License for the specific language governing permissions and
    16	limitations under the License.
    17	*/
    18	
    19	package fs
    20	
    21	import (
    22		"errors"
    23		"fmt"
    24		"math"
    25		"strconv"
    26		"time"
    27	)
    28	
    29	var timeFormats = []string{
    30		time.RFC3339Nano,
    31		time.RFC3339,
    32		time.RFC1123Z,
    33		time.RFC1123,
    34		time.UnixDate,
    35		time.ANSIC,
    36		time.RubyDate,
    37		"2006-01-02T15:04",
    38		"2006-01-02T15",
    39		"2006-01-02",
    40		"2006-01",
    41		"2006",
    42	}
    43	
    44	var errUnparseableTimestamp = errors.New("unparsable timestamp")
    45	
    46	var powTable = []int{
    47		10e8,
    48		10e7,
    49		10e6,
    50		10e5,
    51		10e4,
    52		10e3,
    53		10e2,
    54		10e1,
    55		10,
    56		1,
    57	}
    58	
    59	// Hand crafted this parser since it's a really common path.
    60	func parseCanonicalTime(in string) (time.Time, error) {
    61		if len(in) < 20 || in[len(in)-1] != 'Z' {
    62			return time.Time{}, errUnparseableTimestamp
    63		}
    64	
    65		if !(in[4] == '-' && in[7] == '-' && in[10] == 'T' &&
    66			in[13] == ':' && in[16] == ':' && (in[19] == '.' || in[19] == 'Z')) {
    67			return time.Time{}, fmt.Errorf("positionally incorrect: %v", in)
    68		}
    69	
    70		// 2012-08-28T21:24:35.37465188Z
    71		//     4  7  10 13 16 19
    72		// -----------------------------
    73		// 0-4  5  8  11 14 17 20
    74	
    75		year, err := strconv.Atoi(in[0:4])
    76		if err != nil {
    77			return time.Time{}, fmt.Errorf("error parsing year: %v", err)
    78		}
    79	
    80		month, err := strconv.Atoi(in[5:7])
    81		if err != nil {
    82			return time.Time{}, fmt.Errorf("error parsing month: %v", err)
    83		}
    84	
    85		day, err := strconv.Atoi(in[8:10])
    86		if err != nil {
    87			return time.Time{}, fmt.Errorf("error parsing day: %v", err)
    88		}
    89	
    90		hour, err := strconv.Atoi(in[11:13])
    91		if err != nil {
    92			return time.Time{}, fmt.Errorf("error parsing hour: %v", err)
    93		}
    94	
    95		minute, err := strconv.Atoi(in[14:16])
    96		if err != nil {
    97			return time.Time{}, fmt.Errorf("error parsing minute: %v", err)
    98		}
    99	
   100		second, err := strconv.Atoi(in[17:19])
   101		if err != nil {
   102			return time.Time{}, fmt.Errorf("error parsing second: %v", err)
   103		}
   104	
   105		var nsecstr string
   106		if in[19] != 'Z' {
   107			nsecstr = in[20 : len(in)-1]
   108		}
   109		var nsec int
   110	
   111		if nsecstr != "" {
   112			nsec, err = strconv.Atoi(nsecstr)
   113			if err != nil {
   114				return time.Time{}, fmt.Errorf("error parsing nanoseconds: %v", err)
   115			}
   116		}
   117	
   118		nsec *= powTable[len(nsecstr)]
   119	
   120		return time.Date(year, time.Month(month), day,
   121			hour, minute, second, nsec, time.UTC), nil
   122	}
   123	
   124	func parseTime(in string) (time.Time, error) {
   125		// First, try a few numerics
   126		n, err := strconv.ParseInt(in, 10, 64)
   127		if err == nil {
   128			switch {
   129			case n > int64(math.MaxInt32)*1000:
   130				// nanosecond timestamps
   131				return time.Unix(n/1e9, n%1e9), nil
   132			case n > int64(math.MaxInt32):
   133				// millisecond timestamps
   134				return time.Unix(n/1000, (n%1000)*1e6), nil
   135			case n > 10000:
   136				// second timestamps
   137				return time.Unix(n, 0), nil
   138			}
   139		}
   140		rv, err := parseCanonicalTime(in)
   141		if err == nil {
   142			return rv, nil
   143		}
   144		for _, f := range timeFormats {
   145			parsed, err := time.Parse(f, in)
   146			if err == nil {
   147				return parsed, nil
   148			}
   149		}
   150		return time.Time{}, errUnparseableTimestamp
   151	}
Website layout inspired by memcached.
Content by the authors.