20
0

Expand format recognition for dates

Read in and use DATEMODE (0x22), and recognize more formats as dates (both built-in and user-defined).
This commit is contained in:
Tams Gulcsi 2015-11-25 14:50:29 +01:00
parent 6130495e06
commit 80a9dc03c7
2 changed files with 45 additions and 25 deletions

63
col.go
View File

@ -3,6 +3,9 @@ package xls
import ( import (
"fmt" "fmt"
"math" "math"
"strconv"
"strings"
"time"
) )
//content type //content type
@ -43,50 +46,64 @@ type XfRk struct {
} }
func (xf *XfRk) String(wb *WorkBook) string { func (xf *XfRk) String(wb *WorkBook) string {
if len(wb.Xfs) > 21 { idx := int(xf.Index)
switch wb.Xfs[21].formatNo() { if len(wb.Xfs) > idx {
case 27: fNo := wb.Xfs[idx].formatNo()
if f, e := xf.Rk.Float(); e == nil { if fNo >= 164 { // user defined format
t := timeFromExcelTime(f, true) 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 t.Format("2006.01") //TODO it should be international
} }
} }
} return xf.Rk.String()
return fmt.Sprintf("%s", xf.Rk.String())
} }
type RK uint32 type RK uint32
func (rk RK) String() string { func (rk RK) number() (intNum int64, floatNum float64, isFloat bool) {
multiplied := rk & 1 multiplied := rk & 1
isInt := rk & 2 isInt := rk & 2
val := rk >> 2 val := rk >> 2
if isInt == 0 { if isInt == 0 {
f := math.Float64frombits(uint64(val) << 34) isFloat = true
floatNum = math.Float64frombits(uint64(val) << 34)
if multiplied != 0 { if multiplied != 0 {
f = f / 100 floatNum = floatNum / 100
} }
return
}
return int64(val), 0, false
}
func (rk RK) String() string {
i, f, isFloat := rk.number()
if isFloat {
return fmt.Sprintf("%.1f", f) return fmt.Sprintf("%.1f", f)
} else {
return fmt.Sprint(val)
} }
return strconv.FormatInt(i, 10)
} }
var ErrIsInt = fmt.Errorf("is int") var ErrIsInt = fmt.Errorf("is int")
func (rk RK) Float() (float64, error) { func (rk RK) Float() (float64, error) {
multiplied := rk & 1 _, f, isFloat := rk.number()
isInt := rk & 2 if !isFloat {
val := rk >> 2 return 0, ErrIsInt
if isInt == 0 {
f := math.Float64frombits(uint64(val) << 34)
if multiplied != 0 {
f = f / 100
} }
return f, nil return f, nil
} else {
return 0.0, ErrIsInt
}
} }
type MulrkCol struct { type MulrkCol struct {
@ -153,7 +170,7 @@ type RkCol struct {
} }
func (c *RkCol) String(wb *WorkBook) []string { func (c *RkCol) String(wb *WorkBook) []string {
return []string{c.Xfrk.Rk.String()} return []string{c.Xfrk.String(wb)}
} }
type LabelsstCol struct { type LabelsstCol struct {

View File

@ -21,6 +21,7 @@ type WorkBook struct {
rs io.ReadSeeker rs io.ReadSeeker
sst []string sst []string
continue_utf16 uint16 continue_utf16 uint16
dateMode uint16
} }
//read workbook from ole2 file //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) binary.Read(buf_item, binary.LittleEndian, &f.Head)
f.str = wb.get_string(buf_item, f.Head.Size) f.str = wb.get_string(buf_item, f.Head.Size)
wb.addFormat(f) wb.addFormat(f)
case 0x22: //DATEMODE
binary.Read(buf_item, binary.LittleEndian, &wb.dateMode)
} }
return return
} }