sixty.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package otherutils
  2. import (
  3. "bytes"
  4. "fmt"
  5. "math/rand"
  6. "strings"
  7. "sync/atomic"
  8. "time"
  9. )
  10. const (
  11. charset = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  12. maxBase = 62
  13. defaultBase = 61
  14. maxOrderNum = 65536
  15. )
  16. var orderIncrId uint32 // 订单自增ID,每次重启从头开始即可
  17. // ConvertToBaseN converts a decimal number to a string representation in the specified base (2-62)
  18. func ConvertToBaseN(decimalNum int64, base int64) (string, error) {
  19. if base <= 0 || base > maxBase {
  20. return "", fmt.Errorf("base must be between 1 and %d", maxBase)
  21. }
  22. if decimalNum == 0 {
  23. return "0", nil
  24. }
  25. if decimalNum < 0 {
  26. return "", fmt.Errorf("negative numbers are not supported")
  27. }
  28. var buf bytes.Buffer
  29. for decimalNum > 0 {
  30. remainder := decimalNum % base
  31. decimalNum /= base
  32. buf.WriteByte(charset[remainder])
  33. }
  34. // Reverse the result
  35. result := buf.Bytes()
  36. for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 {
  37. result[i], result[j] = result[j], result[i]
  38. }
  39. return string(result), nil
  40. }
  41. // ConvertToDecimal converts a string in the specified base (2-62) to decimal
  42. func ConvertToDecimal(str string, base int64) (int64, error) {
  43. if base <= 0 || base > maxBase {
  44. return 0, fmt.Errorf("base must be between 1 and %d", maxBase)
  45. }
  46. if str == "" {
  47. return 0, fmt.Errorf("empty string is not valid")
  48. }
  49. var result int64
  50. for i, char := range str {
  51. index := strings.IndexRune(charset, char)
  52. if index == -1 || index >= int(base) {
  53. return 0, fmt.Errorf("invalid character '%c' for base %d", char, base)
  54. }
  55. // Use multiplication instead of math.Pow to avoid floating point precision issues
  56. power := len(str) - i - 1
  57. multiplier := int64(1)
  58. for j := 0; j < power; j++ {
  59. multiplier *= base
  60. }
  61. result += int64(index) * multiplier
  62. }
  63. return result, nil
  64. }
  65. // formatDateTime returns a compact string representation of the current time
  66. func formatDateTime(t time.Time) int64 {
  67. y, m, d := t.Date()
  68. h, mi, s := t.Hour(), t.Minute(), t.Second()
  69. return int64(y)*1e10 + int64(m)*1e8 + int64(d)*1e6 + int64(h)*1e4 + int64(mi)*1e2 + int64(s)
  70. }
  71. // CreateOutTradeNo generates a unique trade number
  72. func CreateOutTradeNo(playerId int64, serverId int64, zoneId int) string {
  73. n := atomic.AddUint32(&orderIncrId, 1) % maxOrderNum
  74. num := formatDateTime(time.Now())
  75. baseN, _ := ConvertToBaseN(num, defaultBase)
  76. serverIdStr, _ := ConvertToBaseN(serverId, defaultBase)
  77. playerIdStr, _ := ConvertToBaseN(playerId, defaultBase)
  78. orderStr, _ := ConvertToBaseN(int64(n), defaultBase)
  79. return fmt.Sprintf("%sZ%sZ%sZ%sZ%d",
  80. baseN, serverIdStr, playerIdStr, orderStr, zoneId)
  81. }
  82. func TestCreateOutTradeNo() {
  83. var (
  84. playerId = 1
  85. serverId = 102
  86. zoneId = 1
  87. )
  88. for i := 0; i < 10000; i += 1 {
  89. playerId += 10000000
  90. orderCode := CreateOutTradeNo(int64(playerId), int64(serverId), zoneId)
  91. fmt.Println(orderCode)
  92. }
  93. }
  94. // 随机不含重复字符的字符串
  95. // l长度 超过20需修改逻辑 命中会降低
  96. func RandString(l int) string {
  97. cl := len(charset)
  98. if l > cl || l <= 0 {
  99. return ""
  100. }
  101. bytes := make([]byte, l)
  102. selected := make(map[byte]bool)
  103. for i := 0; i < l; {
  104. b := rand.Intn(cl)
  105. char := charset[b]
  106. if !selected[char] {
  107. bytes[i] = char
  108. selected[char] = true
  109. i++
  110. }
  111. }
  112. return string(bytes)
  113. }