Browse Source

extend cell value load to support custom datetime format (#703)

* extend cell value load to support custom datetime format

* cleanup incorrect imports

* fix numeric values conversion as done in legacy Excel

* fix tests coverage

* revert temporary package name fix

* remove personal info from test XLSX files

* remove unused dependencies

* update format conversion in parseTime

* new UT to increase code coverage

* Resolve code review issue for PR #703

* Rename broken file name generated by unit test

Co-authored-by: xuri <xuri.me@gmail.com>
Artem Kustikov 5 years ago
parent
commit
f2b8798a34
14 changed files with 452 additions and 248 deletions
  1. 1 0
      .gitignore
  2. 16 2
      cell.go
  3. 36 0
      cell_test.go
  4. 1 1
      crypt_test.go
  5. 1 1
      excelize.go
  6. 4 1
      excelize_test.go
  7. 1 1
      file.go
  8. 19 0
      rows.go
  9. 36 1
      rows_test.go
  10. 42 44
      sheet_test.go
  11. 124 126
      sheetpr_test.go
  12. 45 47
      sheetview_test.go
  13. 80 24
      styles.go
  14. 46 0
      styles_test.go

+ 1 - 0
.gitignore

@@ -1,5 +1,6 @@
 ~$*.xlsx
 ~$*.xlsx
 test/Test*.xlsx
 test/Test*.xlsx
+test/Test*.xlsm
 *.out
 *.out
 *.test
 *.test
 .idea
 .idea

+ 16 - 2
cell.go

@@ -762,9 +762,23 @@ func (f *File) formattedValue(s int, v string) string {
 		return v
 		return v
 	}
 	}
 	styleSheet := f.stylesReader()
 	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 {
 	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
 	return v
 }
 }

+ 36 - 0
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"`)
 	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) {
 func TestSetCellBool(t *testing.T) {
 	f := NewFile()
 	f := NewFile()
 	assert.EqualError(t, f.SetCellBool("Sheet1", "A", true), `cannot convert cell "A" to coordinates: invalid cell name "A"`)
 	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
 	// 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"`)
 	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)
+}

+ 1 - 1
crypt_test.go

@@ -19,5 +19,5 @@ import (
 func TestEncrypt(t *testing.T) {
 func TestEncrypt(t *testing.T) {
 	f, err := OpenFile(filepath.Join("test", "encryptSHA1.xlsx"), Options{Password: "password"})
 	f, err := OpenFile(filepath.Join("test", "encryptSHA1.xlsx"), Options{Password: "password"})
 	assert.NoError(t, err)
 	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")
 }
 }

+ 1 - 1
excelize.go

@@ -158,7 +158,7 @@ func (f *File) setDefaultTimeStyle(sheet, axis string, format int) error {
 	}
 	}
 	if s == 0 {
 	if s == 0 {
 		style, _ := f.NewStyle(&Style{NumFmt: format})
 		style, _ := f.NewStyle(&Style{NumFmt: format})
-		_ = f.SetCellStyle(sheet, axis, axis, style)
+		err = f.SetCellStyle(sheet, axis, axis, style)
 	}
 	}
 	return err
 	return err
 }
 }

+ 4 - 1
excelize_test.go

