This closes #1212, init support for 1900 or 1904 date system
This commit is contained in:
parent
0f93bd23c9
commit
856ee57c40
64
cell.go
64
cell.go
|
@ -109,8 +109,12 @@ func (f *File) GetCellType(sheet, axis string) (CellType, error) {
|
|||
// bool
|
||||
// nil
|
||||
//
|
||||
// Note that default date format is m/d/yy h:mm of time.Time type value. You can
|
||||
// set numbers format by SetCellStyle() method.
|
||||
// Note that default date format is m/d/yy h:mm of time.Time type value. You
|
||||
// can set numbers format by SetCellStyle() method. If you need to set the
|
||||
// specialized date in Excel like January 0, 1900 or February 29, 1900, these
|
||||
// times can not representation in Go language time.Time data type. Please set
|
||||
// the cell value as number 0 or 60, then create and bind the date-time number
|
||||
// format style for the cell.
|
||||
func (f *File) SetCellValue(sheet, axis string, value interface{}) error {
|
||||
var err error
|
||||
switch v := value.(type) {
|
||||
|
@ -240,7 +244,7 @@ func setCellTime(value time.Time) (t string, b string, isNum bool, err error) {
|
|||
// setCellDuration prepares cell type and value by given Go time.Duration type
|
||||
// time duration.
|
||||
func setCellDuration(value time.Duration) (t string, v string) {
|
||||
v = strconv.FormatFloat(value.Seconds()/86400.0, 'f', -1, 32)
|
||||
v = strconv.FormatFloat(value.Seconds()/86400, 'f', -1, 32)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -752,26 +756,8 @@ func (f *File) SetCellHyperLink(sheet, axis, link, linkType string, opts ...Hype
|
|||
return nil
|
||||
}
|
||||
|
||||
// GetCellRichText provides a function to get rich text of cell by given
|
||||
// worksheet.
|
||||
func (f *File) GetCellRichText(sheet, cell string) (runs []RichTextRun, err error) {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cellData, _, _, err := f.prepareCell(ws, cell)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
siIdx, err := strconv.Atoi(cellData.V)
|
||||
if err != nil || cellData.T != "s" {
|
||||
return
|
||||
}
|
||||
sst := f.sharedStringsReader()
|
||||
if len(sst.SI) <= siIdx || siIdx < 0 {
|
||||
return
|
||||
}
|
||||
si := sst.SI[siIdx]
|
||||
// getCellRichText returns rich text of cell by given string item.
|
||||
func getCellRichText(si *xlsxSI) (runs []RichTextRun) {
|
||||
for _, v := range si.R {
|
||||
run := RichTextRun{
|
||||
Text: v.T.Val,
|
||||
|
@ -803,6 +789,29 @@ func (f *File) GetCellRichText(sheet, cell string) (runs []RichTextRun, err erro
|
|||
return
|
||||
}
|
||||
|
||||
// GetCellRichText provides a function to get rich text of cell by given
|
||||
// worksheet.
|
||||
func (f *File) GetCellRichText(sheet, cell string) (runs []RichTextRun, err error) {
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cellData, _, _, err := f.prepareCell(ws, cell)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
siIdx, err := strconv.Atoi(cellData.V)
|
||||
if err != nil || cellData.T != "s" {
|
||||
return
|
||||
}
|
||||
sst := f.sharedStringsReader()
|
||||
if len(sst.SI) <= siIdx || siIdx < 0 {
|
||||
return
|
||||
}
|
||||
runs = getCellRichText(&sst.SI[siIdx])
|
||||
return
|
||||
}
|
||||
|
||||
// newRpr create run properties for the rich text by given font format.
|
||||
func newRpr(fnt *Font) *xlsxRPr {
|
||||
rpr := xlsxRPr{}
|
||||
|
@ -1099,17 +1108,20 @@ func (f *File) formattedValue(s int, v string, raw bool) string {
|
|||
if styleSheet.CellXfs.Xf[s].NumFmtID != nil {
|
||||
numFmtID = *styleSheet.CellXfs.Xf[s].NumFmtID
|
||||
}
|
||||
|
||||
date1904, wb := false, f.workbookReader()
|
||||
if wb != nil && wb.WorkbookPr != nil {
|
||||
date1904 = wb.WorkbookPr.Date1904
|
||||
}
|
||||
ok := builtInNumFmtFunc[numFmtID]
|
||||
if ok != nil {
|
||||
return ok(v, builtInNumFmt[numFmtID])
|
||||
return ok(v, builtInNumFmt[numFmtID], date1904)
|
||||
}
|
||||
if styleSheet == nil || styleSheet.NumFmts == nil {
|
||||
return v
|
||||
}
|
||||
for _, xlsxFmt := range styleSheet.NumFmts.NumFmt {
|
||||
if xlsxFmt.NumFmtID == numFmtID {
|
||||
return format(v, xlsxFmt.FormatCode)
|
||||
return format(v, xlsxFmt.FormatCode, date1904)
|
||||
}
|
||||
}
|
||||
return v
|
||||
|
|
4
chart.go
4
chart.go
|
@ -479,8 +479,8 @@ func parseFormatChartSet(formatSet string) (*formatChart, error) {
|
|||
},
|
||||
Format: formatPicture{
|
||||
FPrintsWithSheet: true,
|
||||
XScale: 1.0,
|
||||
YScale: 1.0,
|
||||
XScale: 1,
|
||||
YScale: 1,
|
||||
},
|
||||
Legend: formatChartLegend{
|
||||
Position: "bottom",
|
||||
|
|
4
date.go
4
date.go
|
@ -36,7 +36,7 @@ func timeToExcelTime(t time.Time) (float64, error) {
|
|||
// TODO in future this should probably also handle date1904 and like TimeFromExcelTime
|
||||
|
||||
if t.Before(excelMinTime1900) {
|
||||
return 0.0, nil
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
tt := t
|
||||
|
@ -58,7 +58,7 @@ func timeToExcelTime(t time.Time) (float64, error) {
|
|||
// program that had the majority market share at the time; Lotus 1-2-3.
|
||||
// https://www.myonlinetraininghub.com/excel-date-and-time
|
||||
if t.After(excelBuggyPeriodStart) {
|
||||
result += 1.0
|
||||
result++
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ type numberFormat struct {
|
|||
section []nfp.Section
|
||||
t time.Time
|
||||
sectionIdx int
|
||||
isNumeric, hours, seconds bool
|
||||
date1904, isNumeric, hours, seconds bool
|
||||
number float64
|
||||
ap, afterPoint, beforePoint, localCode, result, value, valueSectionType string
|
||||
}
|
||||
|
@ -287,9 +287,9 @@ func (nf *numberFormat) prepareNumberic(value string) {
|
|||
// format provides a function to return a string parse by number format
|
||||
// expression. If the given number format is not supported, this will return
|
||||
// the original cell value.
|
||||
func format(value, numFmt string) string {
|
||||
func format(value, numFmt string, date1904 bool) string {
|
||||
p := nfp.NumberFormatParser()
|
||||
nf := numberFormat{section: p.Parse(numFmt), value: value}
|
||||
nf := numberFormat{section: p.Parse(numFmt), value: value, date1904: date1904}
|
||||
nf.number, nf.valueSectionType = nf.getValueSectionType(value)
|
||||
nf.prepareNumberic(value)
|
||||
for i, section := range nf.section {
|
||||
|
@ -315,7 +315,7 @@ func format(value, numFmt string) string {
|
|||
// positiveHandler will be handling positive selection for a number format
|
||||
// expression.
|
||||
func (nf *numberFormat) positiveHandler() (result string) {
|
||||
nf.t, nf.hours, nf.seconds = timeFromExcelTime(nf.number, false), false, false
|
||||
nf.t, nf.hours, nf.seconds = timeFromExcelTime(nf.number, nf.date1904), false, false
|
||||
for i, token := range nf.section[nf.sectionIdx].Items {
|
||||
if inStrSlice(supportedTokenTypes, token.TType, true) == -1 || token.TType == nfp.TokenTypeGeneral {
|
||||
result = nf.value
|
||||
|
|
|
@ -1005,7 +1005,7 @@ func TestNumFmt(t *testing.T) {
|
|||
{"-8.0450685976001E-21", "0_);[Red]\\(0\\)", "(0)"},
|
||||
{"-8.04506", "0_);[Red]\\(0\\)", "(8)"},
|
||||
} {
|
||||
result := format(item[0], item[1])
|
||||
result := format(item[0], item[1], false)
|
||||
assert.Equal(t, item[2], result, item)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ import (
|
|||
func parseFormatPictureSet(formatSet string) (*formatPicture, error) {
|
||||
format := formatPicture{
|
||||
FPrintsWithSheet: true,
|
||||
XScale: 1.0,
|
||||
YScale: 1.0,
|
||||
XScale: 1,
|
||||
YScale: 1,
|
||||
}
|
||||
err := json.Unmarshal(parseFormatSet(formatSet), &format)
|
||||
return &format, err
|
||||
|
|
4
shape.go
4
shape.go
|
@ -25,8 +25,8 @@ func parseFormatShapeSet(formatSet string) (*formatShape, error) {
|
|||
Height: 160,
|
||||
Format: formatPicture{
|
||||
FPrintsWithSheet: true,
|
||||
XScale: 1.0,
|
||||
YScale: 1.0,
|
||||
XScale: 1,
|
||||
YScale: 1,
|
||||
},
|
||||
Line: formatLine{Width: 1},
|
||||
}
|
||||
|
|
16
styles.go
16
styles.go
|
@ -754,7 +754,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{
|
||||
var builtInNumFmtFunc = map[int]func(v, format string, date1904 bool) string{
|
||||
0: format,
|
||||
1: formatToInt,
|
||||
2: formatToFloat,
|
||||
|
@ -847,7 +847,7 @@ var criteriaType = map[string]string{
|
|||
// formatToInt provides a function to convert original string to integer
|
||||
// format as string type by given built-in number formats code and cell
|
||||
// string.
|
||||
func formatToInt(v string, format string) string {
|
||||
func formatToInt(v, format string, date1904 bool) string {
|
||||
f, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return v
|
||||
|
@ -858,7 +858,7 @@ func formatToInt(v string, format string) string {
|
|||
// formatToFloat provides a function to convert original string to float
|
||||
// format as string type by given built-in number formats code and cell
|
||||
// string.
|
||||
func formatToFloat(v string, format string) string {
|
||||
func formatToFloat(v, format string, date1904 bool) string {
|
||||
f, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return v
|
||||
|
@ -868,7 +868,7 @@ func formatToFloat(v string, format string) string {
|
|||
|
||||
// formatToA provides a function to convert original string to special format
|
||||
// as string type by given built-in number formats code and cell string.
|
||||
func formatToA(v string, format string) string {
|
||||
func formatToA(v, format string, date1904 bool) string {
|
||||
f, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return v
|
||||
|
@ -883,7 +883,7 @@ func formatToA(v string, format string) string {
|
|||
|
||||
// formatToB provides a function to convert original string to special format
|
||||
// as string type by given built-in number formats code and cell string.
|
||||
func formatToB(v string, format string) string {
|
||||
func formatToB(v, format string, date1904 bool) string {
|
||||
f, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return v
|
||||
|
@ -896,7 +896,7 @@ func formatToB(v string, format string) string {
|
|||
|
||||
// formatToC provides a function to convert original string to special format
|
||||
// as string type by given built-in number formats code and cell string.
|
||||
func formatToC(v string, format string) string {
|
||||
func formatToC(v, format string, date1904 bool) string {
|
||||
f, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return v
|
||||
|
@ -907,7 +907,7 @@ func formatToC(v string, format string) string {
|
|||
|
||||
// formatToD provides a function to convert original string to special format
|
||||
// as string type by given built-in number formats code and cell string.
|
||||
func formatToD(v string, format string) string {
|
||||
func formatToD(v, format string, date1904 bool) string {
|
||||
f, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return v
|
||||
|
@ -918,7 +918,7 @@ func formatToD(v string, format string) string {
|
|||
|
||||
// formatToE provides a function to convert original string to special format
|
||||
// as string type by given built-in number formats code and cell string.
|
||||
func formatToE(v string, format string) string {
|
||||
func formatToE(v, format string, date1904 bool) string {
|
||||
f, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return v
|
||||
|
|
25
workbook.go
25
workbook.go
|
@ -33,6 +33,10 @@ type WorkbookPrOptionPtr interface {
|
|||
}
|
||||
|
||||
type (
|
||||
// Date1904 is an option used for WorkbookPrOption, that indicates whether
|
||||
// to use a 1900 or 1904 date system when converting serial date-times in
|
||||
// the workbook to dates
|
||||
Date1904 bool
|
||||
// FilterPrivacy is an option used for WorkbookPrOption
|
||||
FilterPrivacy bool
|
||||
)
|
||||
|
@ -116,6 +120,7 @@ func (f *File) workBookWriter() {
|
|||
// SetWorkbookPrOptions provides a function to sets workbook properties.
|
||||
//
|
||||
// Available options:
|
||||
// Date1904(bool)
|
||||
// FilterPrivacy(bool)
|
||||
// CodeName(string)
|
||||
func (f *File) SetWorkbookPrOptions(opts ...WorkbookPrOption) error {
|
||||
|
@ -131,6 +136,11 @@ func (f *File) SetWorkbookPrOptions(opts ...WorkbookPrOption) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// setWorkbookPrOption implements the WorkbookPrOption interface.
|
||||
func (o Date1904) setWorkbookPrOption(pr *xlsxWorkbookPr) {
|
||||
pr.Date1904 = bool(o)
|
||||
}
|
||||
|
||||
// setWorkbookPrOption implements the WorkbookPrOption interface.
|
||||
func (o FilterPrivacy) setWorkbookPrOption(pr *xlsxWorkbookPr) {
|
||||
pr.FilterPrivacy = bool(o)
|
||||
|
@ -144,6 +154,7 @@ func (o CodeName) setWorkbookPrOption(pr *xlsxWorkbookPr) {
|
|||
// GetWorkbookPrOptions provides a function to gets workbook properties.
|
||||
//
|
||||
// Available options:
|
||||
// Date1904(bool)
|
||||
// FilterPrivacy(bool)
|
||||
// CodeName(string)
|
||||
func (f *File) GetWorkbookPrOptions(opts ...WorkbookPrOptionPtr) error {
|
||||
|
@ -156,7 +167,17 @@ func (f *File) GetWorkbookPrOptions(opts ...WorkbookPrOptionPtr) error {
|
|||
}
|
||||
|
||||
// getWorkbookPrOption implements the WorkbookPrOption interface and get the
|
||||
// filter privacy of thw workbook.
|
||||
// date1904 of the workbook.
|
||||
func (o *Date1904) getWorkbookPrOption(pr *xlsxWorkbookPr) {
|
||||
if pr == nil {
|
||||
*o = false
|
||||
return
|
||||
}
|
||||
*o = Date1904(pr.Date1904)
|
||||
}
|
||||
|
||||
// getWorkbookPrOption implements the WorkbookPrOption interface and get the
|
||||
// filter privacy of the workbook.
|
||||
func (o *FilterPrivacy) getWorkbookPrOption(pr *xlsxWorkbookPr) {
|
||||
if pr == nil {
|
||||
*o = false
|
||||
|
@ -166,7 +187,7 @@ func (o *FilterPrivacy) getWorkbookPrOption(pr *xlsxWorkbookPr) {
|
|||
}
|
||||
|
||||
// getWorkbookPrOption implements the WorkbookPrOption interface and get the
|
||||
// code name of thw workbook.
|
||||
// code name of the workbook.
|
||||
func (o *CodeName) getWorkbookPrOption(pr *xlsxWorkbookPr) {
|
||||
if pr == nil {
|
||||
*o = ""
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
func ExampleFile_SetWorkbookPrOptions() {
|
||||
f := NewFile()
|
||||
if err := f.SetWorkbookPrOptions(
|
||||
Date1904(false),
|
||||
FilterPrivacy(false),
|
||||
CodeName("code"),
|
||||
); err != nil {
|
||||
|
@ -21,9 +22,13 @@ func ExampleFile_SetWorkbookPrOptions() {
|
|||
func ExampleFile_GetWorkbookPrOptions() {
|
||||
f := NewFile()
|
||||
var (
|
||||
date1904 Date1904
|
||||
filterPrivacy FilterPrivacy
|
||||
codeName CodeName
|
||||
)
|
||||
if err := f.GetWorkbookPrOptions(&date1904); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
if err := f.GetWorkbookPrOptions(&filterPrivacy); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
@ -31,10 +36,12 @@ func ExampleFile_GetWorkbookPrOptions() {
|
|||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println("Defaults:")
|
||||
fmt.Printf("- date1904: %t\n", date1904)
|
||||
fmt.Printf("- filterPrivacy: %t\n", filterPrivacy)
|
||||
fmt.Printf("- codeName: %q\n", codeName)
|
||||
// Output:
|
||||
// Defaults:
|
||||
// - date1904: false
|
||||
// - filterPrivacy: true
|
||||
// - codeName: ""
|
||||
}
|
||||
|
@ -42,6 +49,11 @@ func ExampleFile_GetWorkbookPrOptions() {
|
|||
func TestWorkbookPr(t *testing.T) {
|
||||
f := NewFile()
|
||||
wb := f.workbookReader()
|
||||
wb.WorkbookPr = nil
|
||||
var date1904 Date1904
|
||||
assert.NoError(t, f.GetWorkbookPrOptions(&date1904))
|
||||
assert.Equal(t, false, bool(date1904))
|
||||
|
||||
wb.WorkbookPr = nil
|
||||
var codeName CodeName
|
||||
assert.NoError(t, f.GetWorkbookPrOptions(&codeName))
|
||||
|
|
Loading…
Reference in New Issue