v8.run/go/exp@v0.0.26-0.20230226010534-afcdbd3f782d/time2/timeparse/8601.go (about)

     1  package timeparse
     2  
     3  import (
     4  	"strconv"
     5  	"strings"
     6  	"time"
     7  )
     8  
     9  func Parse8601(data string) (unix, nano, offset int64) {
    10  	idx := strings.LastIndexAny(data, "T ")
    11  	var dt string = data
    12  	var tt string = "00:00:00.00Z"
    13  	if idx > 0 {
    14  		dt = data[:idx]
    15  		tt = data[idx+1:]
    16  	}
    17  
    18  	var year, month, day string
    19  
    20  	// Parse date
    21  
    22  	idx = strings.IndexAny(dt, "-/ ")
    23  	if idx == -1 {
    24  		// Year only
    25  		year = dt
    26  	} else {
    27  		year = dt[:idx]
    28  		dt = dt[idx+1:]
    29  
    30  		idx = strings.IndexAny(dt, "-/ ")
    31  		if idx == -1 {
    32  			// Year and month
    33  			month = dt
    34  		} else {
    35  			month = dt[:idx]
    36  			day = dt[idx+1:]
    37  		}
    38  	}
    39  
    40  	// Parse time
    41  
    42  	var hour, min, sec string
    43  	var TZ string = "Z"
    44  
    45  	// Split time and timezone
    46  	idx = strings.LastIndexAny(tt, "Z+-")
    47  	if idx > 0 {
    48  		TZ = tt[idx:]
    49  		tt = tt[:idx]
    50  	}
    51  
    52  	idx = strings.IndexAny(tt, ":")
    53  	if idx == -1 {
    54  		if len(tt) <= 2 {
    55  			// Hour only
    56  			hour = tt
    57  		} else {
    58  			// Maybe HHMMSS
    59  			hour = tt[:2]
    60  			tt = tt[2:]
    61  			if len(tt) >= 2 {
    62  				min = tt[:2]
    63  				sec = tt[2:]
    64  			}
    65  		}
    66  	} else {
    67  		hour = tt[:idx]
    68  		tt = tt[idx+1:]
    69  
    70  		idx = strings.IndexAny(tt, ":")
    71  		if idx == -1 {
    72  			// Hour and minute
    73  			min = tt
    74  		} else {
    75  			min = tt[:idx]
    76  			sec = tt[idx+1:]
    77  		}
    78  	}
    79  
    80  	// Parse timezone
    81  
    82  	if TZ != "Z" {
    83  		// +HH
    84  		// +HHMM
    85  		// +HH:MM
    86  		// -HH
    87  
    88  		var hh, mm string = "00", "00"
    89  		var sign int64 = 0
    90  
    91  		if len(TZ) > 0 {
    92  			if TZ[0] == '-' {
    93  				sign = -1
    94  			} else if TZ[0] == '+' {
    95  				sign = 1
    96  			}
    97  			TZ = TZ[1:]
    98  
    99  			if len(TZ) > 2 {
   100  				hh = TZ[:2]
   101  				mm = strings.TrimLeft(TZ[2:], ":")
   102  			} else {
   103  				hh = TZ
   104  			}
   105  		}
   106  
   107  		offh, err := strconv.Atoi(hh)
   108  		if err != nil {
   109  			offh = 0
   110  		}
   111  		offm, err := strconv.Atoi(mm)
   112  		if err != nil {
   113  			offm = 0
   114  		}
   115  
   116  		offset = int64(offh*3600+offm*60) * sign
   117  	}
   118  
   119  	// Parse Strings
   120  	yeari, err := strconv.Atoi(year)
   121  	if err != nil {
   122  		yeari = 1970
   123  	}
   124  	monthi, err := strconv.Atoi(month)
   125  	if err != nil || monthi < 1 || monthi > 12 {
   126  		monthi = 1
   127  	}
   128  	dayi, err := strconv.Atoi(day)
   129  	if err != nil || dayi < 1 || dayi > 31 {
   130  		dayi = 1
   131  	}
   132  	houri, err := strconv.Atoi(hour)
   133  	if err != nil || houri < 0 || houri > 23 {
   134  		houri = 0
   135  	}
   136  	mini, err := strconv.Atoi(min)
   137  	if err != nil || mini < 0 || mini > 59 {
   138  		mini = 0
   139  	}
   140  	// Parse seconds
   141  	secf, err := strconv.ParseFloat(sec, 64)
   142  	if err != nil || secf < 0 || secf >= 60 {
   143  		secf = 0
   144  	}
   145  
   146  	// Calculate seci and nano
   147  	seci := int64(secf)
   148  	nano = int64((secf - float64(seci)) * 1e9)
   149  
   150  	// Calculate unix
   151  	ttt := time.Date(yeari, time.Month(monthi), dayi, houri, mini, int(seci), int(nano), time.UTC)
   152  
   153  	return ttt.Unix() - offset, nano, offset
   154  }