summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--cell.go18
-rw-r--r--cell_test.go36
-rw-r--r--crypt_test.go2
-rw-r--r--excelize.go2
-rw-r--r--excelize_test.go5
-rw-r--r--file.go2
-rw-r--r--rows.go19
-rw-r--r--rows_test.go37
-rw-r--r--sheet_test.go86
-rw-r--r--sheetpr_test.go250
-rw-r--r--sheetview_test.go92
-rw-r--r--styles.go104
-rw-r--r--styles_test.go46
14 files changed, 452 insertions, 248 deletions
diff --git a/.gitignore b/.gitignore
index a3fcff2..685d2bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
~$*.xlsx
test/Test*.xlsx
+test/Test*.xlsm
*.out
*.test
.idea
diff --git a/cell.go b/cell.go
index 5fe2157..11c6836 100644
--- a/cell.go
+++ b/cell.go
@@ -762,9 +762,23 @@ func (f *File) formattedValue(s int, v string) string {
return v
}
styleSheet := f.stylesReader()
- ok := builtInNumFmtFunc[*styleSheet.CellXfs.Xf[s].NumFmtID]
+ if s >= len(styleSheet.CellXfs.Xf) {
+ return v
+ }
+ numFmtId := *styleSheet.CellXfs.Xf[s].NumFmtID
+ ok := builtInNumFmtFunc[numFmtId]
if ok != nil {
- return ok(*styleSheet.CellXfs.Xf[s].NumFmtID, v)
+ return ok(v, builtInNumFmt[numFmtId])
+ }
+ for _, xlsxFmt := range styleSheet.NumFmts.NumFmt {
+ if xlsxFmt.NumFmtID == numFmtId {
+ format := strings.ToLower(xlsxFmt.FormatCode)
+ if strings.Contains(format, "y") || strings.Contains(format, "m") || strings.Contains(format, "d") || strings.Contains(format, "h") {
+ return parseTime(v, format)
+ }
+
+ return v
+ }
}
return v
}
diff --git a/cell_test.go b/cell_test.go
index 441a694..a855344 100644
--- a/cell_test.go
+++ b/cell_test.go
@@ -111,6 +111,23 @@ func TestSetCellValue(t *testing.T) {
assert.EqualError(t, f.SetCellValue("Sheet1", "A", time.Duration(1e13)), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
}
+func TestSetCellValues(t *testing.T) {
+ f := NewFile()
+ err := f.SetCellValue("Sheet1", "A1", time.Date(2010, time.December, 31, 0, 0, 0, 0, time.UTC))
+ assert.NoError(t, err)
+
+ v, err := f.GetCellValue("Sheet1", "A1")
+ assert.NoError(t, err)
+ assert.Equal(t, v, "12/31/10 12:00")
+
+ // test date value lower than min date supported by Excel
+ err = f.SetCellValue("Sheet1", "A1", time.Date(1600, time.December, 31, 0, 0, 0, 0, time.UTC))
+ assert.NoError(t, err)
+
+ _, err = f.GetCellValue("Sheet1", "A1")
+ assert.EqualError(t, err, `strconv.ParseFloat: parsing "1600-12-31T00:00:00Z": invalid syntax`)
+}
+
func TestSetCellBool(t *testing.T) {
f := NewFile()
assert.EqualError(t, f.SetCellBool("Sheet1", "A", true), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
@@ -264,3 +281,22 @@ func TestSetCellRichText(t *testing.T) {
// Test set cell rich text with illegal cell coordinates
assert.EqualError(t, f.SetCellRichText("Sheet1", "A", richTextRun), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
}
+
+func TestFormattedValue(t *testing.T) {
+ f := NewFile()
+ v := f.formattedValue(0, "43528")
+ assert.Equal(t, "43528", v)
+
+ v = f.formattedValue(15, "43528")
+ assert.Equal(t, "43528", v)
+
+ v = f.formattedValue(1, "43528")
+ assert.Equal(t, "43528", v)
+ customNumFmt := "[$-409]MM/DD/YYYY"
+ _, err := f.NewStyle(&Style{
+ CustomNumFmt: &customNumFmt,
+ })
+ assert.NoError(t, err)
+ v = f.formattedValue(1, "43528")
+ assert.Equal(t, "03/04/2019", v)
+}
diff --git a/crypt_test.go b/crypt_test.go
index c6acb38..f9a3fb7 100644
--- a/crypt_test.go
+++ b/crypt_test.go
@@ -19,5 +19,5 @@ import (
func TestEncrypt(t *testing.T) {
f, err := OpenFile(filepath.Join("test", "encryptSHA1.xlsx"), Options{Password: "password"})
assert.NoError(t, err)
- assert.EqualError(t, f.SaveAs(filepath.Join("test", "TestEncrypt.xlsx"), Options{Password: "password"}), "not support encryption currently")
+ assert.EqualError(t, f.SaveAs(filepath.Join("test", "BadEncrypt.xlsx"), Options{Password: "password"}), "not support encryption currently")
}
diff --git a/excelize.go b/excelize.go
index a90b765..cca6616 100644
--- a/excelize.go
+++ b/excelize.go
@@ -158,7 +158,7 @@ func (f *File) setDefaultTimeStyle(sheet, axis string, format int) error {
}
if s == 0 {
style, _ := f.NewStyle(&Style{NumFmt: format})
- _ = f.SetCellStyle(sheet, axis, axis, style)
+ err = f.SetCellStyle(sheet, axis, axis, style)
}
return err
}
diff --git a/excelize_test.go b/excelize_test.go
index f1cd652..890bcf6 100644
--- a/excelize_test.go
+++ b/excelize_test.go
@@ -257,7 +257,7 @@ func TestBrokenFile(t *testing.T) {
t.Run("SaveAsEmptyStruct", func(t *testing.T) {
// Test write file with broken file struct with given path.
- assert.NoError(t, f.SaveAs(filepath.Join("test", "BrokenFile.SaveAsEmptyStruct.xlsx")))
+ assert.NoError(t, f.SaveAs(filepath.Join("test", "BadWorkbook.SaveAsEmptyStruct.xlsx")))
})
t.Run("OpenBadWorkbook", func(t *testing.T) {
@@ -1175,6 +1175,9 @@ func TestSetDefaultTimeStyle(t *testing.T) {
f := NewFile()
// Test set default time style on not exists worksheet.
assert.EqualError(t, f.setDefaultTimeStyle("SheetN", "", 0), "sheet SheetN is not exist")
+
+ // Test set default time style on invalid cell
+ assert.EqualError(t, f.setDefaultTimeStyle("Sheet1", "", 42), "cannot convert cell \"\" to coordinates: invalid cell name \"\"")
}
func TestAddVBAProject(t *testing.T) {
diff --git a/file.go b/file.go
index 83ed271..6a48c0c 100644
--- a/file.go
+++ b/file.go
@@ -123,7 +123,7 @@ func (f *File) WriteToBuffer() (*bytes.Buffer, error) {
}
}
- if f.options != nil {
+ if f.options != nil && f.options.Password != "" {
if err := zw.Close(); err != nil {
return buf, err
}
diff --git a/rows.go b/rows.go
index eb4b1df..50e7308 100644
--- a/rows.go
+++ b/rows.go
@@ -345,6 +345,25 @@ func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
}
return f.formattedValue(xlsx.S, xlsx.V), nil
default:
+ // correct numeric values as legacy Excel app
+ // https://en.wikipedia.org/wiki/Numeric_precision_in_Microsoft_Excel
+ // In the top figure the fraction 1/9000 in Excel is displayed.
+ // Although this number has a decimal representation that is an infinite string of ones,
+ // Excel displays only the leading 15 figures. In the second line, the number one is added to the fraction, and again Excel displays only 15 figures.
+ const precision = 1000000000000000
+ if len(xlsx.V) > 16 {
+ num, err := strconv.ParseFloat(xlsx.V, 64)
+ if err != nil {
+ return "", err
+ }
+
+ num = math.Round(num*precision) / precision
+ val := fmt.Sprintf("%g", num)
+ if val != xlsx.V {
+ return f.formattedValue(xlsx.S, val), nil
+ }
+ }
+
return f.formattedValue(xlsx.S, xlsx.V), nil
}
}
diff --git a/rows_test.go b/rows_test.go
index c469c01..246233f 100644
--- a/rows_test.go
+++ b/rows_test.go
@@ -817,7 +817,7 @@ func TestDuplicateMergeCells(t *testing.T) {
assert.EqualError(t, f.duplicateMergeCells("SheetN", xlsx, 1, 2), "sheet SheetN is not exist")
}
-func TestGetValueFrom(t *testing.T) {
+func TestGetValueFromInlineStr(t *testing.T) {
c := &xlsxC{T: "inlineStr"}
f := NewFile()
d := &xlsxSST{}
@@ -826,6 +826,20 @@ func TestGetValueFrom(t *testing.T) {
assert.Equal(t, "", val)
}
+func TestGetValueFromNumber(t *testing.T) {
+ c := &xlsxC{T: "n", V: "2.2200000000000002"}
+ f := NewFile()
+ d := &xlsxSST{}
+ val, err := c.getValueFrom(f, d)
+ assert.NoError(t, err)
+ assert.Equal(t, "2.22", val)
+
+ c = &xlsxC{T: "n", V: "2.220000ddsf0000000002-r"}
+ val, err = c.getValueFrom(f, d)
+ assert.NotNil(t, err)
+ assert.Equal(t, "strconv.ParseFloat: parsing \"2.220000ddsf0000000002-r\": invalid syntax", err.Error())
+}
+
func TestErrSheetNotExistError(t *testing.T) {
err := ErrSheetNotExist{SheetName: "Sheet1"}
assert.EqualValues(t, err.Error(), "sheet Sheet1 is not exist")
@@ -842,6 +856,27 @@ func TestCheckRow(t *testing.T) {
assert.EqualError(t, f.SetCellValue("Sheet1", "A1", false), `cannot convert cell "-" to coordinates: invalid cell name "-"`)
}
+func TestNumberFormats(t *testing.T) {
+ f, err := OpenFile(filepath.Join("test", "Book1.xlsx"))
+ if !assert.NoError(t, err) {
+ t.FailNow()
+ }
+ cells := make([][]string, 0)
+ cols, err := f.Cols("Sheet2")
+ if !assert.NoError(t, err) {
+ t.FailNow()
+ }
+ for cols.Next() {
+ col, err := cols.Rows()
+ assert.NoError(t, err)
+ if err != nil {
+ break
+ }
+ cells = append(cells, col)
+ }
+ assert.Equal(t, []string{"", "200", "450", "200", "510", "315", "127", "89", "348", "53", "37"}, cells[3])
+}
+
func BenchmarkRows(b *testing.B) {
f, _ := OpenFile(filepath.Join("test", "Book1.xlsx"))
for i := 0; i < b.N; i++ {
diff --git a/sheet_test.go b/sheet_test.go
index 0014220..890a4e5 100644
--- a/sheet_test.go
+++ b/sheet_test.go
@@ -1,4 +1,4 @@
-package excelize_test
+package excelize
import (
"fmt"
@@ -6,26 +6,24 @@ import (
"strings"
"testing"
- "github.com/360EntSecGroup-Skylar/excelize/v2"
-
"github.com/mohae/deepcopy"
"github.com/stretchr/testify/assert"
)
func ExampleFile_SetPageLayout() {
- f := excelize.NewFile()
+ f := NewFile()
if err := f.SetPageLayout(
"Sheet1",
- excelize.PageLayoutOrientation(excelize.OrientationLandscape),
+ PageLayoutOrientation(OrientationLandscape),
); err != nil {
fmt.Println(err)
}
if err := f.SetPageLayout(
"Sheet1",
- excelize.PageLayoutPaperSize(10),
- excelize.FitToHeight(2),
- excelize.FitToWidth(2),
+ PageLayoutPaperSize(10),
+ FitToHeight(2),
+ FitToWidth(2),
); err != nil {
fmt.Println(err)
}
@@ -33,12 +31,12 @@ func ExampleFile_SetPageLayout() {
}
func ExampleFile_GetPageLayout() {
- f := excelize.NewFile()
+ f := NewFile()
var (
- orientation excelize.PageLayoutOrientation
- paperSize excelize.PageLayoutPaperSize
- fitToHeight excelize.FitToHeight
- fitToWidth excelize.FitToWidth
+ orientation PageLayoutOrientation
+ paperSize PageLayoutPaperSize
+ fitToHeight FitToHeight
+ fitToWidth FitToWidth
)
if err := f.GetPageLayout("Sheet1", &orientation); err != nil {
fmt.Println(err)
@@ -67,7 +65,7 @@ func ExampleFile_GetPageLayout() {
}
func TestNewSheet(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
sheetID := f.NewSheet("Sheet2")
f.SetActiveSheet(sheetID)
// delete original sheet
@@ -76,7 +74,7 @@ func TestNewSheet(t *testing.T) {
}
func TestSetPane(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
assert.NoError(t, f.SetPanes("Sheet1", `{"freeze":false,"split":false}`))
f.NewSheet("Panes 2")
assert.NoError(t, f.SetPanes("Panes 2", `{"freeze":true,"split":false,"x_split":1,"y_split":0,"top_left_cell":"B1","active_pane":"topRight","panes":[{"sqref":"K16","active_cell":"K16","pane":"topRight"}]}`))
@@ -93,13 +91,13 @@ func TestPageLayoutOption(t *testing.T) {
const sheet = "Sheet1"
testData := []struct {
- container excelize.PageLayoutOptionPtr
- nonDefault excelize.PageLayoutOption
+ container PageLayoutOptionPtr
+ nonDefault PageLayoutOption
}{
- {new(excelize.PageLayoutOrientation), excelize.PageLayoutOrientation(excelize.OrientationLandscape)},
- {new(excelize.PageLayoutPaperSize), excelize.PageLayoutPaperSize(10)},
- {new(excelize.FitToHeight), excelize.FitToHeight(2)},
- {new(excelize.FitToWidth), excelize.FitToWidth(2)},
+ {new(PageLayoutOrientation), PageLayoutOrientation(OrientationLandscape)},
+ {new(PageLayoutPaperSize), PageLayoutPaperSize(10)},
+ {new(FitToHeight), FitToHeight(2)},
+ {new(FitToWidth), FitToWidth(2)},
}
for i, test := range testData {
@@ -108,11 +106,11 @@ func TestPageLayoutOption(t *testing.T) {
opt := test.nonDefault
t.Logf("option %T", opt)
- def := deepcopy.Copy(test.container).(excelize.PageLayoutOptionPtr)
- val1 := deepcopy.Copy(def).(excelize.PageLayoutOptionPtr)
- val2 := deepcopy.Copy(def).(excelize.PageLayoutOptionPtr)
+ def := deepcopy.Copy(test.container).(PageLayoutOptionPtr)
+ val1 := deepcopy.Copy(def).(PageLayoutOptionPtr)
+ val2 := deepcopy.Copy(def).(PageLayoutOptionPtr)
- f := excelize.NewFile()
+ f := NewFile()
// Get the default value
assert.NoError(t, f.GetPageLayout(sheet, def), opt)
// Get again and check
@@ -150,7 +148,7 @@ func TestPageLayoutOption(t *testing.T) {
}
func TestSearchSheet(t *testing.T) {
- f, err := excelize.OpenFile(filepath.Join("test", "SharedStrings.xlsx"))
+ f, err := OpenFile(filepath.Join("test", "SharedStrings.xlsx"))
if !assert.NoError(t, err) {
t.FailNow()
}
@@ -172,36 +170,36 @@ func TestSearchSheet(t *testing.T) {
assert.EqualValues(t, expected, result)
// Test search worksheet data after set cell value
- f = excelize.NewFile()
+ f = NewFile()
assert.NoError(t, f.SetCellValue("Sheet1", "A1", true))
_, err = f.SearchSheet("Sheet1", "")
assert.NoError(t, err)
}
func TestSetPageLayout(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
// Test set page layout on not exists worksheet.
assert.EqualError(t, f.SetPageLayout("SheetN"), "sheet SheetN is not exist")
}
func TestGetPageLayout(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
// Test get page layout on not exists worksheet.
assert.EqualError(t, f.GetPageLayout("SheetN"), "sheet SheetN is not exist")
}
func TestSetHeaderFooter(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
assert.NoError(t, f.SetCellStr("Sheet1", "A1", "Test SetHeaderFooter"))
// Test set header and footer on not exists worksheet.
assert.EqualError(t, f.SetHeaderFooter("SheetN", nil), "sheet SheetN is not exist")
// Test set header and footer with illegal setting.
- assert.EqualError(t, f.SetHeaderFooter("Sheet1", &excelize.FormatHeaderFooter{
+ assert.EqualError(t, f.SetHeaderFooter("Sheet1", &FormatHeaderFooter{
OddHeader: strings.Repeat("c", 256),
}), "field OddHeader must be less than 255 characters")
assert.NoError(t, f.SetHeaderFooter("Sheet1", nil))
- assert.NoError(t, f.SetHeaderFooter("Sheet1", &excelize.FormatHeaderFooter{
+ assert.NoError(t, f.SetHeaderFooter("Sheet1", &FormatHeaderFooter{
DifferentFirst: true,
DifferentOddEven: true,
OddHeader: "&R&P",
@@ -214,28 +212,28 @@ func TestSetHeaderFooter(t *testing.T) {
}
func TestDefinedName(t *testing.T) {
- f := excelize.NewFile()
- assert.NoError(t, f.SetDefinedName(&excelize.DefinedName{
+ f := NewFile()
+ assert.NoError(t, f.SetDefinedName(&DefinedName{
Name: "Amount",
RefersTo: "Sheet1!$A$2:$D$5",
Comment: "defined name comment",
Scope: "Sheet1",
}))
- assert.NoError(t, f.SetDefinedName(&excelize.DefinedName{
+ assert.NoError(t, f.SetDefinedName(&DefinedName{
Name: "Amount",
RefersTo: "Sheet1!$A$2:$D$5",
Comment: "defined name comment",
}))
- assert.EqualError(t, f.SetDefinedName(&excelize.DefinedName{
+ assert.EqualError(t, f.SetDefinedName(&DefinedName{
Name: "Amount",
RefersTo: "Sheet1!$A$2:$D$5",
Comment: "defined name comment",
}), "the same name already exists on the scope")
- assert.EqualError(t, f.DeleteDefinedName(&excelize.DefinedName{
+ assert.EqualError(t, f.DeleteDefinedName(&DefinedName{
Name: "No Exist Defined Name",
}), "no defined name on the scope")
assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[1].RefersTo)
- assert.NoError(t, f.DeleteDefinedName(&excelize.DefinedName{
+ assert.NoError(t, f.DeleteDefinedName(&DefinedName{
Name: "Amount",
}))
assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[0].RefersTo)
@@ -244,7 +242,7 @@ func TestDefinedName(t *testing.T) {
}
func TestGroupSheets(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
sheets := []string{"Sheet2", "Sheet3"}
for _, sheet := range sheets {
f.NewSheet(sheet)
@@ -256,7 +254,7 @@ func TestGroupSheets(t *testing.T) {
}
func TestUngroupSheets(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
sheets := []string{"Sheet2", "Sheet3", "Sheet4", "Sheet5"}
for _, sheet := range sheets {
f.NewSheet(sheet)
@@ -265,7 +263,7 @@ func TestUngroupSheets(t *testing.T) {
}
func TestInsertPageBreak(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
assert.NoError(t, f.InsertPageBreak("Sheet1", "A1"))
assert.NoError(t, f.InsertPageBreak("Sheet1", "B2"))
assert.NoError(t, f.InsertPageBreak("Sheet1", "C3"))
@@ -276,7 +274,7 @@ func TestInsertPageBreak(t *testing.T) {
}
func TestRemovePageBreak(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
assert.NoError(t, f.RemovePageBreak("Sheet1", "A2"))
assert.NoError(t, f.InsertPageBreak("Sheet1", "A2"))
@@ -302,7 +300,7 @@ func TestRemovePageBreak(t *testing.T) {
}
func TestGetSheetName(t *testing.T) {
- f, _ := excelize.OpenFile(filepath.Join("test", "Book1.xlsx"))
+ f, _ := OpenFile(filepath.Join("test", "Book1.xlsx"))
assert.Equal(t, "Sheet1", f.GetSheetName(0))
assert.Equal(t, "Sheet2", f.GetSheetName(1))
assert.Equal(t, "", f.GetSheetName(-1))
@@ -314,7 +312,7 @@ func TestGetSheetMap(t *testing.T) {
1: "Sheet1",
2: "Sheet2",
}
- f, _ := excelize.OpenFile(filepath.Join("test", "Book1.xlsx"))
+ f, _ := OpenFile(filepath.Join("test", "Book1.xlsx"))
sheetMap := f.GetSheetMap()
for idx, name := range sheetMap {
assert.Equal(t, expectedMap[idx], name)
diff --git a/sheetpr_test.go b/sheetpr_test.go
index 6e03151..29bd99e 100644
--- a/sheetpr_test.go
+++ b/sheetpr_test.go
@@ -1,4 +1,4 @@
-package excelize_test
+package excelize
import (
"fmt"
@@ -6,39 +6,37 @@ import (
"github.com/mohae/deepcopy"
"github.com/stretchr/testify/assert"
-
- "github.com/360EntSecGroup-Skylar/excelize/v2"
)
-var _ = []excelize.SheetPrOption{
- excelize.CodeName("hello"),
- excelize.EnableFormatConditionsCalculation(false),
- excelize.Published(false),
- excelize.FitToPage(true),
- excelize.AutoPageBreaks(true),
- excelize.OutlineSummaryBelow(true),
+var _ = []SheetPrOption{
+ CodeName("hello"),
+ EnableFormatConditionsCalculation(false),
+ Published(false),
+ FitToPage(true),
+ AutoPageBreaks(true),
+ OutlineSummaryBelow(true),
}
-var _ = []excelize.SheetPrOptionPtr{
- (*excelize.CodeName)(nil),
- (*excelize.EnableFormatConditionsCalculation)(nil),
- (*excelize.Published)(nil),
- (*excelize.FitToPage)(nil),
- (*excelize.AutoPageBreaks)(nil),
- (*excelize.OutlineSummaryBelow)(nil),
+var _ = []SheetPrOptionPtr{
+ (*CodeName)(nil),
+ (*EnableFormatConditionsCalculation)(nil),
+ (*Published)(nil),
+ (*FitToPage)(nil),
+ (*AutoPageBreaks)(nil),
+ (*OutlineSummaryBelow)(nil),
}
func ExampleFile_SetSheetPrOptions() {
- f := excelize.NewFile()
+ f := NewFile()
const sheet = "Sheet1"
if err := f.SetSheetPrOptions(sheet,
- excelize.CodeName("code"),
- excelize.EnableFormatConditionsCalculation(false),
- excelize.Published(false),
- excelize.FitToPage(true),
- excelize.AutoPageBreaks(true),
- excelize.OutlineSummaryBelow(false),
+ CodeName("code"),
+ EnableFormatConditionsCalculation(false),
+ Published(false),
+ FitToPage(true),
+ AutoPageBreaks(true),
+ OutlineSummaryBelow(false),
); err != nil {
fmt.Println(err)
}
@@ -46,16 +44,16 @@ func ExampleFile_SetSheetPrOptions() {
}
func ExampleFile_GetSheetPrOptions() {
- f := excelize.NewFile()
+ f := NewFile()
const sheet = "Sheet1"
var (
- codeName excelize.CodeName
- enableFormatConditionsCalculation excelize.EnableFormatConditionsCalculation
- published excelize.Published
- fitToPage excelize.FitToPage
- autoPageBreaks excelize.AutoPageBreaks
- outlineSummaryBelow excelize.OutlineSummaryBelow
+ codeName CodeName
+ enableFormatConditionsCalculation EnableFormatConditionsCalculation
+ published Published
+ fitToPage FitToPage
+ autoPageBreaks AutoPageBreaks
+ outlineSummaryBelow OutlineSummaryBelow
)
if err := f.GetSheetPrOptions(sheet,
@@ -89,15 +87,15 @@ func TestSheetPrOptions(t *testing.T) {
const sheet = "Sheet1"
testData := []struct {
- container excelize.SheetPrOptionPtr
- nonDefault excelize.SheetPrOption
+ container SheetPrOptionPtr
+ nonDefault SheetPrOption
}{
- {new(excelize.CodeName), excelize.CodeName("xx")},
- {new(excelize.EnableFormatConditionsCalculation), excelize.EnableFormatConditionsCalculation(false)},
- {new(excelize.Published), excelize.Published(false)},
- {new(excelize.FitToPage), excelize.FitToPage(true)},
- {new(excelize.AutoPageBreaks), excelize.AutoPageBreaks(true)},
- {new(excelize.OutlineSummaryBelow), excelize.OutlineSummaryBelow(false)},
+ {new(CodeName), CodeName("xx")},
+ {new(EnableFormatConditionsCalculation), EnableFormatConditionsCalculation(false)},
+ {new(Published), Published(false)},
+ {new(FitToPage), FitToPage(true)},
+ {new(AutoPageBreaks), AutoPageBreaks(true)},
+ {new(OutlineSummaryBelow), OutlineSummaryBelow(false)},
}
for i, test := range testData {
@@ -106,11 +104,11 @@ func TestSheetPrOptions(t *testing.T) {
opt := test.nonDefault
t.Logf("option %T", opt)
- def := deepcopy.Copy(test.container).(excelize.SheetPrOptionPtr)
- val1 := deepcopy.Copy(def).(excelize.SheetPrOptionPtr)
- val2 := deepcopy.Copy(def).(excelize.SheetPrOptionPtr)
+ def := deepcopy.Copy(test.container).(SheetPrOptionPtr)
+ val1 := deepcopy.Copy(def).(SheetPrOptionPtr)
+ val2 := deepcopy.Copy(def).(SheetPrOptionPtr)
- f := excelize.NewFile()
+ f := NewFile()
// Get the default value
assert.NoError(t, f.GetSheetPrOptions(sheet, def), opt)
// Get again and check
@@ -148,46 +146,46 @@ func TestSheetPrOptions(t *testing.T) {
}
func TestSetSheetrOptions(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
// Test SetSheetrOptions on not exists worksheet.
assert.EqualError(t, f.SetSheetPrOptions("SheetN"), "sheet SheetN is not exist")
}
func TestGetSheetPrOptions(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
// Test GetSheetPrOptions on not exists worksheet.
assert.EqualError(t, f.GetSheetPrOptions("SheetN"), "sheet SheetN is not exist")
}
-var _ = []excelize.PageMarginsOptions{
- excelize.PageMarginBottom(1.0),
- excelize.PageMarginFooter(1.0),
- excelize.PageMarginHeader(1.0),
- excelize.PageMarginLeft(1.0),
- excelize.PageMarginRight(1.0),
- excelize.PageMarginTop(1.0),
+var _ = []PageMarginsOptions{
+ PageMarginBottom(1.0),
+ PageMarginFooter(1.0),
+ PageMarginHeader(1.0),
+ PageMarginLeft(1.0),
+ PageMarginRight(1.0),
+ PageMarginTop(1.0),
}
-var _ = []excelize.PageMarginsOptionsPtr{
- (*excelize.PageMarginBottom)(nil),
- (*excelize.PageMarginFooter)(nil),
- (*excelize.PageMarginHeader)(nil),
- (*excelize.PageMarginLeft)(nil),
- (*excelize.PageMarginRight)(nil),
- (*excelize.PageMarginTop)(nil),
+var _ = []PageMarginsOptionsPtr{
+ (*PageMarginBottom)(nil),
+ (*PageMarginFooter)(nil),
+ (*PageMarginHeader)(nil),
+ (*PageMarginLeft)(nil),
+ (*PageMarginRight)(nil),
+ (*PageMarginTop)(nil),
}
func ExampleFile_SetPageMargins() {
- f := excelize.NewFile()
+ f := NewFile()
const sheet = "Sheet1"
if err := f.SetPageMargins(sheet,
- excelize.PageMarginBottom(1.0),
- excelize.PageMarginFooter(1.0),
- excelize.PageMarginHeader(1.0),
- excelize.PageMarginLeft(1.0),
- excelize.PageMarginRight(1.0),
- excelize.PageMarginTop(1.0),
+ PageMarginBottom(1.0),
+ PageMarginFooter(1.0),
+ PageMarginHeader(1.0),
+ PageMarginLeft(1.0),
+ PageMarginRight(1.0),
+ PageMarginTop(1.0),
); err != nil {
fmt.Println(err)
}
@@ -195,16 +193,16 @@ func ExampleFile_SetPageMargins() {
}
func ExampleFile_GetPageMargins() {
- f := excelize.NewFile()
+ f := NewFile()
const sheet = "Sheet1"
var (
- marginBottom excelize.PageMarginBottom
- marginFooter excelize.PageMarginFooter
- marginHeader excelize.PageMarginHeader
- marginLeft excelize.PageMarginLeft
- marginRight excelize.PageMarginRight
- marginTop excelize.PageMarginTop
+ marginBottom PageMarginBottom
+ marginFooter PageMarginFooter
+ marginHeader PageMarginHeader
+ marginLeft PageMarginLeft
+ marginRight PageMarginRight
+ marginTop PageMarginTop
)
if err := f.GetPageMargins(sheet,
@@ -238,15 +236,15 @@ func TestPageMarginsOption(t *testing.T) {
const sheet = "Sheet1"
testData := []struct {
- container excelize.PageMarginsOptionsPtr
- nonDefault excelize.PageMarginsOptions
+ container PageMarginsOptionsPtr
+ nonDefault PageMarginsOptions
}{
- {new(excelize.PageMarginTop), excelize.PageMarginTop(1.0)},
- {new(excelize.PageMarginBottom), excelize.PageMarginBottom(1.0)},
- {new(excelize.PageMarginLeft), excelize.PageMarginLeft(1.0)},
- {new(excelize.PageMarginRight), excelize.PageMarginRight(1.0)},
- {new(excelize.PageMarginHeader), excelize.PageMarginHeader(1.0)},
- {new(excelize.PageMarginFooter), excelize.PageMarginFooter(1.0)},
+ {new(PageMarginTop), PageMarginTop(1.0)},
+ {new(PageMarginBottom), PageMarginBottom(1.0)},
+ {new(PageMarginLeft), PageMarginLeft(1.0)},
+ {new(PageMarginRight), PageMarginRight(1.0)},
+ {new(PageMarginHeader), PageMarginHeader(1.0)},
+ {new(PageMarginFooter), PageMarginFooter(1.0)},
}
for i, test := range testData {
@@ -255,11 +253,11 @@ func TestPageMarginsOption(t *testing.T) {
opt := test.nonDefault
t.Logf("option %T", opt)
- def := deepcopy.Copy(test.container).(excelize.PageMarginsOptionsPtr)
- val1 := deepcopy.Copy(def).(excelize.PageMarginsOptionsPtr)
- val2 := deepcopy.Copy(def).(excelize.PageMarginsOptionsPtr)
+ def := deepcopy.Copy(test.container).(PageMarginsOptionsPtr)
+ val1 := deepcopy.Copy(def).(PageMarginsOptionsPtr)
+ val2 := deepcopy.Copy(def).(PageMarginsOptionsPtr)
- f := excelize.NewFile()
+ f := NewFile()
// Get the default value
assert.NoError(t, f.GetPageMargins(sheet, def), opt)
// Get again and check
@@ -297,29 +295,29 @@ func TestPageMarginsOption(t *testing.T) {
}
func TestSetPageMargins(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
// Test set page margins on not exists worksheet.
assert.EqualError(t, f.SetPageMargins("SheetN"), "sheet SheetN is not exist")
}
func TestGetPageMargins(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
// Test get page margins on not exists worksheet.
assert.EqualError(t, f.GetPageMargins("SheetN"), "sheet SheetN is not exist")
}
func ExampleFile_SetSheetFormatPr() {
- f := excelize.NewFile()
+ f := NewFile()
const sheet = "Sheet1"
if err := f.SetSheetFormatPr(sheet,
- excelize.BaseColWidth(1.0),
- excelize.DefaultColWidth(1.0),
- excelize.DefaultRowHeight(1.0),
- excelize.CustomHeight(true),
- excelize.ZeroHeight(true),
- excelize.ThickTop(true),
- excelize.ThickBottom(true),
+ BaseColWidth(1.0),
+ DefaultColWidth(1.0),
+ DefaultRowHeight(1.0),
+ CustomHeight(true),
+ ZeroHeight(true),
+ ThickTop(true),
+ ThickBottom(true),
); err != nil {
fmt.Println(err)
}
@@ -327,17 +325,17 @@ func ExampleFile_SetSheetFormatPr() {
}
func ExampleFile_GetSheetFormatPr() {
- f := excelize.NewFile()
+ f := NewFile()
const sheet = "Sheet1"
var (
- baseColWidth excelize.BaseColWidth
- defaultColWidth excelize.DefaultColWidth
- defaultRowHeight excelize.DefaultRowHeight
- customHeight excelize.CustomHeight
- zeroHeight excelize.ZeroHeight
- thickTop excelize.ThickTop
- thickBottom excelize.ThickBottom
+ baseColWidth BaseColWidth
+ defaultColWidth DefaultColWidth
+ defaultRowHeight DefaultRowHeight
+ customHeight CustomHeight
+ zeroHeight ZeroHeight
+ thickTop ThickTop
+ thickBottom ThickBottom
)
if err := f.GetSheetFormatPr(sheet,
@@ -374,16 +372,16 @@ func TestSheetFormatPrOptions(t *testing.T) {
const sheet = "Sheet1"
testData := []struct {
- container excelize.SheetFormatPrOptionsPtr
- nonDefault excelize.SheetFormatPrOptions
+ container SheetFormatPrOptionsPtr
+ nonDefault SheetFormatPrOptions
}{
- {new(excelize.BaseColWidth), excelize.BaseColWidth(1.0)},
- {new(excelize.DefaultColWidth), excelize.DefaultColWidth(1.0)},
- {new(excelize.DefaultRowHeight), excelize.DefaultRowHeight(1.0)},
- {new(excelize.CustomHeight), excelize.CustomHeight(true)},
- {new(excelize.ZeroHeight), excelize.ZeroHeight(true)},
- {new(excelize.ThickTop), excelize.ThickTop(true)},
- {new(excelize.ThickBottom), excelize.ThickBottom(true)},
+ {new(BaseColWidth), BaseColWidth(1.0)},
+ {new(DefaultColWidth), DefaultColWidth(1.0)},
+ {new(DefaultRowHeight), DefaultRowHeight(1.0)},
+ {new(CustomHeight), CustomHeight(true)},
+ {new(ZeroHeight), ZeroHeight(true)},
+ {new(ThickTop), ThickTop(true)},
+ {new(ThickBottom), ThickBottom(true)},
}
for i, test := range testData {
@@ -392,11 +390,11 @@ func TestSheetFormatPrOptions(t *testing.T) {
opt := test.nonDefault
t.Logf("option %T", opt)
- def := deepcopy.Copy(test.container).(excelize.SheetFormatPrOptionsPtr)
- val1 := deepcopy.Copy(def).(excelize.SheetFormatPrOptionsPtr)
- val2 := deepcopy.Copy(def).(excelize.SheetFormatPrOptionsPtr)
+ def := deepcopy.Copy(test.container).(SheetFormatPrOptionsPtr)
+ val1 := deepcopy.Copy(def).(SheetFormatPrOptionsPtr)
+ val2 := deepcopy.Copy(def).(SheetFormatPrOptionsPtr)
- f := excelize.NewFile()
+ f := NewFile()
// Get the default value
assert.NoError(t, f.GetSheetFormatPr(sheet, def), opt)
// Get again and check
@@ -434,26 +432,26 @@ func TestSheetFormatPrOptions(t *testing.T) {
}
func TestSetSheetFormatPr(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
assert.NoError(t, f.GetSheetFormatPr("Sheet1"))
f.Sheet["xl/worksheets/sheet1.xml"].SheetFormatPr = nil
- assert.NoError(t, f.SetSheetFormatPr("Sheet1", excelize.BaseColWidth(1.0)))
+ assert.NoError(t, f.SetSheetFormatPr("Sheet1", BaseColWidth(1.0)))
// Test set formatting properties on not exists worksheet.
assert.EqualError(t, f.SetSheetFormatPr("SheetN"), "sheet SheetN is not exist")
}
func TestGetSheetFormatPr(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
assert.NoError(t, f.GetSheetFormatPr("Sheet1"))
f.Sheet["xl/worksheets/sheet1.xml"].SheetFormatPr = nil
var (
- baseColWidth excelize.BaseColWidth
- defaultColWidth excelize.DefaultColWidth
- defaultRowHeight excelize.DefaultRowHeight
- customHeight excelize.CustomHeight
- zeroHeight excelize.ZeroHeight
- thickTop excelize.ThickTop
- thickBottom excelize.ThickBottom
+ baseColWidth BaseColWidth
+ defaultColWidth DefaultColWidth
+ defaultRowHeight DefaultRowHeight
+ customHeight CustomHeight
+ zeroHeight ZeroHeight
+ thickTop ThickTop
+ thickBottom ThickBottom
)
assert.NoError(t, f.GetSheetFormatPr("Sheet1",
&baseColWidth,
diff --git a/sheetview_test.go b/sheetview_test.go
index d999875..e323e23 100644
--- a/sheetview_test.go
+++ b/sheetview_test.go
@@ -1,60 +1,58 @@
-package excelize_test
+package excelize
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
-
- "github.com/360EntSecGroup-Skylar/excelize/v2"
)
-var _ = []excelize.SheetViewOption{
- excelize.DefaultGridColor(true),
- excelize.RightToLeft(false),
- excelize.ShowFormulas(false),
- excelize.ShowGridLines(true),
- excelize.ShowRowColHeaders(true),
- excelize.TopLeftCell("B2"),
+var _ = []SheetViewOption{
+ DefaultGridColor(true),
+ RightToLeft(false),
+ ShowFormulas(false),
+ ShowGridLines(true),
+ ShowRowColHeaders(true),
+ TopLeftCell("B2"),
// SheetViewOptionPtr are also SheetViewOption
- new(excelize.DefaultGridColor),
- new(excelize.RightToLeft),
- new(excelize.ShowFormulas),
- new(excelize.ShowGridLines),
- new(excelize.ShowRowColHeaders),
- new(excelize.TopLeftCell),
+ new(DefaultGridColor),
+ new(RightToLeft),
+ new(ShowFormulas),
+ new(ShowGridLines),
+ new(ShowRowColHeaders),
+ new(TopLeftCell),
}
-var _ = []excelize.SheetViewOptionPtr{
- (*excelize.DefaultGridColor)(nil),
- (*excelize.RightToLeft)(nil),
- (*excelize.ShowFormulas)(nil),
- (*excelize.ShowGridLines)(nil),
- (*excelize.ShowRowColHeaders)(nil),
- (*excelize.TopLeftCell)(nil),
+var _ = []SheetViewOptionPtr{
+ (*DefaultGridColor)(nil),
+ (*RightToLeft)(nil),
+ (*ShowFormulas)(nil),
+ (*ShowGridLines)(nil),
+ (*ShowRowColHeaders)(nil),
+ (*TopLeftCell)(nil),
}
func ExampleFile_SetSheetViewOptions() {
- f := excelize.NewFile()
+ f := NewFile()
const sheet = "Sheet1"
if err := f.SetSheetViewOptions(sheet, 0,
- excelize.DefaultGridColor(false),
- excelize.RightToLeft(false),
- excelize.ShowFormulas(true),
- excelize.ShowGridLines(true),
- excelize.ShowRowColHeaders(true),
- excelize.ZoomScale(80),
- excelize.TopLeftCell("C3"),
+ DefaultGridColor(false),
+ RightToLeft(false),
+ ShowFormulas(true),
+ ShowGridLines(true),
+ ShowRowColHeaders(true),
+ ZoomScale(80),
+ TopLeftCell("C3"),
); err != nil {
fmt.Println(err)
}
- var zoomScale excelize.ZoomScale
+ var zoomScale ZoomScale
fmt.Println("Default:")
fmt.Println("- zoomScale: 80")
- if err := f.SetSheetViewOptions(sheet, 0, excelize.ZoomScale(500)); err != nil {
+ if err := f.SetSheetViewOptions(sheet, 0, ZoomScale(500)); err != nil {
fmt.Println(err)
}
@@ -65,7 +63,7 @@ func ExampleFile_SetSheetViewOptions() {
fmt.Println("Used out of range value:")
fmt.Println("- zoomScale:", zoomScale)
- if err := f.SetSheetViewOptions(sheet, 0, excelize.ZoomScale(123)); err != nil {
+ if err := f.SetSheetViewOptions(sheet, 0, ZoomScale(123)); err != nil {
fmt.Println(err)
}
@@ -87,18 +85,18 @@ func ExampleFile_SetSheetViewOptions() {
}
func ExampleFile_GetSheetViewOptions() {
- f := excelize.NewFile()
+ f := NewFile()
const sheet = "Sheet1"
var (
- defaultGridColor excelize.DefaultGridColor
- rightToLeft excelize.RightToLeft
- showFormulas excelize.ShowFormulas
- showGridLines excelize.ShowGridLines
- showZeros excelize.ShowZeros
- showRowColHeaders excelize.ShowRowColHeaders
- zoomScale excelize.ZoomScale
- topLeftCell excelize.TopLeftCell
+ defaultGridColor DefaultGridColor
+ rightToLeft RightToLeft
+ showFormulas ShowFormulas
+ showGridLines ShowGridLines
+ showZeros ShowZeros
+ showRowColHeaders ShowRowColHeaders
+ zoomScale ZoomScale
+ topLeftCell TopLeftCell
)
if err := f.GetSheetViewOptions(sheet, 0,
@@ -124,7 +122,7 @@ func ExampleFile_GetSheetViewOptions() {
fmt.Println("- zoomScale:", zoomScale)
fmt.Println("- topLeftCell:", `"`+topLeftCell+`"`)
- if err := f.SetSheetViewOptions(sheet, 0, excelize.TopLeftCell("B2")); err != nil {
+ if err := f.SetSheetViewOptions(sheet, 0, TopLeftCell("B2")); err != nil {
fmt.Println(err)
}
@@ -132,7 +130,7 @@ func ExampleFile_GetSheetViewOptions() {
fmt.Println(err)
}
- if err := f.SetSheetViewOptions(sheet, 0, excelize.ShowGridLines(false)); err != nil {
+ if err := f.SetSheetViewOptions(sheet, 0, ShowGridLines(false)); err != nil {
fmt.Println(err)
}
@@ -140,7 +138,7 @@ func ExampleFile_GetSheetViewOptions() {
fmt.Println(err)
}
- if err := f.SetSheetViewOptions(sheet, 0, excelize.ShowZeros(false)); err != nil {
+ if err := f.SetSheetViewOptions(sheet, 0, ShowZeros(false)); err != nil {
fmt.Println(err)
}
@@ -170,7 +168,7 @@ func ExampleFile_GetSheetViewOptions() {
}
func TestSheetViewOptionsErrors(t *testing.T) {
- f := excelize.NewFile()
+ f := NewFile()
const sheet = "Sheet1"
assert.NoError(t, f.GetSheetViewOptions(sheet, 0))
diff --git a/styles.go b/styles.go
index 14bcecc..d4d0468 100644
--- a/styles.go
+++ b/styles.go
@@ -21,6 +21,7 @@ import (
"log"
"math"
"reflect"
+ "regexp"
"strconv"
"strings"
)
@@ -755,7 +756,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(i int, v string) string{
+var builtInNumFmtFunc = map[int]func(v string, format string) string{
0: formatToString,
1: formatToInt,
2: formatToFloat,
@@ -847,14 +848,14 @@ var criteriaType = map[string]string{
// formatToString provides a function to return original string by given
// built-in number formats code and cell string.
-func formatToString(i int, v string) string {
+func formatToString(v string, format string) string {
return v
}
// 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(i int, v string) string {
+func formatToInt(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@@ -865,7 +866,7 @@ func formatToInt(i int, v 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(i int, v string) string {
+func formatToFloat(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@@ -875,7 +876,7 @@ func formatToFloat(i int, v 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(i int, v string) string {
+func formatToA(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@@ -890,7 +891,7 @@ func formatToA(i int, v 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(i int, v string) string {
+func formatToB(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@@ -903,7 +904,7 @@ func formatToB(i int, v 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(i int, v string) string {
+func formatToC(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@@ -914,7 +915,7 @@ func formatToC(i int, v 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(i int, v string) string {
+func formatToD(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@@ -925,7 +926,7 @@ func formatToD(i int, v 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(i int, v string) string {
+func formatToE(v string, format string) string {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return v
@@ -933,6 +934,8 @@ func formatToE(i int, v string) string {
return fmt.Sprintf("%.e", f)
}
+var dateTimeFormatsCache = map[string]string{}
+
// parseTime provides a function to returns a string parsed using time.Time.
// Replace Excel placeholders with Go time placeholders. For example, replace
// yyyy with 2006. These are in a specific order, due to the fact that m is
@@ -944,15 +947,46 @@ func formatToE(i int, v string) string {
// arbitrary characters unused in Excel Date formats, and then at the end,
// turn them to what they should actually be. Based off:
// http://www.ozgrid.com/Excel/CustomFormats.htm
-func parseTime(i int, v string) string {
- f, err := strconv.ParseFloat(v, 64)
+func parseTime(v string, format string) string {
+ var (
+ f float64
+ err error
+ goFmt string
+ )
+ f, err = strconv.ParseFloat(v, 64)
if err != nil {
return v
}
val := timeFromExcelTime(f, false)
- format := builtInNumFmt[i]
+
+ if format == "" {
+ return v
+ }
+
+ goFmt, found := dateTimeFormatsCache[format]
+ if found {
+ return val.Format(goFmt)
+ }
+
+ goFmt = format
+
+ if strings.Contains(goFmt, "[") {
+ var re = regexp.MustCompile(`\[.+\]`)
+ goFmt = re.ReplaceAllLiteralString(goFmt, "")
+ }
+
+ // use only first variant
+ if strings.Contains(goFmt, ";") {
+ goFmt = goFmt[:strings.IndexByte(goFmt, ';')]
+ }
replacements := []struct{ xltime, gotime string }{
+ {"YYYY", "2006"},
+ {"YY", "06"},
+ {"MM", "01"},
+ {"M", "1"},
+ {"DD", "02"},
+ {"D", "2"},
{"yyyy", "2006"},
{"yy", "06"},
{"mmmm", "%%%%"},
@@ -962,38 +996,59 @@ func parseTime(i int, v string) string {
{"mmm", "Jan"},
{"mmss", "0405"},
{"ss", "05"},
+ {"s", "5"},
{"mm:", "04:"},
{":mm", ":04"},
+ {"m:", "4:"},
+ {":m", ":4"},
{"mm", "01"},
{"am/pm", "pm"},
{"m/", "1/"},
{"%%%%", "January"},
{"&&&&", "Monday"},
}
+
+ replacementsGlobal := []struct{ xltime, gotime string }{
+ {"\\-", "-"},
+ {"\\ ", " "},
+ {"\\.", "."},
+ {"\\", ""},
+ }
// It is the presence of the "am/pm" indicator that determines if this is
// a 12 hour or 24 hours time format, not the number of 'h' characters.
if is12HourTime(format) {
- format = strings.Replace(format, "hh", "03", 1)
- format = strings.Replace(format, "h", "3", 1)
+ goFmt = strings.Replace(goFmt, "hh", "3", 1)
+ goFmt = strings.Replace(goFmt, "h", "3", 1)
+ goFmt = strings.Replace(goFmt, "HH", "3", 1)
+ goFmt = strings.Replace(goFmt, "H", "3", 1)
} else {
- format = strings.Replace(format, "hh", "15", 1)
- format = strings.Replace(format, "h", "15", 1)
+ goFmt = strings.Replace(goFmt, "hh", "15", 1)
+ goFmt = strings.Replace(goFmt, "h", "3", 1)
+ goFmt = strings.Replace(goFmt, "HH", "15", 1)
+ goFmt = strings.Replace(goFmt, "H", "3", 1)
}
+
for _, repl := range replacements {
- format = strings.Replace(format, repl.xltime, repl.gotime, 1)
+ goFmt = strings.Replace(goFmt, repl.xltime, repl.gotime, 1)
+ }
+ for _, repl := range replacementsGlobal {
+ goFmt = strings.Replace(goFmt, repl.xltime, repl.gotime, -1)
}
// If the hour is optional, strip it out, along with the possible dangling
// colon that would remain.
if val.Hour() < 1 {
- format = strings.Replace(format, "]:", "]", 1)
- format = strings.Replace(format, "[03]", "", 1)
- format = strings.Replace(format, "[3]", "", 1)
- format = strings.Replace(format, "[15]", "", 1)
+ goFmt = strings.Replace(goFmt, "]:", "]", 1)
+ goFmt = strings.Replace(goFmt, "[03]", "", 1)
+ goFmt = strings.Replace(goFmt, "[3]", "", 1)
+ goFmt = strings.Replace(goFmt, "[15]", "", 1)
} else {
- format = strings.Replace(format, "[3]", "3", 1)
- format = strings.Replace(format, "[15]", "15", 1)
+ goFmt = strings.Replace(goFmt, "[3]", "3", 1)
+ goFmt = strings.Replace(goFmt, "[15]", "15", 1)
}
- return val.Format(format)
+
+ dateTimeFormatsCache[format] = goFmt
+
+ return val.Format(goFmt)
}
// is12HourTime checks whether an Excel time format string is a 12 hours form.
@@ -2226,6 +2281,7 @@ func newNumFmt(styleSheet *xlsxStyleSheet, style *Style) int {
// setCustomNumFmt provides a function to set custom number format code.
func setCustomNumFmt(styleSheet *xlsxStyleSheet, style *Style) int {
nf := xlsxNumFmt{FormatCode: *style.CustomNumFmt}
+
if styleSheet.NumFmts != nil {
nf.NumFmtID = styleSheet.NumFmts.NumFmt[len(styleSheet.NumFmts.NumFmt)-1].NumFmtID + 1
styleSheet.NumFmts.NumFmt = append(styleSheet.NumFmts.NumFmt, &nf)
diff --git a/styles_test.go b/styles_test.go
index b68365b..8ce26a4 100644
--- a/styles_test.go
+++ b/styles_test.go
@@ -201,10 +201,44 @@ func TestNewStyle(t *testing.T) {
assert.NoError(t, err)
_, err = f.NewStyle(Style{})
assert.EqualError(t, err, "invalid parameter type")
+
_, err = f.NewStyle(&Style{Font: &Font{Family: strings.Repeat("s", MaxFontFamilyLength+1)}})
assert.EqualError(t, err, "the length of the font family name must be smaller than or equal to 31")
_, err = f.NewStyle(&Style{Font: &Font{Size: MaxFontSize + 1}})
assert.EqualError(t, err, "font size must be between 1 and 409 points")
+
+ // new numeric custom style
+ fmt := "####;####"
+ f.Styles.NumFmts = nil
+ styleID, err = f.NewStyle(&Style{
+ CustomNumFmt: &fmt,
+ })
+ assert.NoError(t, err)
+ assert.Equal(t, 2, styleID)
+
+ assert.NotNil(t, f.Styles)
+ assert.NotNil(t, f.Styles.CellXfs)
+ assert.NotNil(t, f.Styles.CellXfs.Xf)
+
+ nf := f.Styles.CellXfs.Xf[styleID]
+ assert.Equal(t, 164, *nf.NumFmtID)
+
+ // new currency custom style
+ f.Styles.NumFmts = nil
+ styleID, err = f.NewStyle(&Style{
+ Lang: "ko-kr",
+ NumFmt: 32, // must not be in currencyNumFmt
+
+ })
+ assert.NoError(t, err)
+ assert.Equal(t, 3, styleID)
+
+ assert.NotNil(t, f.Styles)
+ assert.NotNil(t, f.Styles.CellXfs)
+ assert.NotNil(t, f.Styles.CellXfs.Xf)
+
+ nf = f.Styles.CellXfs.Xf[styleID]
+ assert.Equal(t, 32, *nf.NumFmtID)
}
func TestGetDefaultFont(t *testing.T) {
@@ -250,3 +284,15 @@ func TestGetStyleID(t *testing.T) {
func TestGetFillID(t *testing.T) {
assert.Equal(t, -1, getFillID(NewFile().stylesReader(), &Style{Fill: Fill{Type: "unknown"}}))
}
+
+func TestParseTime(t *testing.T) {
+ assert.Equal(t, "2019", parseTime("43528", "YYYY"))
+ assert.Equal(t, "43528", parseTime("43528", ""))
+
+ assert.Equal(t, "2019-03-04 05:05:42", parseTime("43528.2123", "YYYY-MM-DD hh:mm:ss"))
+ assert.Equal(t, "2019-03-04 05:05:42", parseTime("43528.2123", "YYYY-MM-DD hh:mm:ss;YYYY-MM-DD hh:mm:ss"))
+ assert.Equal(t, "3/4/2019 5:5:42", parseTime("43528.2123", "M/D/YYYY h:m:s"))
+ assert.Equal(t, "March", parseTime("43528", "mmmm"))
+ assert.Equal(t, "Monday", parseTime("43528", "dddd"))
+
+}