Skip to content

Commit f1d1a5d

Browse files
committed
This closes #2004, support apply number format for time and duration cell value
- Add unit tests - Update dependencies modules
1 parent b23e5a2 commit f1d1a5d

File tree

6 files changed

+71
-17
lines changed

6 files changed

+71
-17
lines changed

cell.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ func (f *File) SetCellValue(sheet, cell string, value interface{}) error {
144144
if err != nil {
145145
return err
146146
}
147-
err = f.setDefaultTimeStyle(sheet, cell, 21)
147+
err = f.setDefaultTimeStyle(sheet, cell, getDurationNumFmt(v))
148148
case time.Time:
149149
err = f.setCellTimeFunc(sheet, cell, v)
150150
case bool:
@@ -256,7 +256,7 @@ func (f *File) setCellTimeFunc(sheet, cell string, value time.Time) error {
256256
return err
257257
}
258258
if isNum {
259-
_ = f.setDefaultTimeStyle(sheet, cell, 22)
259+
_ = f.setDefaultTimeStyle(sheet, cell, getTimeNumFmt(value))
260260
}
261261
return err
262262
}

cell_test.go

+24-1
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,29 @@ func TestSetCellValue(t *testing.T) {
305305
assert.NoError(t, err)
306306
assert.Equal(t, expected, val)
307307
}
308+
// Test set cell value with time duration
309+
for val, expected := range map[time.Duration]string{
310+
time.Hour*21 + time.Minute*51 + time.Second*44: "21:51:44",
311+
time.Hour*21 + time.Minute*50: "21:50",
312+
time.Hour*24 + time.Minute*51 + time.Second*44: "24:51:44",
313+
time.Hour*24 + time.Minute*50: "24:50:00",
314+
} {
315+
assert.NoError(t, f.SetCellValue("Sheet1", "A1", val))
316+
val, err := f.GetCellValue("Sheet1", "A1")
317+
assert.NoError(t, err)
318+
assert.Equal(t, expected, val)
319+
}
320+
// Test set cell value with time
321+
for val, expected := range map[time.Time]string{
322+
time.Date(2024, time.October, 1, 0, 0, 0, 0, time.UTC): "Oct-24",
323+
time.Date(2024, time.October, 10, 0, 0, 0, 0, time.UTC): "10-10-24",
324+
time.Date(2024, time.October, 10, 12, 0, 0, 0, time.UTC): "10/10/24 12:00",
325+
} {
326+
assert.NoError(t, f.SetCellValue("Sheet1", "A1", val))
327+
val, err := f.GetCellValue("Sheet1", "A1")
328+
assert.NoError(t, err)
329+
assert.Equal(t, expected, val)
330+
}
308331
}
309332

310333
func TestSetCellValues(t *testing.T) {
@@ -314,7 +337,7 @@ func TestSetCellValues(t *testing.T) {
314337

315338
v, err := f.GetCellValue("Sheet1", "A1")
316339
assert.NoError(t, err)
317-
assert.Equal(t, v, "12/31/10 00:00")
340+
assert.Equal(t, v, "12-31-10")
318341

319342
// Test date value lower than min date supported by Excel
320343
err = f.SetCellValue("Sheet1", "A1", time.Date(1600, time.December, 31, 0, 0, 0, 0, time.UTC))

date.go

+28
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,31 @@ func formatYear(y int) int {
214214
}
215215
return y
216216
}
217+
218+
// getDurationNumFmt returns most simplify numbers format code for time
219+
// duration type cell value by given worksheet name, cell reference and number.
220+
func getDurationNumFmt(d time.Duration) int {
221+
if d >= time.Hour*24 {
222+
return 46
223+
}
224+
// Whole minutes
225+
if d.Minutes() == float64(int(d.Minutes())) {
226+
return 20
227+
}
228+
return 21
229+
}
230+
231+
// getTimeNumFmt returns most simplify numbers format code for time type cell
232+
// value by given worksheet name, cell reference and number.
233+
func getTimeNumFmt(t time.Time) int {
234+
nextMonth := t.AddDate(0, 1, 0)
235+
// Whole months
236+
if t.Day() == 1 && nextMonth.Day() == 1 {
237+
return 17
238+
}
239+
// Whole days
240+
if t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 && t.Nanosecond() == 0 {
241+
return 14
242+
}
243+
return 22
244+
}

excelize.go

+8-5
Original file line numberDiff line numberDiff line change
@@ -242,15 +242,18 @@ func (f *File) xmlNewDecoder(rdr io.Reader) (ret *xml.Decoder) {
242242
// time.Time type cell value by given worksheet name, cell reference and
243243
// number format code.
244244
func (f *File) setDefaultTimeStyle(sheet, cell string, format int) error {
245-
s, err := f.GetCellStyle(sheet, cell)
245+
styleIdx, err := f.GetCellStyle(sheet, cell)
246246
if err != nil {
247247
return err
248248
}
249-
if s == 0 {
250-
style, _ := f.NewStyle(&Style{NumFmt: format})
251-
err = f.SetCellStyle(sheet, cell, cell, style)
249+
if styleIdx == 0 {
250+
styleIdx, _ = f.NewStyle(&Style{NumFmt: format})
251+
} else {
252+
style, _ := f.GetStyle(styleIdx)
253+
style.NumFmt = format
254+
styleIdx, _ = f.NewStyle(style)
252255
}
253-
return err
256+
return f.SetCellStyle(sheet, cell, cell, styleIdx)
254257
}
255258

256259
// workSheetReader provides a function to get the pointer to the structure

go.mod

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ require (
88
github.com/stretchr/testify v1.8.4
99
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d
1010
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7
11-
golang.org/x/crypto v0.27.0
11+
golang.org/x/crypto v0.28.0
1212
golang.org/x/image v0.18.0
13-
golang.org/x/net v0.29.0
14-
golang.org/x/text v0.18.0
13+
golang.org/x/net v0.30.0
14+
golang.org/x/text v0.19.0
1515
)
1616

1717
require (

go.sum

+6-6
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d h1:llb0neMWDQe87IzJLS4Ci7
1515
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
1616
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 h1:hPVCafDV85blFTabnqKgNhDCkJX25eik94Si9cTER4A=
1717
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
18-
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
19-
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
18+
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
19+
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
2020
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
2121
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
22-
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
23-
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
24-
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
25-
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
22+
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
23+
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
24+
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
25+
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
2626
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
2727
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
2828
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

0 commit comments

Comments
 (0)