Files

94 lines
2.0 KiB
Go

package money
import (
"errors"
"fmt"
"strconv"
"strings"
)
// CentsPerYuan 是人民币元与分的固定换算比例。
const CentsPerYuan int64 = 100
var ErrInvalidYuan = errors.New("金额格式不正确")
// ParseYuan 将用户输入的元字符串精确解析为分,不经过 float64。
// 支持 "12"、"12.3"、"12.34"、"-1.20";超过两位小数直接拒绝。
func ParseYuan(value string) (int64, error) {
trimmed := strings.TrimSpace(value)
if trimmed == "" {
return 0, ErrInvalidYuan
}
sign := int64(1)
if strings.HasPrefix(trimmed, "-") {
sign = -1
trimmed = strings.TrimPrefix(trimmed, "-")
} else if strings.HasPrefix(trimmed, "+") {
trimmed = strings.TrimPrefix(trimmed, "+")
}
if trimmed == "" {
return 0, ErrInvalidYuan
}
parts := strings.Split(trimmed, ".")
if len(parts) > 2 {
return 0, ErrInvalidYuan
}
wholeText := parts[0]
if wholeText == "" {
wholeText = "0"
}
whole, err := strconv.ParseInt(wholeText, 10, 64)
if err != nil || whole < 0 {
return 0, ErrInvalidYuan
}
fraction := int64(0)
if len(parts) == 2 {
fracText := parts[1]
if len(fracText) > 2 {
return 0, ErrInvalidYuan
}
fracText = fracText + strings.Repeat("0", 2-len(fracText))
if fracText == "" {
fracText = "00"
}
fraction, err = strconv.ParseInt(fracText, 10, 64)
if err != nil || fraction < 0 || fraction >= CentsPerYuan {
return 0, ErrInvalidYuan
}
}
if whole > (1<<62)/CentsPerYuan {
return 0, ErrInvalidYuan
}
return sign * (whole*CentsPerYuan + fraction), nil
}
// Format 将分精确格式化为两位小数,例如 1234 -> "12.34"。
// 全程使用整数运算,不经过 float64,也不做四舍五入。
func Format(cent int64) string {
sign := ""
value := cent
if value < 0 {
sign = "-"
value = -value
}
return fmt.Sprintf("%s%d.%02d", sign, value/CentsPerYuan, value%CentsPerYuan)
}
func FormatWithSymbol(cent int64) string {
return "¥" + Format(cent)
}
func MinCent(a, b int64) int64 {
if a < b {
return a
}
return b
}
func MaxCent(a, b int64) int64 {
if a > b {
return a
}
return b
}