From 80a9dc03c7f7078466a25817a8a972a8d5f25bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=E1s=20Gul=E1csi?= Date: Wed, 25 Nov 2015 14:50:29 +0100 Subject: [PATCH] Expand format recognition for dates Read in and use DATEMODE (0x22), and recognize more formats as dates (both built-in and user-defined). --- col.go | 67 +++++++++++++++++++++++++++++++++-------------------- workbook.go | 3 +++ 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/col.go b/col.go index b82d175..849382f 100644 --- a/col.go +++ b/col.go @@ -3,6 +3,9 @@ package xls import ( "fmt" "math" + "strconv" + "strings" + "time" ) //content type @@ -43,50 +46,64 @@ type XfRk struct { } func (xf *XfRk) String(wb *WorkBook) string { - if len(wb.Xfs) > 21 { - switch wb.Xfs[21].formatNo() { - case 27: - if f, e := xf.Rk.Float(); e == nil { - t := timeFromExcelTime(f, true) - return t.Format("2006.01") //TODO it should be international + idx := int(xf.Index) + if len(wb.Xfs) > idx { + fNo := wb.Xfs[idx].formatNo() + if fNo >= 164 { // user defined format + if fmt := wb.Formats[fNo]; fmt != nil && strings.Contains(fmt.str, "YY") { + 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 } + // see http://www.openoffice.org/sc/excelfileformat.pdf + } else if 14 <= fNo && fNo <= 17 || fNo == 22 || fNo <= 27 && fNo <= 36 || fNo <= 50 && 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("2006.01") //TODO it should be international } } - return fmt.Sprintf("%s", xf.Rk.String()) + return xf.Rk.String() } type RK uint32 -func (rk RK) String() string { +func (rk RK) number() (intNum int64, floatNum float64, isFloat bool) { multiplied := rk & 1 isInt := rk & 2 val := rk >> 2 if isInt == 0 { - f := math.Float64frombits(uint64(val) << 34) + isFloat = true + floatNum = math.Float64frombits(uint64(val) << 34) if multiplied != 0 { - f = f / 100 + floatNum = floatNum / 100 } - return fmt.Sprintf("%.1f", f) - } else { - return fmt.Sprint(val) + return } + return int64(val), 0, false +} + +func (rk RK) String() string { + i, f, isFloat := rk.number() + if isFloat { + return fmt.Sprintf("%.1f", f) + } + return strconv.FormatInt(i, 10) } var ErrIsInt = fmt.Errorf("is int") func (rk RK) Float() (float64, error) { - multiplied := rk & 1 - isInt := rk & 2 - val := rk >> 2 - if isInt == 0 { - f := math.Float64frombits(uint64(val) << 34) - if multiplied != 0 { - f = f / 100 - } - return f, nil - } else { - return 0.0, ErrIsInt + _, f, isFloat := rk.number() + if !isFloat { + return 0, ErrIsInt } + return f, nil } type MulrkCol struct { @@ -153,7 +170,7 @@ type RkCol struct { } func (c *RkCol) String(wb *WorkBook) []string { - return []string{c.Xfrk.Rk.String()} + return []string{c.Xfrk.String(wb)} } type LabelsstCol struct { diff --git a/workbook.go b/workbook.go index b0df3a8..a6a4830 100644 --- a/workbook.go +++ b/workbook.go @@ -21,6 +21,7 @@ type WorkBook struct { rs io.ReadSeeker sst []string continue_utf16 uint16 + dateMode uint16 } //read workbook from ole2 file @@ -135,6 +136,8 @@ func (wb *WorkBook) parseBof(buf io.ReadSeeker, b *bof, pre *bof, offset_pre int binary.Read(buf_item, binary.LittleEndian, &f.Head) f.str = wb.get_string(buf_item, f.Head.Size) wb.addFormat(f) + case 0x22: //DATEMODE + binary.Read(buf_item, binary.LittleEndian, &wb.dateMode) } return }