extrame / xls

Pure Golang xls library
Apache License 2.0
329 stars 207 forks source link

Custom number formats are not properly implemented #74

Open ryba-xek opened 3 years ago

ryba-xek commented 3 years ago

Custom number formats are not implemented

http://www.openoffice.org/sc/excelfileformat.pdf page 174

i use github.com/IntelligenceX/fileconversion/xls which contain a number of fixes, but still formats like '0"руб."' do not work well.

Here is my patched func (xf *XfRk) String(wb *WorkBook) from col.go

func (xf *XfRk) String(wb *WorkBook) string {
    idx := int(xf.Index)
    if len(wb.Xfs) > idx {
        fNo := wb.Xfs[idx].formatNo()
        if fNo >= 164 { // user defined format
            if formatter := wb.Formats[fNo]; formatter != nil {
                formatterLower := strings.ToLower(formatter.str)
                if formatterLower == "general" ||
                    strings.Contains(formatter.str, "#") ||
                    strings.Contains(formatter.str, ".00") ||
                    strings.Contains(formatterLower, "m/y") ||
                    strings.Contains(formatterLower, "d/y") ||
                    strings.Contains(formatterLower, "m.y") ||
                    strings.Contains(formatterLower, "d.y") ||
                    strings.Contains(formatterLower, "h:") ||
                    strings.Contains(formatterLower, "д.г") {
                    //If format contains # or .00 then this is a number
                    return xf.Rk.String()
                } else {
                    // http://www.openoffice.org/sc/excelfileformat.pdf page 174
                    var res []string
                    parts := strings.Split(formatter.str, "\"")
                    var inString bool
                    for _, part := range parts {
                        if inString {
                            res = append(res, part)
                        } else {
                            switch part {
                            case "":
                                res = append(res, part)

                            case "0": // Decimal
                                i, f, isFloat := xf.Rk.number()
                                if isFloat {
                                    res = append(res, fmt.Sprintf("%.f", f)) // convert float to decimal
                                } else {
                                    res = append(res, strconv.FormatInt(i, 10))
                                }

                            default:
                                panic(fmt.Sprintf("Unknown formater: '%s'", part))
                            }
                        }
                        inString = !inString
                    }
                    return strings.Join(res, "")

                    //i, f, isFloat := xf.Rk.number()
                    //if !isFloat {
                    //  f = float64(i)
                    //}
                    //t := timeFromExcelTime(f, wb.dateMode == 1)
                    //
                    //return yymmdd.Format(t, formatter.str)
                }
            }
            // see http://www.openoffice.org/sc/excelfileformat.pdf Page #174
        } else if 14 <= fNo && fNo <= 17 || fNo == 22 || 27 <= fNo && fNo <= 36 || 50 <= fNo && fNo <= 58 { // jp. date format
            i, f, isFloat := xf.Rk.number()
            if !isFloat {
                f = float64(i)
            }
            t := timeFromExcelTime(f, wb.dateMode == 1)
            return t.Format(time.RFC3339) //TODO it should be international
        }
    }
    return xf.Rk.String()
}