summaryrefslogtreecommitdiff
path: root/styles.go
diff options
context:
space:
mode:
authorxuri <xuri.me@gmail.com>2022-02-13 00:06:30 +0800
committerxuri <xuri.me@gmail.com>2022-02-13 00:06:30 +0800
commit4b64b26c52932a51ca97a2bb6bf372a07020e52b (patch)
tree0d5b88ab9db7b459de73e65b022871ef69fe2cd6 /styles.go
parent3f8f4f52e68d408da5a2e5108af3cc99bf8586bc (diff)
Ref: #660, #764, #1093, #1112, #1133 This improve number format support
- Introduced NFP (number format parser) dependencies module - Initialize custom dates and times number format support - Dependencies module upgraded
Diffstat (limited to 'styles.go')
-rw-r--r--styles.go185
1 files changed, 20 insertions, 165 deletions
diff --git a/styles.go b/styles.go
index 7678b84..6dea20e 100644
--- a/styles.go
+++ b/styles.go
@@ -20,7 +20,6 @@ import (
"log"
"math"
"reflect"
- "regexp"
"strconv"
"strings"
)
@@ -756,7 +755,7 @@ var currencyNumFmt = map[int]string{
// builtInNumFmtFunc defined the format conversion functions map. Partial format
// code doesn't support currently and will return original string.
var builtInNumFmtFunc = map[int]func(v string, format string) string{
- 0: formatToString,
+ 0: format,
1: formatToInt,
2: formatToFloat,
3: formatToInt,
@@ -764,30 +763,30 @@ var builtInNumFmtFunc = map[int]func(v string, format string) string{
9: formatToC,
10: formatToD,
11: formatToE,
- 12: formatToString, // Doesn't support currently
- 13: formatToString, // Doesn't support currently
- 14: parseTime,
- 15: parseTime,
- 16: parseTime,
- 17: parseTime,
- 18: parseTime,
- 19: parseTime,
- 20: parseTime,
- 21: parseTime,
- 22: parseTime,
+ 12: format, // Doesn't support currently
+ 13: format, // Doesn't support currently
+ 14: format,
+ 15: format,
+ 16: format,
+ 17: format,
+ 18: format,
+ 19: format,
+ 20: format,
+ 21: format,
+ 22: format,
37: formatToA,
38: formatToA,
39: formatToB,
40: formatToB,
- 41: formatToString, // Doesn't support currently
- 42: formatToString, // Doesn't support currently
- 43: formatToString, // Doesn't support currently
- 44: formatToString, // Doesn't support currently
- 45: parseTime,
- 46: parseTime,
- 47: parseTime,
+ 41: format, // Doesn't support currently
+ 42: format, // Doesn't support currently
+ 43: format, // Doesn't support currently
+ 44: format, // Doesn't support currently
+ 45: format,
+ 46: format,
+ 47: format,
48: formatToE,
- 49: formatToString,
+ 49: format,
}
// validType defined the list of valid validation types.
@@ -845,12 +844,6 @@ var criteriaType = map[string]string{
"continue month": "continueMonth",
}
-// formatToString provides a function to return original string by given
-// built-in number formats code and cell string.
-func formatToString(v string, format string) string {
- return v
-}
-
// formatToInt provides a function to convert original string to integer
// format as string type by given built-in number formats code and cell
// string.
@@ -933,144 +926,6 @@ func formatToE(v string, format string) string {
return fmt.Sprintf("%.2E", f)
}
-// parseTime provides a function to returns a string parsed using time.Time.
-// Replace Excel placeholders with Go time placeholders. For example, replace
-// yyyy with 2006. These are in a specific order, due to the fact that m is
-// used in month, minute, and am/pm. It would be easier to fix that with
-// regular expressions, but if it's possible to keep this simple it would be
-// easier to maintain. Full-length month and days (e.g. March, Tuesday) have
-// letters in them that would be replaced by other characters below (such as
-// the 'h' in March, or the 'd' in Tuesday) below. First we convert them to
-// arbitrary characters unused in Excel Date formats, and then at the end,
-// turn them to what they should actually be. Based off:
-// http://www.ozgrid.com/Excel/CustomFormats.htm
-func parseTime(v string, format string) string {
- var (
- f float64
- err error
- goFmt string
- )
- f, err = strconv.ParseFloat(v, 64)
- if err != nil {
- return v
- }
- val := timeFromExcelTime(f, false)
-
- if format == "" {
- return v
- }
-
- goFmt = format
-
- if strings.Contains(goFmt, "[") {
- re := regexp.MustCompile(`\[.+\]`)
- goFmt = re.ReplaceAllLiteralString(goFmt, "")
- }
-
- // use only first variant
- if strings.Contains(goFmt, ";") {
- goFmt = goFmt[:strings.IndexByte(goFmt, ';')]
- }
-
- replacements := []struct{ xltime, gotime string }{
- {"YYYY", "2006"},
- {"YY", "06"},
- {"MM", "01"},
- {"M", "1"},
- {"DD", "02"},
- {"D", "2"},
- {"yyyy", "2006"},
- {"yy", "06"},
- {"MMMM", "%%%%"},
- {"mmmm", "%%%%"},
- {"DDDD", "&&&&"},
- {"dddd", "&&&&"},
- {"DD", "02"},
- {"dd", "02"},
- {"D", "2"},
- {"d", "2"},
- {"MMM", "Jan"},
- {"mmm", "Jan"},
- {"MMSS", "0405"},
- {"mmss", "0405"},
- {"SS", "05"},
- {"ss", "05"},
- {"s", "5"},
- {"MM:", "04:"},
- {"mm:", "04:"},
- {":MM", ":04"},
- {":mm", ":04"},
- {"m:", "4:"},
- {":m", ":4"},
- {"MM", "01"},
- {"mm", "01"},
- {"AM/PM", "PM"},
- {"am/pm", "PM"},
- {"M/", "1/"},
- {"m/", "1/"},
- {"%%%%", "January"},
- {"&&&&", "Monday"},
- }
-
- replacementsGlobal := []struct{ xltime, gotime string }{
- {"\\-", "-"},
- {"\\ ", " "},
- {"\\.", "."},
- {"\\", ""},
- {"\"", ""},
- }
- // It is the presence of the "am/pm" indicator that determines if this is
- // a 12 hour or 24 hours time format, not the number of 'h' characters.
- var padding bool
- if val.Hour() == 0 && !strings.Contains(format, "hh") && !strings.Contains(format, "HH") {
- padding = true
- }
- if is12HourTime(format) {
- goFmt = strings.Replace(goFmt, "hh", "3", 1)
- goFmt = strings.Replace(goFmt, "h", "3", 1)
- goFmt = strings.Replace(goFmt, "HH", "3", 1)
- goFmt = strings.Replace(goFmt, "H", "3", 1)
- } else {
- goFmt = strings.Replace(goFmt, "hh", "15", 1)
- goFmt = strings.Replace(goFmt, "HH", "15", 1)
- if 0 < val.Hour() && val.Hour() < 12 {
- goFmt = strings.Replace(goFmt, "h", "3", 1)
- goFmt = strings.Replace(goFmt, "H", "3", 1)
- } else {
- goFmt = strings.Replace(goFmt, "h", "15", 1)
- goFmt = strings.Replace(goFmt, "H", "15", 1)
- }
- }
-
- for _, repl := range replacements {
- goFmt = strings.Replace(goFmt, repl.xltime, repl.gotime, 1)
- }
- for _, repl := range replacementsGlobal {
- goFmt = strings.Replace(goFmt, repl.xltime, repl.gotime, -1)
- }
- // If the hour is optional, strip it out, along with the possible dangling
- // colon that would remain.
- if val.Hour() < 1 {
- goFmt = strings.Replace(goFmt, "]:", "]", 1)
- goFmt = strings.Replace(goFmt, "[03]", "", 1)
- goFmt = strings.Replace(goFmt, "[3]", "", 1)
- goFmt = strings.Replace(goFmt, "[15]", "", 1)
- } else {
- goFmt = strings.Replace(goFmt, "[3]", "3", 1)
- goFmt = strings.Replace(goFmt, "[15]", "15", 1)
- }
- s := val.Format(goFmt)
- if padding {
- s = strings.Replace(s, "00:", "0:", 1)
- }
- return s
-}
-
-// is12HourTime checks whether an Excel time format string is a 12 hours form.
-func is12HourTime(format string) bool {
- return strings.Contains(format, "am/pm") || strings.Contains(format, "AM/PM") || strings.Contains(format, "a/p") || strings.Contains(format, "A/P")
-}
-
// stylesReader provides a function to get the pointer to the structure after
// deserialization of xl/styles.xml.
func (f *File) stylesReader() *xlsxStyleSheet {