// Copyright 2014 The Gogs Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. package base import ( "crypto/md5" "encoding/hex" "fmt" "math" "strings" "time" ) // Encode string to md5 hex value func EncodeMd5(str string) string { m := md5.New() m.Write([]byte(str)) return hex.EncodeToString(m.Sum(nil)) } // Seconds-based time units const ( Minute = 60 Hour = 60 * Minute Day = 24 * Hour Week = 7 * Day Month = 30 * Day Year = 12 * Month ) // TimeSince calculates the time interval and generate user-friendly string. func TimeSince(then time.Time) string { now := time.Now() lbl := "ago" diff := now.Unix() - then.Unix() if then.After(now) { lbl = "from now" diff = then.Unix() - now.Unix() } switch { case diff <= 0: return "now" case diff <= 2: return fmt.Sprintf("1 second %s", lbl) case diff < 1*Minute: return fmt.Sprintf("%d seconds %s", diff, lbl) case diff < 2*Minute: return fmt.Sprintf("1 minute %s", lbl) case diff < 1*Hour: return fmt.Sprintf("%d minutes %s", diff/Minute, lbl) case diff < 2*Hour: return fmt.Sprintf("1 hour %s", lbl) case diff < 1*Day: return fmt.Sprintf("%d hours %s", diff/Hour, lbl) case diff < 2*Day: return fmt.Sprintf("1 day %s", lbl) case diff < 1*Week: return fmt.Sprintf("%d days %s", diff/Day, lbl) case diff < 2*Week: return fmt.Sprintf("1 week %s", lbl) case diff < 1*Month: return fmt.Sprintf("%d weeks %s", diff/Week, lbl) case diff < 2*Month: return fmt.Sprintf("1 month %s", lbl) case diff < 1*Year: return fmt.Sprintf("%d months %s", diff/Month, lbl) case diff < 18*Month: return fmt.Sprintf("1 year %s", lbl) } return then.String() } const ( Byte = 1 KByte = Byte * 1024 MByte = KByte * 1024 GByte = MByte * 1024 TByte = GByte * 1024 PByte = TByte * 1024 EByte = PByte * 1024 ) var bytesSizeTable = map[string]uint64{ "b": Byte, "kb": KByte, "mb": MByte, "gb": GByte, "tb": TByte, "pb": PByte, "eb": EByte, } func logn(n, b float64) float64 { return math.Log(n) / math.Log(b) } func humanateBytes(s uint64, base float64, sizes []string) string { if s < 10 { return fmt.Sprintf("%dB", s) } e := math.Floor(logn(float64(s), base)) suffix := sizes[int(e)] val := float64(s) / math.Pow(base, math.Floor(e)) f := "%.0f" if val < 10 { f = "%.1f" } return fmt.Sprintf(f+"%s", val, suffix) } // FileSize calculates the file size and generate user-friendly string. func FileSize(s int64) string { sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"} return humanateBytes(uint64(s), 1024, sizes) } // Subtract deals with subtraction of all types of number. func Subtract(left interface{}, right interface{}) interface{} { var rleft, rright int64 var fleft, fright float64 var isInt bool = true switch left.(type) { case int: rleft = int64(left.(int)) case int8: rleft = int64(left.(int8)) case int16: rleft = int64(left.(int16)) case int32: rleft = int64(left.(int32)) case int64: rleft = left.(int64) case float32: fleft = float64(left.(float32)) isInt = false case float64: fleft = left.(float64) isInt = false } switch right.(type) { case int: rright = int64(right.(int)) case int8: rright = int64(right.(int8)) case int16: rright = int64(right.(int16)) case int32: rright = int64(right.(int32)) case int64: rright = right.(int64) case float32: fright = float64(left.(float32)) isInt = false case float64: fleft = left.(float64) isInt = false } if isInt { return rleft - rright } else { return fleft + float64(rleft) - (fright + float64(rright)) } } // DateFormat pattern rules. var datePatterns = []string{ // year "Y", "2006", // A full numeric representation of a year, 4 digits Examples: 1999 or 2003 "y", "06", //A two digit representation of a year Examples: 99 or 03 // month "m", "01", // Numeric representation of a month, with leading zeros 01 through 12 "n", "1", // Numeric representation of a month, without leading zeros 1 through 12 "M", "Jan", // A short textual representation of a month, three letters Jan through Dec "F", "January", // A full textual representation of a month, such as January or March January through December // day "d", "02", // Day of the month, 2 digits with leading zeros 01 to 31 "j", "2", // Day of the month without leading zeros 1 to 31 // week "D", "Mon", // A textual representation of a day, three letters Mon through Sun "l", "Monday", // A full textual representation of the day of the week Sunday through Saturday // time "g", "3", // 12-hour format of an hour without leading zeros 1 through 12 "G", "15", // 24-hour format of an hour without leading zeros 0 through 23 "h", "03", // 12-hour format of an hour with leading zeros 01 through 12 "H", "15", // 24-hour format of an hour with leading zeros 00 through 23 "a", "pm", // Lowercase Ante meridiem and Post meridiem am or pm "A", "PM", // Uppercase Ante meridiem and Post meridiem AM or PM "i", "04", // Minutes with leading zeros 00 to 59 "s", "05", // Seconds, with leading zeros 00 through 59 // time zone "T", "MST", "P", "-07:00", "O", "-0700", // RFC 2822 "r", time.RFC1123Z, } // Parse Date use PHP time format. func DateParse(dateString, format string) (time.Time, error) { replacer := strings.NewReplacer(datePatterns...) format = replacer.Replace(format) return time.ParseInLocation(format, dateString, time.Local) } // Date takes a PHP like date func to Go's time format. func DateFormat(t time.Time, format string) string { replacer := strings.NewReplacer(datePatterns...) format = replacer.Replace(format) return t.Format(format) } type Actioner interface { GetOpType() int GetActUserName() string GetRepoName() string } // ActionIcon accepts a int that represents action operation type // and returns a icon class name. func ActionIcon(opType int) string { switch opType { case 1: // Create repository. return "plus-circle" default: return "invalid type" } } const ( CreateRepoTpl = `%s created repository %s` ) // ActionDesc accepts int that represents action operation type // and returns the description. func ActionDesc(act Actioner) string { actUserName := act.GetActUserName() repoName := act.GetRepoName() switch act.GetOpType() { case 1: // Create repository. return fmt.Sprintf(CreateRepoTpl, actUserName, actUserName, actUserName, repoName, repoName) default: return "invalid type" } }