summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxuri <xuri.me@gmail.com>2022-04-30 09:54:11 +0800
committerGitHub <noreply@github.com>2022-04-30 09:54:11 +0800
commit856ee57c4019b4478da0f6cb3010ae636914a6be (patch)
treea1a28fb6dec307695d4ec491929a00961c1c65ec
parent0f93bd23c97ac0f04fe8012bd4a262c851e44a82 (diff)
This closes #1212, init support for 1900 or 1904 date system
-rw-r--r--cell.go64
-rw-r--r--chart.go4
-rw-r--r--date.go4
-rw-r--r--numfmt.go8
-rw-r--r--numfmt_test.go2
-rw-r--r--picture.go4
-rw-r--r--shape.go4
-rw-r--r--styles.go16
-rw-r--r--workbook.go25
-rw-r--r--workbook_test.go12
10 files changed, 94 insertions, 49 deletions
diff --git a/cell.go b/cell.go
index 3c44af4..1d6ed84 100644
--- a/cell.go
+++ b/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
diff --git a/chart.go b/chart.go
index f740a2b..7b7162b 100644
--- a/chart.go
+++ b/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",
diff --git a/date.go b/date.go
index 83d23cc..1574af7 100644
--- a/date.go
+++ b/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
}
diff --git a/numfmt.go b/numfmt.go
index 6cb7fc7..5503027 100644
--- a/numfmt.go
+++ b/numfmt.go
@@ -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
diff --git a/numfmt_test.go b/numfmt_test.go
index 7dc3f77..5cdf56b 100644
--- a/numfmt_test.go
+++ b/numfmt_test.go
@@ -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)
}
}
diff --git a/picture.go b/picture.go
index 919262c..5e8f6b8 100644
--- a/picture.go
+++ b/picture.go
@@ -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
diff --git a/shape.go b/shape.go
index db76867..6d86f38 100644
--- a/shape.go
+++ b/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},
}
diff --git a/styles.go b/styles.go
index 11f6f75..6ef7dcb 100644
--- a/styles.go
+++ b/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
diff --git a/workbook.go b/workbook.go
index c65397b..417524b 100644
--- a/workbook.go
+++ b/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 {
@@ -132,6 +137,11 @@ func (f *File) SetWorkbookPrOptions(opts ...WorkbookPrOption) error {
}
// 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 = ""
diff --git a/workbook_test.go b/workbook_test.go
index e31caf2..18b222c 100644
--- a/workbook_test.go
+++ b/workbook_test.go
@@ -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: ""
}
@@ -43,6 +50,11 @@ 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))
assert.Equal(t, "", string(codeName))