diff --git a/date/date.go b/date/date.go new file mode 100644 index 0000000..1abcbf3 --- /dev/null +++ b/date/date.go @@ -0,0 +1,82 @@ +package date + +import ( + "errors" + "fmt" + "time" +) + +// Format 根据特定格式格式化日期 +func (td *DateTime) Format(date time.Time, format string) (string, error) { + if _, ok := formatMap[format]; !ok { + return "", errors.New("unsupported format") + } + return date.Format(formatMap[format]), nil +} + +// Parse 将日期字符串转换为Time +func (td *DateTime) Parse(dateStr, format string) (time.Time, error) { + if _, ok := formatMap[format]; !ok { + return time.Time{}, errors.New("unsupported format") + } + return time.Parse(formatMap[format], dateStr) +} + +// Offset 时间偏移 +func (td *DateTime) Offset(date time.Time, format string) (time.Time, error) { + pd, err := time.ParseDuration(format) + if err != nil { + return date, err + } + return date.Add(pd), nil +} + +// OffsetDay 时间日期偏移 +func (td *DateTime) OffsetDay(date time.Time, day int) (time.Time, error) { + return td.Offset(date, fmt.Sprintf("%dh", day*24)) +} + +// OffsetHour 按小时偏移 +func (td *DateTime) OffsetHour(date time.Time, hour int) (time.Time, error) { + return td.Offset(date, fmt.Sprintf("%dh", hour)) +} + +// OffsetMinute 按分钟偏移 +func (td *DateTime) OffsetMinute(date time.Time, minute int) (time.Time, error) { + return td.Offset(date, fmt.Sprintf("%dm", minute)) +} + +// OffsetSecond 按秒偏移 +func (td *DateTime) OffsetSecond(date time.Time, second int) (time.Time, error) { + return td.Offset(date, fmt.Sprintf("%ds", second)) +} + +// OffsetMillisecond 按毫秒偏移 +func (td *DateTime) OffsetMillisecond(date time.Time, ms int) (time.Time, error) { + return td.Offset(date, fmt.Sprintf("%dms", ms)) +} + +// SubDays 日期差 +func (td *DateTime) SubDays(date1, date2 time.Time) int { + return int(date1.Sub(date2).Hours() / 24) +} + +// SubHours 小时差 +func (td *DateTime) SubHours(date1, date2 time.Time) int { + return int(date1.Sub(date2).Hours()) +} + +// SubMinutes 分钟差 +func (td *DateTime) SubMinutes(date1, date2 time.Time) int { + return int(date1.Sub(date2).Minutes()) +} + +// SubSeconds 秒差 +func (td *DateTime) SubSeconds(date1, date2 time.Time) int { + return int(date1.Sub(date2).Seconds()) +} + +// SubMilliseconds 毫秒差 +func (td *DateTime) SubMilliseconds(date1, date2 time.Time) int { + return int(date1.Sub(date2).Milliseconds()) +} diff --git a/date/date_test.go b/date/date_test.go new file mode 100644 index 0000000..2e02691 --- /dev/null +++ b/date/date_test.go @@ -0,0 +1,48 @@ +package date + +import ( + "fmt" + "testing" + "time" +) + +// Format 根据特定格式格式化日期 +func TestFormat(t *testing.T) { + tm, err := dateTime.Format(time.Now(), "yyyy-MM-dd") + if err != nil { + t.Errorf("format failed, %s", err.Error()) + return + } + fmt.Println(tm) +} + +// Parse 将日期字符串转换为Time +func TestParse(t *testing.T) { + tm, err := dateTime.Parse("2006-01-02", "yyyy-MM-dd") + if err != nil { + t.Errorf("parse failed, %s", err.Error()) + return + } + fmt.Println(tm) +} + +// Offset 时间偏移 +func TestOffset(t *testing.T) { + tm, err := dateTime.Offset(time.Now(), "-24h") + if err != nil { + t.Errorf("offset day failed, %s", err.Error()) + return + } + fmt.Println(tm) +} + +// SubDays 日期差 +func TestSubDays(t *testing.T) { + tm, _ := dateTime.Offset(time.Now(), "-24h") + n := dateTime.SubDays(time.Now(), tm) + if n != 0 { + t.Error("value must be 0") + return + } + fmt.Println(n) +} diff --git a/date/entry.go b/date/entry.go index 9702bc1..e6549b8 100644 --- a/date/entry.go +++ b/date/entry.go @@ -7,6 +7,23 @@ import ( "time" ) +// 格式化支持的类型 +var formatMap = map[string]string{ + "yyyy/MM/dd HH:mm:ss": "2006/01/02 15:04:05", + "yyyy.MM.dd HH:mm:ss": "2006.01.02 15:04:05", + "yyyy年MM月dd日 HH时mm分ss秒": "2006年01月02 15时04分05秒", + "yyyy-MM-dd": "2006-01-02", + "yyyy/MM/dd": "2006/01/02", + "yyyy.MM.dd": "2006.01.02", + "HH:mm:ss": "15:04:05", + "HH时mm分ss秒": "15时04分05秒", + "yyyy-MM-dd HH:mm": "2006-01-02 15:04", + "yyyy-MM-dd HH:mm:ss.SSS": "2006-01-02 15:04:05.999", + "yyyyMMddHHmmss": "20060102150405", + "yyyyMMddHHmmssSSS": "20060102150405999", + "yyyyMMdd": "20060102", +} + var weekStartDay = common.Sunday type DateTime struct { diff --git a/date/entry_test.go b/date/entry_test.go new file mode 100644 index 0000000..b8adf77 --- /dev/null +++ b/date/entry_test.go @@ -0,0 +1,3 @@ +package date + +var dateTime DateTime diff --git a/date/time.go b/date/time.go index 4dbe01e..0b6c963 100644 --- a/date/time.go +++ b/date/time.go @@ -18,7 +18,7 @@ func (dateTime *DateTime) Now() *DateTime { } // Format format time -func (dateTime *DateTime) Format(s ...string) string { +func (dateTime *DateTime) Format1(s ...string) string { if dateTime.t.IsZero() { dateTime.t = time.Now() } @@ -217,7 +217,7 @@ func (dateTime *DateTime) EndOfYear() *DateTime { } // Parse parse string to time -func (dateTime *DateTime) Parse(strFormat ...string) (*DateTime, error) { +func (dateTime *DateTime) Parse2(strFormat ...string) (*DateTime, error) { var err error if dateTime.t.IsZero() { dateTime.t = time.Now() @@ -272,7 +272,7 @@ func (dateTime *DateTime) Parse(strFormat ...string) (*DateTime, error) { // MustParse must parse string to time or it will panic func (dateTime *DateTime) MustParse(strs ...string) (d *DateTime) { - d, err := dateTime.Parse(strs...) + d, err := dateTime.Parse2(strs...) if err != nil { panic(err) } diff --git a/operaSystem/file.go b/operaSystem/file.go index 2a9d107..8cead40 100644 --- a/operaSystem/file.go +++ b/operaSystem/file.go @@ -1,8 +1,11 @@ package operaSystem import ( + "bufio" "encoding/base64" "os" + "path/filepath" + "strings" "time" ) @@ -76,3 +79,40 @@ func (fl *OperaSystem) IsDir(filePath string) bool { } return false } + +// Exist 判断文件是否存在 +func (tf *OperaSystem) FileExist(path string) bool { + _, err := os.Lstat(path) + return !os.IsNotExist(err) +} + +// RemoveSuffix 删除文件后缀 +func (tf *OperaSystem) RemoveSuffix(path string) string { + suffix := filepath.Ext(path) + if suffix != "" { + return strings.Replace(path, suffix, "", -1) + } + return "" +} + +// RemovePrefix 删除文件前缀 +func (tf *OperaSystem) RemovePrefix(path string) string { + prefix := filepath.Ext(path) + if prefix != "" { + return prefix[1:] + } + return "" +} + +// FileAppendString 将String写入文件,追加模式 +func (tf *OperaSystem) FileAppendString(content string, path string) (*os.File, error) { + file, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + return nil, err + } + defer file.Close() + write := bufio.NewWriter(file) + write.WriteString(content) + write.Flush() + return file, nil +} diff --git a/operaSystem/file_test.go b/operaSystem/file_test.go index acd7b7f..a7b0de1 100644 --- a/operaSystem/file_test.go +++ b/operaSystem/file_test.go @@ -39,3 +39,29 @@ func TestOperaSystem_IsDir(t *testing.T) { isDir := operaSystem.IsDir(filePath) fmt.Println(isDir) } + +// Exist 判断文件是否存在 +func TestOperaSystem_FileExist(t *testing.T) { + filePath := "./file.go" + isExist := operaSystem.FileExist(filePath) + fmt.Println(isExist) +} +func TestOperaSystem_RemovePrefix(t *testing.T) { + filePath := "./file.go" + filePath = operaSystem.RemovePrefix(filePath) + fmt.Println(filePath) +} +func TestOperaSystem_RemoveSuffix(t *testing.T) { + filePath := "./file.go" + filePath = operaSystem.RemoveSuffix(filePath) + fmt.Println(filePath) +} + +func TestOperaSystem_FileAppendString(t *testing.T) { + filePath := "./file_test.go" + operaSystem.FileAppendString("//将String写入文件 追加模式\n", filePath) + fmt.Println(filePath) +} + +//将String写入文件 追加模式 +//将String写入文件 追加模式 diff --git a/operaSystem/zip.go b/operaSystem/zip.go new file mode 100644 index 0000000..1ec7079 --- /dev/null +++ b/operaSystem/zip.go @@ -0,0 +1,104 @@ +package operaSystem + +import ( + "archive/zip" + "io" + "os" + "path" + "path/filepath" + "strings" +) + +// Zip 压缩文件 +func (fl *OperaSystem) Zip(dest string, paths ...string) error { + zfile, err := os.Create(dest) + if err != nil { + return err + } + defer zfile.Close() + + zipWriter := zip.NewWriter(zfile) + defer zipWriter.Close() + + for _, src := range paths { + // remove the trailing path sepeartor if it is a directory + src := strings.TrimSuffix(src, string(os.PathSeparator)) + + err = filepath.Walk(src, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + // create local file header + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + // set compression method to deflate + header.Method = zip.Deflate + // set relative path of file in zip archive + header.Name, err = filepath.Rel(filepath.Dir(src), path) + if err != nil { + return err + } + if info.IsDir() { + header.Name += string(os.PathSeparator) + } + // create writer for writing header + headerWriter, err := zipWriter.CreateHeader(header) + if err != nil { + return err + } + if info.IsDir() { + return nil + } + f, err := os.Open(path) + if err != nil { + return err + } + defer f.Close() + _, err = io.Copy(headerWriter, f) + return err + }) + if err != nil { + return err + } + } + return nil +} + +// Unzip 解压文件 +func (fl *OperaSystem) Unzip(src string, dest string) error { + reader, err := zip.OpenReader(src) + if err != nil { + return err + } + defer reader.Close() + + for _, file := range reader.File { + filePath := path.Join(dest, file.Name) + if file.FileInfo().IsDir() { + os.MkdirAll(filePath, os.ModePerm) + } else { + if err = os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { + return err + } + inFile, err := file.Open() + if err != nil { + return err + } + defer inFile.Close() + + outFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode()) + if err != nil { + return err + } + defer outFile.Close() + + _, err = io.Copy(outFile, inFile) + if err != nil { + return err + } + } + } + return nil +} diff --git a/operaSystem/zip_test.go b/operaSystem/zip_test.go new file mode 100644 index 0000000..653da7a --- /dev/null +++ b/operaSystem/zip_test.go @@ -0,0 +1,16 @@ +package operaSystem + +import "testing" + +func TestOperaSystem_Zip(t *testing.T) { + err := operaSystem.Zip("test.zip", "zip.go") + if err != nil { + t.Error(err) + } +} +func TestOperaSystem_Unzip(t *testing.T) { + err := operaSystem.Unzip("test.zip", "test") + if err != nil { + t.Error(err) + } +} diff --git a/readme.md b/readme.md index 2877ea1..57ea821 100644 --- a/readme.md +++ b/readme.md @@ -9,6 +9,13 @@ go get git.sre.ink/go/gtool *** +https://github.com/xbmlz/gct + +golang common tools + + + + https://github.com/duke-git/lancet lancet(柳叶刀)是一个全面、高效、可复用的go语言工具函数库。 lancet受到了java apache common包和lodash.js的启发。 \ No newline at end of file diff --git a/str/blank.go b/str/blank.go new file mode 100644 index 0000000..343e02f --- /dev/null +++ b/str/blank.go @@ -0,0 +1,42 @@ +package str + +// IsBlank 是否空(空白)字符串. +func (ts *Str) IsBlank(str string) bool { + // Check length + if len(str) > 0 { + // Iterate string + for i := range str { + // Check about char different from whitespace + // 227为全角空格 + if str[i] > 32 && str[i] != 227 { + return false + } + } + } + return true +} + +// IsNotBlank 是否非空(非空白)字符串. +func (ts *Str) IsNotBlank(str string) bool { + return !ts.IsBlank(str) +} + +// IsEmpty 是否空字符串. +func (ts *Str) IsEmpty(str string) bool { + return len(str) == 0 +} + +// IsNotEmpty 是否非空字符串. +func (ts *Str) IsNotEmpty(str string) bool { + return !ts.IsEmpty(str) +} + +// IsBlankOrEmpty 是否空白或空字符串. +func (ts *Str) IsBlankOrEmpty(str string) bool { + return ts.IsBlank(str) || ts.IsEmpty(str) +} + +// IsNotBlankOrEmpty 是否非空白或非空字符串. +func (ts *Str) IsNotBlankOrEmpty(str string) bool { + return !ts.IsBlankOrEmpty(str) +} diff --git a/str/blank_test.go b/str/blank_test.go new file mode 100644 index 0000000..91161e9 --- /dev/null +++ b/str/blank_test.go @@ -0,0 +1,51 @@ +package str + +import "testing" + +func TestIsBlank(t *testing.T) { + var tests = []struct { + param string + expected bool + }{ + {"", true}, + {" \t\n\r\v\f\x00 ", true}, + {"0", false}, + {"hello", false}, + } + for _, test := range tests { + actual := StrTool.IsBlank(test.param) + if actual != test.expected { + t.Errorf("%s must be %t", test.param, test.expected) + } + } +} +func FuzzStrIsBlank(f *testing.F) { + f.Fuzz(func(t *testing.T, str string) { + StrTool.IsBlank(str) + }) +} +func FuzzStrIsNotBlank(f *testing.F) { + f.Fuzz(func(t *testing.T, str string) { + StrTool.IsNotBlank(str) + }) +} +func FuzzStr_IsEmpty(f *testing.F) { + f.Fuzz(func(t *testing.T, str string) { + StrTool.IsEmpty(str) + }) +} +func FuzzStr_IsNotEmpty(f *testing.F) { + f.Fuzz(func(t *testing.T, str string) { + StrTool.IsNotEmpty(str) + }) +} +func FuzzIsBlankOrEmpty(f *testing.F) { + f.Fuzz(func(t *testing.T, str string) { + StrTool.IsBlankOrEmpty(str) + }) +} +func FuzzIsNotBlankOrEmpty(f *testing.F) { + f.Fuzz(func(t *testing.T, str string) { + StrTool.IsNotBlankOrEmpty(str) + }) +}