@@ -257,7 +257,7 @@ func TestBrokenFile(t *testing.T) {
 
 
 	t.Run("SaveAsEmptyStruct", func(t *testing.T) {
 	t.Run("SaveAsEmptyStruct", func(t *testing.T) {
 		// Test write file with broken file struct with given path.
 		// 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) {
 	t.Run("OpenBadWorkbook", func(t *testing.T) {
@@ -1175,6 +1175,9 @@ func TestSetDefaultTimeStyle(t *testing.T) {
 	f := NewFile()
 	f := NewFile()
 	// Test set default time style on not exists worksheet.
 	// Test set default time style on not exists worksheet.
 	assert.EqualError(t, f.setDefaultTimeStyle("SheetN", "", 0), "sheet SheetN is not exist")
 	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) {
 func TestAddVBAProject(t *testing.T) {

+ 1 - 1
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 {
 		if err := zw.Close(); err != nil {
 			return buf, err
 			return buf, err
 		}
 		}

+ 19 - 0
rows.go

@@ -345,6 +345,25 @@ func (xlsx *xlsxC) getValueFrom(f *File, d *xlsxSST) (string, error) {
 		}
 		}
 		return f.formattedValue(xlsx.S, xlsx.V), nil
 		return f.formattedValue(xlsx.S, xlsx.V), nil
 	default:
 	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
 		return f.formattedValue(xlsx.S, xlsx.V), nil
 	}
 	}
 }
 }

+ 36 - 1
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")
 	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"}
 	c := &xlsxC{T: "inlineStr"}
 	f := NewFile()
 	f := NewFile()
 	d := &xlsxSST{}
 	d := &xlsxSST{}
@@ -826,6 +826,20 @@ func TestGetValueFrom(t *testing.T) {
 	assert.Equal(t, "", val)
 	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) {
 func TestErrSheetNotExistError(t *testing.T) {
 	err := ErrSheetNotExist{SheetName: "Sheet1"}
 	err := ErrSheetNotExist{SheetName: "Sheet1"}
 	assert.EqualValues(t, err.Error(), "sheet Sheet1 is not exist")
 	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 "-"`)
 	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) {
 func BenchmarkRows(b *testing.B) {
 	f, _ := OpenFile(filepath.Join("test", "Book1.xlsx"))
 	f, _ := OpenFile(filepath.Join("test", "Book1.xlsx"))
 	for i := 0; i < b.N; i++ {
 	for i := 0; i < b.N; i++ {

+ 42 - 44
sheet_test.go

@@ -1,4 +1,4 @@
-package excelize_test
+package excelize
 
 
 import (
 import (
 	"fmt"
 	"fmt"
@@ -6,26 +6,24 @@ import (
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 
 
-	"github.com/360EntSecGroup-Skylar/excelize/v2"
-
 	"github.com/mohae/deepcopy"
 	"github.com/mohae/deepcopy"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/assert"
 )
 )
 
 
 func ExampleFile_SetPageLayout() {
 func ExampleFile_SetPageLayout() {
-	f := excelize.NewFile()
+	f := NewFile()
 
 
 	if err := f.SetPageLayout(
 	if err := f.SetPageLayout(
 		"Sheet1",
 		"Sheet1",
-		excelize.PageLayoutOrientation(excelize.OrientationLandscape),
+		PageLayoutOrientation(OrientationLandscape),
 	); err != nil {
 	); err != nil {
 		fmt.Println(err)
 		fmt.Println(err)
 	}
 	}
 	if err := f.SetPageLayout(
 	if err := f.SetPageLayout(
 		"Sheet1",
 		"Sheet1",
-		excelize.PageLayoutPaperSize(10),
-		excelize.FitToHeight(2),
-		excelize.FitToWidth(2),
+		PageLayoutPaperSize(10),
+		FitToHeight(2),
+		FitToWidth(2),
 	); err != nil {
 	); err != nil {
 		fmt.Println(err)
 		fmt.Println(err)
 	}
 	}
@@ -33,12 +31,12 @@ func ExampleFile_SetPageLayout() {
 }
 }
 
 
 func ExampleFile_GetPageLayout() {
 func ExampleFile_GetPageLayout() {
-	f := excelize.NewFile()
+	f := NewFile()
 	var (
 	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 {
 	if err := f.GetPageLayout("Sheet1", &orientation); err != nil {
 		fmt.Println(err)
 		fmt.Println(err)
@@ -67,7 +65,7 @@ func ExampleFile_GetPageLayout() {
 }
 }
 
 
 func TestNewSheet(t *testing.T) {
 func TestNewSheet(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	sheetID := f.NewSheet("Sheet2")
 	sheetID := f.NewSheet("Sheet2")
 	f.SetActiveSheet(sheetID)
 	f.SetActiveSheet(sheetID)
 	// delete original sheet
 	// delete original sheet
@@ -76,7 +74,7 @@ func TestNewSheet(t *testing.T) {
 }
 }
 
 
 func TestSetPane(t *testing.T) {
 func TestSetPane(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	assert.NoError(t, f.SetPanes("Sheet1", `{"freeze":false,"split":false}`))
 	assert.NoError(t, f.SetPanes("Sheet1", `{"freeze":false,"split":false}`))
 	f.NewSheet("Panes 2")
 	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"}]}`))
 	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"
 	const sheet = "Sheet1"
 
 
 	testData := []struct {
 	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 {
 	for i, test := range testData {
@@ -108,11 +106,11 @@ func TestPageLayoutOption(t *testing.T) {
 			opt := test.nonDefault
 			opt := test.nonDefault
 			t.Logf("option %T", opt)
 			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
 			// Get the default value
 			assert.NoError(t, f.GetPageLayout(sheet, def), opt)
 			assert.NoError(t, f.GetPageLayout(sheet, def), opt)
 			// Get again and check
 			// Get again and check
@@ -150,7 +148,7 @@ func TestPageLayoutOption(t *testing.T) {
 }
 }
 
 
 func TestSearchSheet(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) {
 	if !assert.NoError(t, err) {
 		t.FailNow()
 		t.FailNow()
 	}
 	}
@@ -172,36 +170,36 @@ func TestSearchSheet(t *testing.T) {
 	assert.EqualValues(t, expected, result)
 	assert.EqualValues(t, expected, result)
 
 
 	// Test search worksheet data after set cell value
 	// Test search worksheet data after set cell value
-	f = excelize.NewFile()
+	f = NewFile()
 	assert.NoError(t, f.SetCellValue("Sheet1", "A1", true))
 	assert.NoError(t, f.SetCellValue("Sheet1", "A1", true))
 	_, err = f.SearchSheet("Sheet1", "")
 	_, err = f.SearchSheet("Sheet1", "")
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 }
 }
 
 
 func TestSetPageLayout(t *testing.T) {
 func TestSetPageLayout(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	// Test set page layout on not exists worksheet.
 	// Test set page layout on not exists worksheet.
 	assert.EqualError(t, f.SetPageLayout("SheetN"), "sheet SheetN is not exist")
 	assert.EqualError(t, f.SetPageLayout("SheetN"), "sheet SheetN is not exist")
 }
 }
 
 
 func TestGetPageLayout(t *testing.T) {
 func TestGetPageLayout(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	// Test get page layout on not exists worksheet.
 	// Test get page layout on not exists worksheet.
 	assert.EqualError(t, f.GetPageLayout("SheetN"), "sheet SheetN is not exist")
 	assert.EqualError(t, f.GetPageLayout("SheetN"), "sheet SheetN is not exist")
 }
 }
 
 
 func TestSetHeaderFooter(t *testing.T) {
 func TestSetHeaderFooter(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	assert.NoError(t, f.SetCellStr("Sheet1", "A1", "Test SetHeaderFooter"))
 	assert.NoError(t, f.SetCellStr("Sheet1", "A1", "Test SetHeaderFooter"))
 	// Test set header and footer on not exists worksheet.
 	// Test set header and footer on not exists worksheet.
 	assert.EqualError(t, f.SetHeaderFooter("SheetN", nil), "sheet SheetN is not exist")
 	assert.EqualError(t, f.SetHeaderFooter("SheetN", nil), "sheet SheetN is not exist")
 	// Test set header and footer with illegal setting.
 	// 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),
 		OddHeader: strings.Repeat("c", 256),
 	}), "field OddHeader must be less than 255 characters")
 	}), "field OddHeader must be less than 255 characters")
 
 
 	assert.NoError(t, f.SetHeaderFooter("Sheet1", nil))
 	assert.NoError(t, f.SetHeaderFooter("Sheet1", nil))
-	assert.NoError(t, f.SetHeaderFooter("Sheet1", &excelize.FormatHeaderFooter{
+	assert.NoError(t, f.SetHeaderFooter("Sheet1", &FormatHeaderFooter{
 		DifferentFirst:   true,
 		DifferentFirst:   true,
 		DifferentOddEven: true,
 		DifferentOddEven: true,
 		OddHeader:        "&R&P",
 		OddHeader:        "&R&P",
@@ -214,28 +212,28 @@ func TestSetHeaderFooter(t *testing.T) {
 }
 }
 
 
 func TestDefinedName(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",
 		Name:     "Amount",
 		RefersTo: "Sheet1!$A$2:$D$5",
 		RefersTo: "Sheet1!$A$2:$D$5",
 		Comment:  "defined name comment",
 		Comment:  "defined name comment",
 		Scope:    "Sheet1",
 		Scope:    "Sheet1",
 	}))
 	}))
-	assert.NoError(t, f.SetDefinedName(&excelize.DefinedName{
+	assert.NoError(t, f.SetDefinedName(&DefinedName{
 		Name:     "Amount",
 		Name:     "Amount",
 		RefersTo: "Sheet1!$A$2:$D$5",
 		RefersTo: "Sheet1!$A$2:$D$5",
 		Comment:  "defined name comment",
 		Comment:  "defined name comment",
 	}))
 	}))
-	assert.EqualError(t, f.SetDefinedName(&excelize.DefinedName{
+	assert.EqualError(t, f.SetDefinedName(&DefinedName{
 		Name:     "Amount",
 		Name:     "Amount",
 		RefersTo: "Sheet1!$A$2:$D$5",
 		RefersTo: "Sheet1!$A$2:$D$5",
 		Comment:  "defined name comment",
 		Comment:  "defined name comment",
 	}), "the same name already exists on the scope")
 	}), "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",
 		Name: "No Exist Defined Name",
 	}), "no defined name on the scope")
 	}), "no defined name on the scope")
 	assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[1].RefersTo)
 	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",
 		Name: "Amount",
 	}))
 	}))
 	assert.Exactly(t, "Sheet1!$A$2:$D$5", f.GetDefinedName()[0].RefersTo)
 	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) {
 func TestGroupSheets(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	sheets := []string{"Sheet2", "Sheet3"}
 	sheets := []string{"Sheet2", "Sheet3"}
 	for _, sheet := range sheets {
 	for _, sheet := range sheets {
 		f.NewSheet(sheet)
 		f.NewSheet(sheet)
@@ -256,7 +254,7 @@ func TestGroupSheets(t *testing.T) {
 }
 }
 
 
 func TestUngroupSheets(t *testing.T) {
 func TestUngroupSheets(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	sheets := []string{"Sheet2", "Sheet3", "Sheet4", "Sheet5"}
 	sheets := []string{"Sheet2", "Sheet3", "Sheet4", "Sheet5"}
 	for _, sheet := range sheets {
 	for _, sheet := range sheets {
 		f.NewSheet(sheet)
 		f.NewSheet(sheet)
@@ -265,7 +263,7 @@ func TestUngroupSheets(t *testing.T) {
 }
 }
 
 
 func TestInsertPageBreak(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", "A1"))
 	assert.NoError(t, f.InsertPageBreak("Sheet1", "B2"))
 	assert.NoError(t, f.InsertPageBreak("Sheet1", "B2"))
 	assert.NoError(t, f.InsertPageBreak("Sheet1", "C3"))
 	assert.NoError(t, f.InsertPageBreak("Sheet1", "C3"))
@@ -276,7 +274,7 @@ func TestInsertPageBreak(t *testing.T) {
 }
 }
 
 
 func TestRemovePageBreak(t *testing.T) {
 func TestRemovePageBreak(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	assert.NoError(t, f.RemovePageBreak("Sheet1", "A2"))
 	assert.NoError(t, f.RemovePageBreak("Sheet1", "A2"))
 
 
 	assert.NoError(t, f.InsertPageBreak("Sheet1", "A2"))
 	assert.NoError(t, f.InsertPageBreak("Sheet1", "A2"))
@@ -302,7 +300,7 @@ func TestRemovePageBreak(t *testing.T) {
 }
 }
 
 
 func TestGetSheetName(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, "Sheet1", f.GetSheetName(0))
 	assert.Equal(t, "Sheet2", f.GetSheetName(1))
 	assert.Equal(t, "Sheet2", f.GetSheetName(1))
 	assert.Equal(t, "", f.GetSheetName(-1))
 	assert.Equal(t, "", f.GetSheetName(-1))
@@ -314,7 +312,7 @@ func TestGetSheetMap(t *testing.T) {
 		1: "Sheet1",
 		1: "Sheet1",
 		2: "Sheet2",
 		2: "Sheet2",
 	}
 	}
-	f, _ := excelize.OpenFile(filepath.Join("test", "Book1.xlsx"))
+	f, _ := OpenFile(filepath.Join("test", "Book1.xlsx"))
 	sheetMap := f.GetSheetMap()
 	sheetMap := f.GetSheetMap()
 	for idx, name := range sheetMap {
 	for idx, name := range sheetMap {
 		assert.Equal(t, expectedMap[idx], name)
 		assert.Equal(t, expectedMap[idx], name)

+ 124 - 126
sheetpr_test.go

@@ -1,4 +1,4 @@
-package excelize_test
+package excelize
 
 
 import (
 import (
 	"fmt"
 	"fmt"
@@ -6,39 +6,37 @@ import (
 
 
 	"github.com/mohae/deepcopy"
 	"github.com/mohae/deepcopy"
 	"github.com/stretchr/testify/assert"
 	"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() {
 func ExampleFile_SetSheetPrOptions() {
-	f := excelize.NewFile()
+	f := NewFile()
 	const sheet = "Sheet1"
 	const sheet = "Sheet1"
 
 
 	if err := f.SetSheetPrOptions(sheet,
 	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 {
 	); err != nil {
 		fmt.Println(err)
 		fmt.Println(err)
 	}
 	}
@@ -46,16 +44,16 @@ func ExampleFile_SetSheetPrOptions() {
 }
 }
 
 
 func ExampleFile_GetSheetPrOptions() {
 func ExampleFile_GetSheetPrOptions() {
-	f := excelize.NewFile()
+	f := NewFile()
 	const sheet = "Sheet1"
 	const sheet = "Sheet1"
 
 
 	var (
 	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,
 	if err := f.GetSheetPrOptions(sheet,
@@ -89,15 +87,15 @@ func TestSheetPrOptions(t *testing.T) {
 	const sheet = "Sheet1"
 	const sheet = "Sheet1"
 
 
 	testData := []struct {
 	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 {
 	for i, test := range testData {
@@ -106,11 +104,11 @@ func TestSheetPrOptions(t *testing.T) {
 			opt := test.nonDefault
 			opt := test.nonDefault
 			t.Logf("option %T", opt)
 			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
 			// Get the default value
 			assert.NoError(t, f.GetSheetPrOptions(sheet, def), opt)
 			assert.NoError(t, f.GetSheetPrOptions(sheet, def), opt)
 			// Get again and check
 			// Get again and check
@@ -148,46 +146,46 @@ func TestSheetPrOptions(t *testing.T) {
 }
 }
 
 
 func TestSetSheetrOptions(t *testing.T) {
 func TestSetSheetrOptions(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	// Test SetSheetrOptions on not exists worksheet.
 	// Test SetSheetrOptions on not exists worksheet.
 	assert.EqualError(t, f.SetSheetPrOptions("SheetN"), "sheet SheetN is not exist")
 	assert.EqualError(t, f.SetSheetPrOptions("SheetN"), "sheet SheetN is not exist")
 }
 }
 
 
 func TestGetSheetPrOptions(t *testing.T) {
 func TestGetSheetPrOptions(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	// Test GetSheetPrOptions on not exists worksheet.
 	// Test GetSheetPrOptions on not exists worksheet.
 	assert.EqualError(t, f.GetSheetPrOptions("SheetN"), "sheet SheetN is not exist")
 	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() {
 func ExampleFile_SetPageMargins() {
-	f := excelize.NewFile()
+	f := NewFile()
 	const sheet = "Sheet1"
 	const sheet = "Sheet1"
 
 
 	if err := f.SetPageMargins(sheet,
 	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 {
 	); err != nil {
 		fmt.Println(err)
 		fmt.Println(err)
 	}
 	}
@@ -195,16 +193,16 @@ func ExampleFile_SetPageMargins() {
 }
 }
 
 
 func ExampleFile_GetPageMargins() {
 func ExampleFile_GetPageMargins() {
-	f := excelize.NewFile()
+	f := NewFile()
 	const sheet = "Sheet1"
 	const sheet = "Sheet1"
 
 
 	var (
 	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,
 	if err := f.GetPageMargins(sheet,
@@ -238,15 +236,15 @@ func TestPageMarginsOption(t *testing.T) {
 	const sheet = "Sheet1"
 	const sheet = "Sheet1"
 
 
 	testData := []struct {
 	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 {
 	for i, test := range testData {
@@ -255,11 +253,11 @@ func TestPageMarginsOption(t *testing.T) {
 			opt := test.nonDefault
 			opt := test.nonDefault
 			t.Logf("option %T", opt)
 			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
 			// Get the default value
 			assert.NoError(t, f.GetPageMargins(sheet, def), opt)
 			assert.NoError(t, f.GetPageMargins(sheet, def), opt)
 			// Get again and check
 			// Get again and check
@@ -297,29 +295,29 @@ func TestPageMarginsOption(t *testing.T) {
 }
 }
 
 
 func TestSetPageMargins(t *testing.T) {
 func TestSetPageMargins(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	// Test set page margins on not exists worksheet.
 	// Test set page margins on not exists worksheet.
 	assert.EqualError(t, f.SetPageMargins("SheetN"), "sheet SheetN is not exist")
 	assert.EqualError(t, f.SetPageMargins("SheetN"), "sheet SheetN is not exist")
 }
 }
 
 
 func TestGetPageMargins(t *testing.T) {
 func TestGetPageMargins(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	// Test get page margins on not exists worksheet.
 	// Test get page margins on not exists worksheet.
 	assert.EqualError(t, f.GetPageMargins("SheetN"), "sheet SheetN is not exist")
 	assert.EqualError(t, f.GetPageMargins("SheetN"), "sheet SheetN is not exist")
 }
 }
 
 
 func ExampleFile_SetSheetFormatPr() {
 func ExampleFile_SetSheetFormatPr() {
-	f := excelize.NewFile()
+	f := NewFile()
 	const sheet = "Sheet1"
 	const sheet = "Sheet1"
 
 
 	if err := f.SetSheetFormatPr(sheet,
 	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 {
 	); err != nil {
 		fmt.Println(err)
 		fmt.Println(err)
 	}
 	}
@@ -327,17 +325,17 @@ func ExampleFile_SetSheetFormatPr() {
 }
 }
 
 
 func ExampleFile_GetSheetFormatPr() {
 func ExampleFile_GetSheetFormatPr() {
-	f := excelize.NewFile()
+	f := NewFile()
 	const sheet = "Sheet1"
 	const sheet = "Sheet1"
 
 
 	var (
 	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,
 	if err := f.GetSheetFormatPr(sheet,
@@ -374,16 +372,16 @@ func TestSheetFormatPrOptions(t *testing.T) {
 	const sheet = "Sheet1"
 	const sheet = "Sheet1"
 
 
 	testData := []struct {
 	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 {
 	for i, test := range testData {
@@ -392,11 +390,11 @@ func TestSheetFormatPrOptions(t *testing.T) {
 			opt := test.nonDefault
 			opt := test.nonDefault
 			t.Logf("option %T", opt)
 			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
 			// Get the default value
 			assert.NoError(t, f.GetSheetFormatPr(sheet, def), opt)
 			assert.NoError(t, f.GetSheetFormatPr(sheet, def), opt)
 			// Get again and check
 			// Get again and check
@@ -434,26 +432,26 @@ func TestSheetFormatPrOptions(t *testing.T) {
 }
 }
 
 
 func TestSetSheetFormatPr(t *testing.T) {
 func TestSetSheetFormatPr(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	assert.NoError(t, f.GetSheetFormatPr("Sheet1"))
 	assert.NoError(t, f.GetSheetFormatPr("Sheet1"))
 	f.Sheet["xl/worksheets/sheet1.xml"].SheetFormatPr = nil
 	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.
 	// Test set formatting properties on not exists worksheet.
 	assert.EqualError(t, f.SetSheetFormatPr("SheetN"), "sheet SheetN is not exist")
 	assert.EqualError(t, f.SetSheetFormatPr("SheetN"), "sheet SheetN is not exist")
 }
 }
 
 
 func TestGetSheetFormatPr(t *testing.T) {
 func TestGetSheetFormatPr(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	assert.NoError(t, f.GetSheetFormatPr("Sheet1"))
 	assert.NoError(t, f.GetSheetFormatPr("Sheet1"))
 	f.Sheet["xl/worksheets/sheet1.xml"].SheetFormatPr = nil
 	f.Sheet["xl/worksheets/sheet1.xml"].SheetFormatPr = nil
 	var (
 	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",
 	assert.NoError(t, f.GetSheetFormatPr("Sheet1",
 		&baseColWidth,
 		&baseColWidth,

+ 45 - 47
sheetview_test.go

@@ -1,60 +1,58 @@
-package excelize_test
+package excelize
 
 
 import (
 import (
 	"fmt"
 	"fmt"
 	"testing"
 	"testing"
 
 
 	"github.com/stretchr/testify/assert"
 	"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
 	// 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() {
 func ExampleFile_SetSheetViewOptions() {
-	f := excelize.NewFile()
+	f := NewFile()
 	const sheet = "Sheet1"
 	const sheet = "Sheet1"
 
 
 	if err := f.SetSheetViewOptions(sheet, 0,
 	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 {
 	); err != nil {
 		fmt.Println(err)
 		fmt.Println(err)
 	}
 	}
 
 
-	var zoomScale excelize.ZoomScale
+	var zoomScale ZoomScale
 	fmt.Println("Default:")
 	fmt.Println("Default:")
 	fmt.Println("- zoomScale: 80")
 	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)
 		fmt.Println(err)
 	}
 	}
 
 
@@ -65,7 +63,7 @@ func ExampleFile_SetSheetViewOptions() {
 	fmt.Println("Used out of range value:")
 	fmt.Println("Used out of range value:")
 	fmt.Println("- zoomScale:", zoomScale)
 	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)
 		fmt.Println(err)
 	}
 	}
 
 
@@ -87,18 +85,18 @@ func ExampleFile_SetSheetViewOptions() {
 }
 }
 
 
 func ExampleFile_GetSheetViewOptions() {
 func ExampleFile_GetSheetViewOptions() {
-	f := excelize.NewFile()
+	f := NewFile()
 	const sheet = "Sheet1"
 	const sheet = "Sheet1"
 
 
 	var (
 	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,
 	if err := f.GetSheetViewOptions(sheet, 0,
@@ -124,7 +122,7 @@ func ExampleFile_GetSheetViewOptions() {
 	fmt.Println("- zoomScale:", zoomScale)
 	fmt.Println("- zoomScale:", zoomScale)
 	fmt.Println("- topLeftCell:", `"`+topLeftCell+`"`)
 	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)
 		fmt.Println(err)
 	}
 	}
 
 
@@ -132,7 +130,7 @@ func ExampleFile_GetSheetViewOptions() {
 		fmt.Println(err)
 		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)
 		fmt.Println(err)
 	}
 	}
 
 
@@ -140,7 +138,7 @@ func ExampleFile_GetSheetViewOptions() {
 		fmt.Println(err)
 		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)
 		fmt.Println(err)
 	}
 	}
 
 
@@ -170,7 +168,7 @@ func ExampleFile_GetSheetViewOptions() {
 }
 }
 
 
 func TestSheetViewOptionsErrors(t *testing.T) {
 func TestSheetViewOptionsErrors(t *testing.T) {
-	f := excelize.NewFile()
+	f := NewFile()
 	const sheet = "Sheet1"
 	const sheet = "Sheet1"
 
 
 	assert.NoError(t, f.GetSheetViewOptions(sheet, 0))
 	assert.NoError(t, f.GetSheetViewOptions(sheet, 0))

+ 80 - 24
styles.go

@@ -21,6 +21,7 @@ import (
 	"log"
 	"log"
 	"math"
 	"math"
 	"reflect"
 	"reflect"
+	"regexp"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 )
 )
@@ -755,7 +756,7 @@ var currencyNumFmt = map[int]string{
 
 
 // builtInNumFmtFunc defined the format conversion functions map. Partial format
 // builtInNumFmtFunc defined the format conversion functions map. Partial format
 // code doesn't support currently and will return original string.
 // 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,
 	0:  formatToString,
 	1:  formatToInt,
 	1:  formatToInt,
 	2:  formatToFloat,
 	2:  formatToFloat,
@@ -847,14 +848,14 @@ var criteriaType = map[string]string{
 
 
 // formatToString provides a function to return original string by given
 // formatToString provides a function to return original string by given
 // built-in number formats code and cell string.
 // built-in number formats code and cell string.
-func formatToString(i int, v string) string {
+func formatToString(v string, format string) string {
 	return v
 	return v
 }
 }
 
 
 // formatToInt provides a function to convert original string to integer
 // formatToInt provides a function to convert original string to integer
 // format as string type by given built-in number formats code and cell
 // format as string type by given built-in number formats code and cell
 // string.
 // string.
-func formatToInt(i int, v string) string {
+func formatToInt(v string, format string) string {
 	f, err := strconv.ParseFloat(v, 64)
 	f, err := strconv.ParseFloat(v, 64)
 	if err != nil {
 	if err != nil {
 		return v
 		return v
@@ -865,7 +866,7 @@ func formatToInt(i int, v string) string {
 // formatToFloat provides a function to convert original string to float
 // formatToFloat provides a function to convert original string to float
 // format as string type by given built-in number formats code and cell
 // format as string type by given built-in number formats code and cell
 // string.
 // string.
-func formatToFloat(i int, v string) string {
+func formatToFloat(v string, format string) string {
 	f, err := strconv.ParseFloat(v, 64)
 	f, err := strconv.ParseFloat(v, 64)
 	if err != nil {
 	if err != nil {
 		return v
 		return v
@@ -875,7 +876,7 @@ func formatToFloat(i int, v string) string {
 
 
 // formatToA provides a function to convert original string to special format
 // formatToA provides a function to convert original string to special format
 // as string type by given built-in number formats code and cell string.
 // 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)
 	f, err := strconv.ParseFloat(v, 64)
 	if err != nil {
 	if err != nil {
 		return v
 		return v
@@ -890,7 +891,7 @@ func formatToA(i int, v string) string {
 
 
 // formatToB provides a function to convert original string to special format
 // formatToB provides a function to convert original string to special format
 // as string type by given built-in number formats code and cell string.
 // 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)
 	f, err := strconv.ParseFloat(v, 64)
 	if err != nil {
 	if err != nil {
 		return v
 		return v
@@ -903,7 +904,7 @@ func formatToB(i int, v string) string {
 
 
 // formatToC provides a function to convert original string to special format
 // formatToC provides a function to convert original string to special format
 // as string type by given built-in number formats code and cell string.
 // 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)
 	f, err := strconv.ParseFloat(v, 64)
 	if err != nil {
 	if err != nil {
 		return v
 		return v
@@ -914,7 +915,7 @@ func formatToC(i int, v string) string {
 
 
 // formatToD provides a function to convert original string to special format
 // formatToD provides a function to convert original string to special format
 // as string type by given built-in number formats code and cell string.
 // 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)
 	f, err := strconv.ParseFloat(v, 64)
 	if err != nil {
 	if err != nil {
 		return v
 		return v
@@ -925,7 +926,7 @@ func formatToD(i int, v string) string {
 
 
 // formatToE provides a function to convert original string to special format
 // formatToE provides a function to convert original string to special format
 // as string type by given built-in number formats code and cell string.
 // 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)
 	f, err := strconv.ParseFloat(v, 64)
 	if err != nil {
 	if err != nil {
 		return v
 		return v
@@ -933,6 +934,8 @@ func formatToE(i int, v string) string {
 	return fmt.Sprintf("%.e", f)
 	return fmt.Sprintf("%.e", f)
 }
 }
 
 
+var dateTimeFormatsCache = map[string]string{}
+
 // parseTime provides a function to returns a string parsed using time.Time.
 // parseTime provides a function to returns a string parsed using time.Time.
 // Replace Excel placeholders with Go time placeholders. For example, replace
 // 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
 // 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,
 // arbitrary characters unused in Excel Date formats, and then at the end,
 // turn them to what they should actually be. Based off:
 // turn them to what they should actually be. Based off:
 // http://www.ozgrid.com/Excel/CustomFormats.htm
 // 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 {
 	if err != nil {
 		return v
 		return v
 	}
 	}
 	val := timeFromExcelTime(f, false)
 	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 }{
 	replacements := []struct{ xltime, gotime string }{
+		{"YYYY", "2006"},
+		{"YY", "06"},
+		{"MM", "01"},
+		{"M", "1"},
+		{"DD", "02"},
+		{"D", "2"},
 		{"yyyy", "2006"},
 		{"yyyy", "2006"},
 		{"yy", "06"},
 		{"yy", "06"},
 		{"mmmm", "%%%%"},
 		{"mmmm", "%%%%"},
@@ -962,38 +996,59 @@ func parseTime(i int, v string) string {
 		{"mmm", "Jan"},
 		{"mmm", "Jan"},
 		{"mmss", "0405"},
 		{"mmss", "0405"},
 		{"ss", "05"},
 		{"ss", "05"},
+		{"s", "5"},
 		{"mm:", "04:"},
 		{"mm:", "04:"},
 		{":mm", ":04"},
 		{":mm", ":04"},
+		{"m:", "4:"},
+		{":m", ":4"},
 		{"mm", "01"},
 		{"mm", "01"},
 		{"am/pm", "pm"},
 		{"am/pm", "pm"},
 		{"m/", "1/"},
 		{"m/", "1/"},
 		{"%%%%", "January"},
 		{"%%%%", "January"},
 		{"&&&&", "Monday"},
 		{"&&&&", "Monday"},
 	}
 	}
+
+	replacementsGlobal := []struct{ xltime, gotime string }{
+		{"\\-", "-"},
+		{"\\ ", " "},
+		{"\\.", "."},
+		{"\\", ""},
+	}
 	// It is the presence of the "am/pm" indicator that determines if this is
 	// 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.
 	// a 12 hour or 24 hours time format, not the number of 'h' characters.
 	if is12HourTime(format) {
 	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 {
 	} 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 {
 	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
 	// If the hour is optional, strip it out, along with the possible dangling
 	// colon that would remain.
 	// colon that would remain.
 	if val.Hour() < 1 {
 	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 {
 	} 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.
 // 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.
 // setCustomNumFmt provides a function to set custom number format code.
 func setCustomNumFmt(styleSheet *xlsxStyleSheet, style *Style) int {
 func setCustomNumFmt(styleSheet *xlsxStyleSheet, style *Style) int {
 	nf := xlsxNumFmt{FormatCode: *style.CustomNumFmt}
 	nf := xlsxNumFmt{FormatCode: *style.CustomNumFmt}
+
 	if styleSheet.NumFmts != nil {
 	if styleSheet.NumFmts != nil {
 		nf.NumFmtID = styleSheet.NumFmts.NumFmt[len(styleSheet.NumFmts.NumFmt)-1].NumFmtID + 1
 		nf.NumFmtID = styleSheet.NumFmts.NumFmt[len(styleSheet.NumFmts.NumFmt)-1].NumFmtID + 1
 		styleSheet.NumFmts.NumFmt = append(styleSheet.NumFmts.NumFmt, &nf)
 		styleSheet.NumFmts.NumFmt = append(styleSheet.NumFmts.NumFmt, &nf)

+ 46 - 0
styles_test.go

@@ -201,10 +201,44 @@ func TestNewStyle(t *testing.T) {
 	assert.NoError(t, err)
 	assert.NoError(t, err)
 	_, err = f.NewStyle(Style{})
 	_, err = f.NewStyle(Style{})
 	assert.EqualError(t, err, "invalid parameter type")
 	assert.EqualError(t, err, "invalid parameter type")
+
 	_, err = f.NewStyle(&Style{Font: &Font{Family: strings.Repeat("s", MaxFontFamilyLength+1)}})
 	_, 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")
 	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}})
 	_, err = f.NewStyle(&Style{Font: &Font{Size: MaxFontSize + 1}})
 	assert.EqualError(t, err, "font size must be between 1 and 409 points")
 	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) {
 func TestGetDefaultFont(t *testing.T) {
@@ -250,3 +284,15 @@ func TestGetStyleID(t *testing.T) {
 func TestGetFillID(t *testing.T) {
 func TestGetFillID(t *testing.T) {
 	assert.Equal(t, -1, getFillID(NewFile().stylesReader(), &Style{Fill: Fill{Type: "unknown"}}))
 	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"))
+
+}