cell.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. package xlsx
  2. import (
  3. "fmt"
  4. "math"
  5. "strconv"
  6. "strings"
  7. "time"
  8. )
  9. // CellType is an int type for storing metadata about the data type in the cell.
  10. type CellType int
  11. // Known types for cell values.
  12. const (
  13. CellTypeString CellType = iota
  14. CellTypeFormula
  15. CellTypeNumeric
  16. CellTypeBool
  17. CellTypeInline
  18. CellTypeError
  19. CellTypeDate
  20. CellTypeGeneral
  21. )
  22. func (ct CellType) Ptr() *CellType {
  23. return &ct
  24. }
  25. // Cell is a high level structure intended to provide user access to
  26. // the contents of Cell within an xlsx.Row.
  27. type Cell struct {
  28. Row *Row
  29. Value string
  30. formula string
  31. style *Style
  32. NumFmt string
  33. date1904 bool
  34. Hidden bool
  35. HMerge int
  36. VMerge int
  37. cellType CellType
  38. }
  39. // CellInterface defines the public API of the Cell.
  40. type CellInterface interface {
  41. String() string
  42. FormattedValue() string
  43. }
  44. // NewCell creates a cell and adds it to a row.
  45. func NewCell(r *Row) *Cell {
  46. return &Cell{Row: r}
  47. }
  48. // Merge with other cells, horizontally and/or vertically.
  49. func (c *Cell) Merge(hcells, vcells int) {
  50. c.HMerge = hcells
  51. c.VMerge = vcells
  52. }
  53. // Type returns the CellType of a cell. See CellType constants for more details.
  54. func (c *Cell) Type() CellType {
  55. return c.cellType
  56. }
  57. // SetString sets the value of a cell to a string.
  58. func (c *Cell) SetString(s string) {
  59. c.Value = s
  60. c.formula = ""
  61. c.cellType = CellTypeString
  62. }
  63. // String returns the value of a Cell as a string. If you'd like to
  64. // see errors returned from formatting then please use
  65. // Cell.FormattedValue() instead.
  66. func (c *Cell) String() string {
  67. // To preserve the String() interface we'll throw away errors.
  68. // Not that using FormattedValue is therefore strongly
  69. // preferred.
  70. value, _ := c.FormattedValue()
  71. return value
  72. }
  73. // SetFloat sets the value of a cell to a float.
  74. func (c *Cell) SetFloat(n float64) {
  75. c.SetValue(n)
  76. }
  77. //GetTime returns the value of a Cell as a time.Time
  78. func (c *Cell) GetTime(date1904 bool) (t time.Time, err error) {
  79. f, err := c.Float()
  80. if err != nil {
  81. return t, err
  82. }
  83. return TimeFromExcelTime(f, date1904), nil
  84. }
  85. /*
  86. The following are samples of format samples.
  87. * "0.00e+00"
  88. * "0", "#,##0"
  89. * "0.00", "#,##0.00", "@"
  90. * "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)"
  91. * "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)"
  92. * "0%", "0.00%"
  93. * "0.00e+00", "##0.0e+0"
  94. */
  95. // SetFloatWithFormat sets the value of a cell to a float and applies
  96. // formatting to the cell.
  97. func (c *Cell) SetFloatWithFormat(n float64, format string) {
  98. // beauty the output when the float is small enough
  99. if n != 0 && n < 0.00001 {
  100. c.Value = strconv.FormatFloat(n, 'e', -1, 64)
  101. } else {
  102. c.Value = strconv.FormatFloat(n, 'f', -1, 64)
  103. }
  104. c.NumFmt = format
  105. c.formula = ""
  106. c.cellType = CellTypeNumeric
  107. }
  108. var timeLocationUTC, _ = time.LoadLocation("UTC")
  109. func TimeToUTCTime(t time.Time) time.Time {
  110. return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), timeLocationUTC)
  111. }
  112. func TimeToExcelTime(t time.Time) float64 {
  113. return float64(t.UnixNano())/8.64e13 + 25569.0
  114. }
  115. // DateTimeOptions are additional options for exporting times
  116. type DateTimeOptions struct {
  117. // Location allows calculating times in other timezones/locations
  118. Location *time.Location
  119. // ExcelTimeFormat is the string you want excel to use to format the datetime
  120. ExcelTimeFormat string
  121. }
  122. var (
  123. DefaultDateFormat = builtInNumFmt[14]
  124. DefaultDateTimeFormat = builtInNumFmt[22]
  125. DefaultDateOptions = DateTimeOptions{
  126. Location: timeLocationUTC,
  127. ExcelTimeFormat: DefaultDateFormat,
  128. }
  129. DefaultDateTimeOptions = DateTimeOptions{
  130. Location: timeLocationUTC,
  131. ExcelTimeFormat: DefaultDateTimeFormat,
  132. }
  133. )
  134. // SetDate sets the value of a cell to a float.
  135. func (c *Cell) SetDate(t time.Time) {
  136. c.SetDateWithOptions(t, DefaultDateOptions)
  137. }
  138. func (c *Cell) SetDateTime(t time.Time) {
  139. c.SetDateWithOptions(t, DefaultDateTimeOptions)
  140. }
  141. // SetDateWithOptions allows for more granular control when exporting dates and times
  142. func (c *Cell) SetDateWithOptions(t time.Time, options DateTimeOptions) {
  143. _, offset := t.In(options.Location).Zone()
  144. t = time.Unix(t.Unix()+int64(offset), 0)
  145. c.SetDateTimeWithFormat(TimeToExcelTime(t.In(timeLocationUTC)), options.ExcelTimeFormat)
  146. }
  147. func (c *Cell) SetDateTimeWithFormat(n float64, format string) {
  148. c.Value = strconv.FormatFloat(n, 'f', -1, 64)
  149. c.NumFmt = format
  150. c.formula = ""
  151. c.cellType = CellTypeDate
  152. }
  153. // Float returns the value of cell as a number.
  154. func (c *Cell) Float() (float64, error) {
  155. f, err := strconv.ParseFloat(c.Value, 64)
  156. if err != nil {
  157. return math.NaN(), err
  158. }
  159. return f, nil
  160. }
  161. // SetInt64 sets a cell's value to a 64-bit integer.
  162. func (c *Cell) SetInt64(n int64) {
  163. c.SetValue(n)
  164. }
  165. // Int64 returns the value of cell as 64-bit integer.
  166. func (c *Cell) Int64() (int64, error) {
  167. f, err := strconv.ParseInt(c.Value, 10, 64)
  168. if err != nil {
  169. return -1, err
  170. }
  171. return f, nil
  172. }
  173. // SetInt sets a cell's value to an integer.
  174. func (c *Cell) SetInt(n int) {
  175. c.SetValue(n)
  176. }
  177. // SetInt sets a cell's value to an integer.
  178. func (c *Cell) SetValue(n interface{}) {
  179. switch t := n.(type) {
  180. case time.Time:
  181. c.SetDateTime(n.(time.Time))
  182. return
  183. case int, int8, int16, int32, int64, float32, float64:
  184. c.setGeneral(fmt.Sprintf("%v", n))
  185. case string:
  186. c.SetString(t)
  187. case []byte:
  188. c.SetString(string(t))
  189. case nil:
  190. c.SetString("")
  191. default:
  192. c.SetString(fmt.Sprintf("%v", n))
  193. }
  194. }
  195. // SetInt sets a cell's value to an integer.
  196. func (c *Cell) setGeneral(s string) {
  197. c.Value = s
  198. c.NumFmt = builtInNumFmt[builtInNumFmtIndex_GENERAL]
  199. c.formula = ""
  200. c.cellType = CellTypeGeneral
  201. }
  202. // Int returns the value of cell as integer.
  203. // Has max 53 bits of precision
  204. // See: float64(int64(math.MaxInt))
  205. func (c *Cell) Int() (int, error) {
  206. f, err := strconv.ParseFloat(c.Value, 64)
  207. if err != nil {
  208. return -1, err
  209. }
  210. return int(f), nil
  211. }
  212. // SetBool sets a cell's value to a boolean.
  213. func (c *Cell) SetBool(b bool) {
  214. if b {
  215. c.Value = "1"
  216. } else {
  217. c.Value = "0"
  218. }
  219. c.cellType = CellTypeBool
  220. }
  221. // Bool returns a boolean from a cell's value.
  222. // TODO: Determine if the current return value is
  223. // appropriate for types other than CellTypeBool.
  224. func (c *Cell) Bool() bool {
  225. // If bool, just return the value.
  226. if c.cellType == CellTypeBool {
  227. return c.Value == "1"
  228. }
  229. // If numeric, base it on a non-zero.
  230. if c.cellType == CellTypeNumeric || c.cellType == CellTypeGeneral {
  231. return c.Value != "0"
  232. }
  233. // Return whether there's an empty string.
  234. return c.Value != ""
  235. }
  236. // SetFormula sets the format string for a cell.
  237. func (c *Cell) SetFormula(formula string) {
  238. c.formula = formula
  239. c.cellType = CellTypeFormula
  240. }
  241. // Formula returns the formula string for the cell.
  242. func (c *Cell) Formula() string {
  243. return c.formula
  244. }
  245. // GetStyle returns the Style associated with a Cell
  246. func (c *Cell) GetStyle() *Style {
  247. if c.style == nil {
  248. c.style = NewStyle()
  249. }
  250. return c.style
  251. }
  252. // SetStyle sets the style of a cell.
  253. func (c *Cell) SetStyle(style *Style) {
  254. c.style = style
  255. }
  256. // GetNumberFormat returns the number format string for a cell.
  257. func (c *Cell) GetNumberFormat() string {
  258. return c.NumFmt
  259. }
  260. func (c *Cell) formatToFloat(format string) (string, error) {
  261. f, err := strconv.ParseFloat(c.Value, 64)
  262. if err != nil {
  263. return c.Value, err
  264. }
  265. return fmt.Sprintf(format, f), nil
  266. }
  267. func (c *Cell) formatToInt(format string) (string, error) {
  268. f, err := strconv.ParseFloat(c.Value, 64)
  269. if err != nil {
  270. return c.Value, err
  271. }
  272. return fmt.Sprintf(format, int(f)), nil
  273. }
  274. // FormattedValue returns a value, and possibly an error condition
  275. // from a Cell. If it is possible to apply a format to the cell
  276. // value, it will do so, if not then an error will be returned, along
  277. // with the raw value of the Cell.
  278. func (c *Cell) FormattedValue() (string, error) {
  279. var numberFormat = c.GetNumberFormat()
  280. if isTimeFormat(numberFormat) {
  281. return parseTime(c)
  282. }
  283. switch numberFormat {
  284. case builtInNumFmt[builtInNumFmtIndex_GENERAL], builtInNumFmt[builtInNumFmtIndex_STRING]:
  285. return c.Value, nil
  286. case builtInNumFmt[builtInNumFmtIndex_INT], "#,##0":
  287. return c.formatToInt("%d")
  288. case builtInNumFmt[builtInNumFmtIndex_FLOAT], "#,##0.00":
  289. return c.formatToFloat("%.2f")
  290. case "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)":
  291. f, err := strconv.ParseFloat(c.Value, 64)
  292. if err != nil {
  293. return c.Value, err
  294. }
  295. if f < 0 {
  296. i := int(math.Abs(f))
  297. return fmt.Sprintf("(%d)", i), nil
  298. }
  299. i := int(f)
  300. return fmt.Sprintf("%d", i), nil
  301. case "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)":
  302. f, err := strconv.ParseFloat(c.Value, 64)
  303. if err != nil {
  304. return c.Value, err
  305. }
  306. if f < 0 {
  307. return fmt.Sprintf("(%.2f)", f), nil
  308. }
  309. return fmt.Sprintf("%.2f", f), nil
  310. case "0%":
  311. f, err := strconv.ParseFloat(c.Value, 64)
  312. if err != nil {
  313. return c.Value, err
  314. }
  315. f = f * 100
  316. return fmt.Sprintf("%d%%", int(f)), nil
  317. case "0.00%":
  318. f, err := strconv.ParseFloat(c.Value, 64)
  319. if err != nil {
  320. return c.Value, err
  321. }
  322. f = f * 100
  323. return fmt.Sprintf("%.2f%%", f), nil
  324. case "0.00e+00", "##0.0e+0":
  325. return c.formatToFloat("%e")
  326. }
  327. return c.Value, nil
  328. }
  329. // parseTime returns a string parsed using time.Time
  330. func parseTime(c *Cell) (string, error) {
  331. f, err := strconv.ParseFloat(c.Value, 64)
  332. if err != nil {
  333. return c.Value, err
  334. }
  335. val := TimeFromExcelTime(f, c.date1904)
  336. format := c.GetNumberFormat()
  337. // Replace Excel placeholders with Go time placeholders.
  338. // For example, replace yyyy with 2006. These are in a specific order,
  339. // due to the fact that m is used in month, minute, and am/pm. It would
  340. // be easier to fix that with regular expressions, but if it's possible
  341. // to keep this simple it would be easier to maintain.
  342. // Full-length month and days (e.g. March, Tuesday) have letters in them that would be replaced
  343. // by other characters below (such as the 'h' in March, or the 'd' in Tuesday) below.
  344. // First we convert them to arbitrary characters unused in Excel Date formats, and then at the end,
  345. // turn them to what they should actually be.
  346. // Based off: http://www.ozgrid.com/Excel/CustomFormats.htm
  347. replacements := []struct{ xltime, gotime string }{
  348. {"yyyy", "2006"},
  349. {"yy", "06"},
  350. {"mmmm", "%%%%"},
  351. {"dddd", "&&&&"},
  352. {"dd", "02"},
  353. {"d", "2"},
  354. {"mmm", "Jan"},
  355. {"mmss", "0405"},
  356. {"ss", "05"},
  357. {"mm:", "04:"},
  358. {":mm", ":04"},
  359. {"mm", "01"},
  360. {"am/pm", "pm"},
  361. {"m/", "1/"},
  362. {"%%%%", "January"},
  363. {"&&&&", "Monday"},
  364. }
  365. // It is the presence of the "am/pm" indicator that determins
  366. // if this is a 12 hour or 24 hours time format, not the
  367. // number of 'h' characters.
  368. if is12HourTime(format) {
  369. format = strings.Replace(format, "hh", "03", 1)
  370. format = strings.Replace(format, "h", "3", 1)
  371. } else {
  372. format = strings.Replace(format, "hh", "15", 1)
  373. format = strings.Replace(format, "h", "15", 1)
  374. }
  375. for _, repl := range replacements {
  376. format = strings.Replace(format, repl.xltime, repl.gotime, 1)
  377. }
  378. // If the hour is optional, strip it out, along with the
  379. // possible dangling colon that would remain.
  380. if val.Hour() < 1 {
  381. format = strings.Replace(format, "]:", "]", 1)
  382. format = strings.Replace(format, "[03]", "", 1)
  383. format = strings.Replace(format, "[3]", "", 1)
  384. format = strings.Replace(format, "[15]", "", 1)
  385. } else {
  386. format = strings.Replace(format, "[3]", "3", 1)
  387. format = strings.Replace(format, "[15]", "15", 1)
  388. }
  389. return val.Format(format), nil
  390. }
  391. // isTimeFormat checks whether an Excel format string represents
  392. // a time.Time.
  393. func isTimeFormat(format string) bool {
  394. dateParts := []string{
  395. "yy", "hh", "h", "am/pm", "AM/PM", "A/P", "a/p", "ss", "mm", ":",
  396. }
  397. for _, part := range dateParts {
  398. if strings.Contains(format, part) {
  399. return true
  400. }
  401. }
  402. return false
  403. }
  404. // is12HourTime checks whether an Excel time format string is a 12
  405. // hours form.
  406. func is12HourTime(format string) bool {
  407. return strings.Contains(format, "am/pm") || strings.Contains(format, "AM/PM") || strings.Contains(format, "a/p") || strings.Contains(format, "A/P")
  408. }