github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/ztime/transform.go (about)

     1  package ztime
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/sohaha/zlsgo/zstring"
    11  )
    12  
    13  const (
    14  	timePattern = `(\d{4}[-/\.]\d{1,2}[-/\.]\d{1,2})[:\sT-]*(\d{0,2}:{0,1}\d{0,2}:{0,1}\d{0,2}){0,1}\.{0,1}(\d{0,9})([\sZ]{0,1})([\+-]{0,1})([:\d]*)`
    15  )
    16  
    17  var (
    18  	TimeTpl      = "2006-01-02 15:04:05"
    19  	formatKeyTpl = map[byte]string{
    20  		'd': "02",
    21  		'D': "Mon",
    22  		'w': "Monday",
    23  		'N': "Monday",
    24  		'S': "02",
    25  		'l': "Monday",
    26  		'F': "January",
    27  		'm': "01",
    28  		'M': "Jan",
    29  		'n': "1",
    30  		'Y': "2006",
    31  		'y': "06",
    32  		'a': "pm",
    33  		'A': "PM",
    34  		'g': "3",
    35  		'h': "03",
    36  		'H': "15",
    37  		'i': "04",
    38  		's': "05",
    39  		'O': "-0700",
    40  		'P': "-07:00",
    41  		'T': "MST",
    42  		'u': "000000",
    43  		'c': "2006-01-02T15:04:05-07:00",
    44  		'r': "Mon, 02 Jan 06 15:04 MST",
    45  	}
    46  	GetLocationName = func(zone int) string {
    47  		switch zone {
    48  		case 8:
    49  			return "Asia/Shanghai"
    50  		}
    51  		return "UTC"
    52  	}
    53  )
    54  
    55  type TimeEngine struct {
    56  	zone *time.Location
    57  }
    58  
    59  // Zone eastEightTimeZone
    60  func Zone(zone ...int) *time.Location {
    61  	if len(zone) > 0 {
    62  		return time.FixedZone(GetLocationName(zone[0]), zone[0]*3600)
    63  	}
    64  	return time.Local
    65  }
    66  
    67  // FormatTlp format template
    68  func FormatTlp(format string) string {
    69  	runes := []rune(format)
    70  	buffer := bytes.NewBuffer(nil)
    71  	for i := 0; i < len(runes); i++ {
    72  		switch runes[i] {
    73  		case '\\':
    74  			if i < len(runes)-1 {
    75  				buffer.WriteRune(runes[i+1])
    76  				i += 1
    77  				continue
    78  			} else {
    79  				return buffer.String()
    80  			}
    81  		default:
    82  			if runes[i] > 255 {
    83  				buffer.WriteRune(runes[i])
    84  				break
    85  			}
    86  			if f, ok := formatKeyTpl[byte(runes[i])]; ok {
    87  				buffer.WriteString(f)
    88  			} else {
    89  				buffer.WriteRune(runes[i])
    90  			}
    91  		}
    92  	}
    93  	return buffer.String()
    94  }
    95  
    96  // New new timeEngine
    97  func New(zone ...int) *TimeEngine {
    98  	e := &TimeEngine{}
    99  	timezone := Zone(zone...)
   100  	if timezone != time.Local {
   101  		e.zone = timezone
   102  	}
   103  	return e
   104  }
   105  
   106  // SetTimeZone SetTimeZone
   107  func (e *TimeEngine) SetTimeZone(zone int) *TimeEngine {
   108  	e.zone = Zone(zone)
   109  	return e
   110  }
   111  
   112  // GetTimeZone GetTimeZone
   113  func (e *TimeEngine) GetTimeZone() *time.Location {
   114  	if e.zone == nil {
   115  		return time.Local
   116  	}
   117  	return e.zone
   118  }
   119  
   120  func (e *TimeEngine) In(t time.Time) time.Time {
   121  	if e.zone == nil {
   122  		return t
   123  	}
   124  	return t.In(e.zone)
   125  }
   126  
   127  // FormatTime string format of return time
   128  func (e *TimeEngine) FormatTime(t time.Time, format ...string) string {
   129  	t = e.In(t)
   130  	tpl := TimeTpl
   131  	if len(format) > 0 {
   132  		tpl = FormatTlp(format[0])
   133  	}
   134  	return t.Format(tpl)
   135  }
   136  
   137  // FormatTimestamp convert UNIX time to time string
   138  func (e *TimeEngine) FormatTimestamp(timestamp int64, format ...string) string {
   139  	if timestamp <= 9999999999 {
   140  		return e.FormatTime(e.Unix(timestamp), format...)
   141  	}
   142  	if timestamp <= 9999999999999 {
   143  		timestamp = timestamp * 1000
   144  	}
   145  	return e.FormatTime(e.UnixMicro(timestamp), format...)
   146  }
   147  
   148  // Unix int to time
   149  func (e *TimeEngine) Unix(tt int64) time.Time {
   150  	return e.In(time.Unix(tt, 0))
   151  }
   152  
   153  // UnixMicro int to time
   154  func (e *TimeEngine) UnixMicro(tt int64) time.Time {
   155  	return e.In(time.Unix(tt/1e6, (tt%1e6)*1e3))
   156  }
   157  
   158  // Parse Parse
   159  func (e *TimeEngine) Parse(str string, format ...string) (t time.Time, err error) {
   160  	if len(format) > 0 {
   161  		return time.ParseInLocation(FormatTlp(format[0]), str, e.GetTimeZone())
   162  	}
   163  
   164  	var year, month, day, hour, min, sec string
   165  	match, err := zstring.RegexExtract(timePattern, str)
   166  	if err != nil {
   167  		return
   168  	}
   169  	matchLen := len(match)
   170  	if matchLen == 0 {
   171  		err = errors.New("cannot parse")
   172  		return
   173  	}
   174  	if matchLen > 1 && match[1] != "" {
   175  		for k, v := range match {
   176  			match[k] = strings.TrimSpace(v)
   177  		}
   178  		arr := make([]string, 3)
   179  		for _, v := range []string{"-", "/", "."} {
   180  			arr = strings.Split(match[1], v)
   181  			if len(arr) >= 3 {
   182  				break
   183  			}
   184  		}
   185  		if len(arr) < 3 {
   186  			err = errors.New("cannot parse date")
   187  			return
   188  		}
   189  		year = arr[0]
   190  		month = zstring.Pad(arr[1], 2, "0", zstring.PadLeft)
   191  		day = zstring.Pad(arr[2], 2, "0", zstring.PadLeft)
   192  	}
   193  
   194  	if len(match[2]) > 0 {
   195  		s := strings.Replace(match[2], ":", "", -1)
   196  		if len(s) < 6 {
   197  			s += strings.Repeat("0", 6-len(s))
   198  		}
   199  		hour = zstring.Pad(s[0:2], 2, "0", zstring.PadLeft)
   200  		min = zstring.Pad(s[2:4], 2, "0", zstring.PadLeft)
   201  		sec = zstring.Pad(s[4:6], 2, "0", zstring.PadLeft)
   202  		return time.ParseInLocation(TimeTpl, year+"-"+month+"-"+day+" "+hour+":"+min+":"+sec, e.GetTimeZone())
   203  	}
   204  	return time.ParseInLocation("2006-01-02", year+"-"+month+"-"+day, e.GetTimeZone())
   205  }
   206  
   207  func (e *TimeEngine) Week(t time.Time) int {
   208  	week := e.In(t).Weekday().String()
   209  	switch week {
   210  	case "Monday":
   211  		return 1
   212  	case "Tuesday":
   213  		return 2
   214  	case "Wednesday":
   215  		return 3
   216  	case "Thursday":
   217  		return 4
   218  	case "Friday":
   219  		return 5
   220  	case "Saturday":
   221  		return 6
   222  	// case "Sunday":
   223  	default:
   224  		return 0
   225  	}
   226  }
   227  
   228  // MonthRange gets the start and end UNIX times for the specified year and month
   229  func (e *TimeEngine) MonthRange(year int, month int) (beginTime, endTime int64, err error) {
   230  	var monthStr string
   231  	t := e.In(time.Now())
   232  
   233  	if year == 0 {
   234  		year = t.Year()
   235  	}
   236  
   237  	if month == 0 {
   238  		month = int(t.Month())
   239  	}
   240  	if month <= 9 {
   241  		monthStr = fmt.Sprintf("0%d", month)
   242  	} else {
   243  		monthStr = fmt.Sprint(month)
   244  	}
   245  	yearStr := fmt.Sprint(year)
   246  	str := yearStr + "-" + monthStr + "-01 00:00:00"
   247  	begin, err := e.Parse(str)
   248  	if err != nil {
   249  		return
   250  	}
   251  	beginTime = begin.Unix()
   252  	month = int(begin.Month())
   253  	day := 30
   254  	if month == 2 {
   255  		day = 28
   256  	} else if month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12 {
   257  		day = 31
   258  	}
   259  
   260  	str = yearStr + "-" + monthStr + "-" + fmt.Sprint(day) + " 23:59:59"
   261  	end, _ := e.Parse(str)
   262  	endTime = end.Unix()
   263  	return
   264  }