partly support time cell
This commit is contained in:
parent
7345247a91
commit
dff67234df
30
col.go
30
col.go
@ -41,6 +41,17 @@ type XfRk struct {
|
|||||||
Rk RK
|
Rk RK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (xf *XfRk) String(wb *WorkBook) string {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s", xf.Rk.String())
|
||||||
|
}
|
||||||
|
|
||||||
type RK uint32
|
type RK uint32
|
||||||
|
|
||||||
func (rk RK) String() string {
|
func (rk RK) String() string {
|
||||||
@ -58,6 +69,23 @@ func (rk RK) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type MulrkCol struct {
|
type MulrkCol struct {
|
||||||
Col
|
Col
|
||||||
Xfrks []XfRk
|
Xfrks []XfRk
|
||||||
@ -72,7 +100,7 @@ func (c *MulrkCol) String(wb *WorkBook) []string {
|
|||||||
var res = make([]string, len(c.Xfrks))
|
var res = make([]string, len(c.Xfrks))
|
||||||
for i := 0; i < len(c.Xfrks); i++ {
|
for i := 0; i < len(c.Xfrks); i++ {
|
||||||
xfrk := c.Xfrks[i]
|
xfrk := c.Xfrks[i]
|
||||||
res[i] = xfrk.Rk.String()
|
res[i] = xfrk.String(wb)
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
98
date.go
Normal file
98
date.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package xls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const MJD_0 float64 = 2400000.5
|
||||||
|
const MJD_JD2000 float64 = 51544.5
|
||||||
|
|
||||||
|
func shiftJulianToNoon(julianDays, julianFraction float64) (float64, float64) {
|
||||||
|
switch {
|
||||||
|
case -0.5 < julianFraction && julianFraction < 0.5:
|
||||||
|
julianFraction += 0.5
|
||||||
|
case julianFraction >= 0.5:
|
||||||
|
julianDays += 1
|
||||||
|
julianFraction -= 0.5
|
||||||
|
case julianFraction <= -0.5:
|
||||||
|
julianDays -= 1
|
||||||
|
julianFraction += 1.5
|
||||||
|
}
|
||||||
|
return julianDays, julianFraction
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the integer values for hour, minutes, seconds and
|
||||||
|
// nanoseconds that comprised a given fraction of a day.
|
||||||
|
func fractionOfADay(fraction float64) (hours, minutes, seconds, nanoseconds int) {
|
||||||
|
f := 5184000000000000 * fraction
|
||||||
|
nanoseconds = int(math.Mod(f, 1000000000))
|
||||||
|
f = f / 1000000000
|
||||||
|
seconds = int(math.Mod(f, 60))
|
||||||
|
f = f / 3600
|
||||||
|
minutes = int(math.Mod(f, 60))
|
||||||
|
f = f / 60
|
||||||
|
hours = int(f)
|
||||||
|
return hours, minutes, seconds, nanoseconds
|
||||||
|
}
|
||||||
|
|
||||||
|
func julianDateToGregorianTime(part1, part2 float64) time.Time {
|
||||||
|
part1I, part1F := math.Modf(part1)
|
||||||
|
part2I, part2F := math.Modf(part2)
|
||||||
|
julianDays := part1I + part2I
|
||||||
|
julianFraction := part1F + part2F
|
||||||
|
julianDays, julianFraction = shiftJulianToNoon(julianDays, julianFraction)
|
||||||
|
day, month, year := doTheFliegelAndVanFlandernAlgorithm(int(julianDays))
|
||||||
|
hours, minutes, seconds, nanoseconds := fractionOfADay(julianFraction)
|
||||||
|
return time.Date(year, time.Month(month), day, hours, minutes, seconds, nanoseconds, time.UTC)
|
||||||
|
}
|
||||||
|
|
||||||
|
// By this point generations of programmers have repeated the
|
||||||
|
// algorithm sent to the editor of "Communications of the ACM" in 1968
|
||||||
|
// (published in CACM, volume 11, number 10, October 1968, p.657).
|
||||||
|
// None of those programmers seems to have found it necessary to
|
||||||
|
// explain the constants or variable names set out by Henry F. Fliegel
|
||||||
|
// and Thomas C. Van Flandern. Maybe one day I'll buy that jounal and
|
||||||
|
// expand an explanation here - that day is not today.
|
||||||
|
func doTheFliegelAndVanFlandernAlgorithm(jd int) (day, month, year int) {
|
||||||
|
l := jd + 68569
|
||||||
|
n := (4 * l) / 146097
|
||||||
|
l = l - (146097*n+3)/4
|
||||||
|
i := (4000 * (l + 1)) / 1461001
|
||||||
|
l = l - (1461*i)/4 + 31
|
||||||
|
j := (80 * l) / 2447
|
||||||
|
d := l - (2447*j)/80
|
||||||
|
l = j / 11
|
||||||
|
m := j + 2 - (12 * l)
|
||||||
|
y := 100*(n-49) + i + l
|
||||||
|
return d, m, y
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert an excelTime representation (stored as a floating point number) to a time.Time.
|
||||||
|
func TimeFromExcelTime(excelTime float64, date1904 bool) time.Time {
|
||||||
|
var date time.Time
|
||||||
|
var intPart int64 = int64(excelTime)
|
||||||
|
// Excel uses Julian dates prior to March 1st 1900, and
|
||||||
|
// Gregorian thereafter.
|
||||||
|
if intPart <= 61 {
|
||||||
|
const OFFSET1900 = 15018.0
|
||||||
|
const OFFSET1904 = 16480.0
|
||||||
|
var date time.Time
|
||||||
|
if date1904 {
|
||||||
|
date = julianDateToGregorianTime(MJD_0+OFFSET1904, excelTime)
|
||||||
|
} else {
|
||||||
|
date = julianDateToGregorianTime(MJD_0+OFFSET1900, excelTime)
|
||||||
|
}
|
||||||
|
return date
|
||||||
|
}
|
||||||
|
var floatPart float64 = excelTime - float64(intPart)
|
||||||
|
var dayNanoSeconds float64 = 24 * 60 * 60 * 1000 * 1000 * 1000
|
||||||
|
if date1904 {
|
||||||
|
date = time.Date(1904, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||||
|
} else {
|
||||||
|
date = time.Date(1899, 12, 30, 0, 0, 0, 0, time.UTC)
|
||||||
|
}
|
||||||
|
durationDays := time.Duration(intPart) * time.Hour * 24
|
||||||
|
durationPart := time.Duration(dayNanoSeconds * floatPart)
|
||||||
|
return date.Add(durationDays).Add(durationPart)
|
||||||
|
}
|
@ -1,11 +1,9 @@
|
|||||||
package xls
|
package xls
|
||||||
|
|
||||||
type FormatB struct {
|
type Format struct {
|
||||||
|
Head struct {
|
||||||
Index uint16
|
Index uint16
|
||||||
Size uint16
|
Size uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
type Format struct {
|
|
||||||
b *FormatB
|
|
||||||
str string
|
str string
|
||||||
}
|
}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package xls
|
|
||||||
|
|
||||||
// type st_xf_data struct {
|
|
||||||
// Font uint16
|
|
||||||
// Format uint16
|
|
||||||
// Type uint16
|
|
||||||
// Align byte
|
|
||||||
// Rotation byte
|
|
||||||
// Ident byte
|
|
||||||
// Usedattr byte
|
|
||||||
// Linestyle uint32
|
|
||||||
// Linecolor uint32
|
|
||||||
// Groundcolor uint16
|
|
||||||
// }
|
|
||||||
|
|
||||||
type st_xf_data interface {
|
|
||||||
}
|
|
25
workbook.go
25
workbook.go
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -53,8 +54,8 @@ func (w *WorkBook) addFont(font *FontInfo, buf io.ReadSeeker) {
|
|||||||
w.Fonts = append(w.Fonts, Font{Info: font, Name: name})
|
w.Fonts = append(w.Fonts, Font{Info: font, Name: name})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorkBook) addFormat(format *FormatB, buf io.ReadSeeker) {
|
func (w *WorkBook) addFormat(format *Format) {
|
||||||
w.Formats[format.Index] = &Format{b: format, str: w.get_string(buf, uint16(format.Size))}
|
w.Formats[format.Head.Index] = format
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wb *WorkBook) parseBof(buf io.ReadSeeker, b *BOF, pre *BOF, offset_pre int) (after *BOF, offset int) {
|
func (wb *WorkBook) parseBof(buf io.ReadSeeker, b *BOF, pre *BOF, offset_pre int) (after *BOF, offset int) {
|
||||||
@ -119,21 +120,11 @@ func (wb *WorkBook) parseBof(buf io.ReadSeeker, b *BOF, pre *BOF, offset_pre int
|
|||||||
binary.Read(buf_item, binary.LittleEndian, f)
|
binary.Read(buf_item, binary.LittleEndian, f)
|
||||||
wb.addFont(f, buf_item)
|
wb.addFont(f, buf_item)
|
||||||
case 0x41E: //FORMAT
|
case 0x41E: //FORMAT
|
||||||
// var bts = make([]byte, b.Size)
|
f := new(Format)
|
||||||
// binary.Read(buf, binary.LittleEndian, bts)
|
binary.Read(buf_item, binary.LittleEndian, &f.Head)
|
||||||
// buf_item := bytes.NewReader(bts)
|
f.str = wb.get_string(buf_item, f.Head.Size)
|
||||||
f := new(FormatB)
|
wb.addFormat(f)
|
||||||
binary.Read(buf_item, binary.LittleEndian, f)
|
log.Println(f.Head.Index, f.str)
|
||||||
wb.addFormat(f, buf_item)
|
|
||||||
// case 0x5c:
|
|
||||||
// var bts = make([]byte, b.Size)
|
|
||||||
// binary.Read(buf_item, binary.LittleEndian, bts)
|
|
||||||
// if wb.Is5ver {
|
|
||||||
// wb.Author = wb.get_string_from_bytes(bts[1:], uint16(bts[1]))
|
|
||||||
// } else {
|
|
||||||
// size := binary.LittleEndian.Uint16(bts)
|
|
||||||
// wb.Author = wb.get_string_from_bytes(bts[2:], size)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
15
worksheet.go
15
worksheet.go
@ -133,21 +133,6 @@ func (w *WorkSheet) parseBof(buf io.ReadSeeker, bof *BOF, pre *BOF) *BOF {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.addRange(&hy.CellRange, &hy)
|
w.addRange(&hy.CellRange, &hy)
|
||||||
|
|
||||||
//
|
|
||||||
// bts := make([]byte, 20)
|
|
||||||
// binary.Read(buf, binary.LittleEndian, bts)
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
// if flag&0x80 != 0 {
|
|
||||||
// binary.Read(buf, binary.LittleEndian, &count)
|
|
||||||
// var bts = make([]uint16, count)
|
|
||||||
// binary.Read(buf, binary.LittleEndian, &bts)
|
|
||||||
// runes := utf16.Decode(bts)
|
|
||||||
// hy.TargetFrame = string(runes)
|
|
||||||
// }
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Unknow %X,%d\n", bof.Id, bof.Size)
|
fmt.Printf("Unknow %X,%d\n", bof.Id, bof.Size)
|
||||||
buf.Seek(int64(bof.Size), 1)
|
buf.Seek(int64(bof.Size), 1)
|
||||||
|
12
xf.go
12
xf.go
@ -11,6 +11,10 @@ type Xf5 struct {
|
|||||||
Linestyle uint16
|
Linestyle uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Xf5) formatNo() uint16 {
|
||||||
|
return x.Format
|
||||||
|
}
|
||||||
|
|
||||||
type Xf8 struct {
|
type Xf8 struct {
|
||||||
Font uint16
|
Font uint16
|
||||||
Format uint16
|
Format uint16
|
||||||
@ -23,3 +27,11 @@ type Xf8 struct {
|
|||||||
Linecolor uint32
|
Linecolor uint32
|
||||||
Groundcolor uint16
|
Groundcolor uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Xf8) formatNo() uint16 {
|
||||||
|
return x.Format
|
||||||
|
}
|
||||||
|
|
||||||
|
type st_xf_data interface {
|
||||||
|
formatNo() uint16
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user