cell.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  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. // Cell is a high level structure intended to provide user access to
  23. // the contents of Cell within an xlsx.Row.
  24. type Cell struct {
  25. Row *Row
  26. Value string
  27. formula string
  28. style *Style
  29. numFmt string
  30. date1904 bool
  31. Hidden bool
  32. HMerge int
  33. VMerge int
  34. cellType CellType
  35. }
  36. // CellInterface defines the public API of the Cell.
  37. type CellInterface interface {
  38. String() string
  39. FormattedValue() string
  40. }
  41. // NewCell creates a cell and adds it to a row.
  42. func NewCell(r *Row) *Cell {
  43. return &Cell{Row: r}
  44. }
  45. // Merge with other cells, horizontally and/or vertically.
  46. func (c *Cell) Merge(hcells, vcells int) {
  47. c.HMerge = hcells
  48. c.VMerge = vcells
  49. }
  50. // Type returns the CellType of a cell. See CellType constants for more details.
  51. func (c *Cell) Type() CellType {
  52. return c.cellType
  53. }
  54. // SetString sets the value of a cell to a string.
  55. func (c *Cell) SetString(s string) {
  56. c.Value = s
  57. c.formula = ""
  58. c.cellType = CellTypeString
  59. }
  60. // String returns the value of a Cell as a string.
  61. func (c *Cell) String() string {
  62. return c.FormattedValue()
  63. }
  64. // SetFloat sets the value of a cell to a float.
  65. func (c *Cell) SetFloat(n float64) {
  66. c.SetFloatWithFormat(n, builtInNumFmt[builtInNumFmtIndex_GENERAL])
  67. }
  68. /*
  69. The following are samples of format samples.
  70. * "0.00e+00"
  71. * "0", "#,##0"
  72. * "0.00", "#,##0.00", "@"
  73. * "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)"
  74. * "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)"
  75. * "0%", "0.00%"
  76. * "0.00e+00", "##0.0e+0"
  77. */
  78. // SetFloatWithFormat sets the value of a cell to a float and applies
  79. // formatting to the cell.
  80. func (c *Cell) SetFloatWithFormat(n float64, format string) {
  81. // beauty the output when the float is small enough
  82. if n != 0 && n < 0.00001 {
  83. c.Value = strconv.FormatFloat(n, 'e', -1, 64)
  84. } else {
  85. c.Value = strconv.FormatFloat(n, 'f', -1, 64)
  86. }
  87. c.numFmt = format
  88. c.formula = ""
  89. c.cellType = CellTypeNumeric
  90. }
  91. var timeLocationUTC *time.Location
  92. func init() {
  93. timeLocationUTC, _ = time.LoadLocation("UTC")
  94. }
  95. func timeToUTCTime(t time.Time) time.Time {
  96. return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), timeLocationUTC)
  97. }
  98. func timeToExcelTime(t time.Time) float64 {
  99. return float64(t.Unix())/86400.0 + 25569.0
  100. }
  101. // SetDate sets the value of a cell to a float.
  102. func (c *Cell) SetDate(t time.Time) {
  103. c.SetDateTimeWithFormat(float64(int64(timeToExcelTime(timeToUTCTime(t)))), builtInNumFmt[14])
  104. }
  105. func (c *Cell) SetDateTime(t time.Time) {
  106. c.SetDateTimeWithFormat(timeToExcelTime(timeToUTCTime(t)), builtInNumFmt[14])
  107. }
  108. func (c *Cell) SetDateTimeWithFormat(n float64, format string) {
  109. c.Value = strconv.FormatFloat(n, 'f', -1, 64)
  110. c.numFmt = format
  111. c.formula = ""
  112. c.cellType = CellTypeDate
  113. }
  114. // Float returns the value of cell as a number.
  115. func (c *Cell) Float() (float64, error) {
  116. f, err := strconv.ParseFloat(c.Value, 64)
  117. if err != nil {
  118. return math.NaN(), err
  119. }
  120. return f, nil
  121. }
  122. // SetInt64 sets a cell's value to a 64-bit integer.
  123. func (c *Cell) SetInt64(n int64) {
  124. c.Value = fmt.Sprintf("%d", n)
  125. c.numFmt = builtInNumFmt[builtInNumFmtIndex_INT]
  126. c.formula = ""
  127. c.cellType = CellTypeNumeric
  128. }
  129. // Int64 returns the value of cell as 64-bit integer.
  130. func (c *Cell) Int64() (int64, error) {
  131. f, err := strconv.ParseInt(c.Value, 10, 64)
  132. if err != nil {
  133. return -1, err
  134. }
  135. return f, nil
  136. }
  137. // SetInt sets a cell's value to an integer.
  138. func (c *Cell) SetInt(n int) {
  139. c.Value = fmt.Sprintf("%d", n)
  140. c.numFmt = builtInNumFmt[builtInNumFmtIndex_INT]
  141. c.formula = ""
  142. c.cellType = CellTypeNumeric
  143. }
  144. // SetInt sets a cell's value to an integer.
  145. func (c *Cell) SetValue(n interface{}) {
  146. var s string
  147. switch n.(type) {
  148. case time.Time:
  149. c.SetDateTime(n.(time.Time))
  150. return
  151. case int:
  152. c.setGeneral(fmt.Sprintf("%v", n))
  153. return
  154. case int32:
  155. c.setGeneral(fmt.Sprintf("%v", n))
  156. return
  157. case int64:
  158. c.setGeneral(fmt.Sprintf("%v", n))
  159. return
  160. case float32:
  161. c.setGeneral(fmt.Sprintf("%v", n))
  162. return
  163. case float64:
  164. c.setGeneral(fmt.Sprintf("%v", n))
  165. return
  166. case string:
  167. s = n.(string)
  168. case []byte:
  169. s = string(n.([]byte))
  170. case nil:
  171. s = ""
  172. default:
  173. s = fmt.Sprintf("%v", n)
  174. }
  175. c.SetString(s)
  176. }
  177. // SetInt sets a cell's value to an integer.
  178. func (c *Cell) setGeneral(s string) {
  179. c.Value = s
  180. c.numFmt = builtInNumFmt[builtInNumFmtIndex_GENERAL]
  181. c.formula = ""
  182. c.cellType = CellTypeGeneral
  183. }
  184. // Int returns the value of cell as integer.
  185. // Has max 53 bits of precision
  186. // See: float64(int64(math.MaxInt))
  187. func (c *Cell) Int() (int, error) {
  188. f, err := strconv.ParseFloat(c.Value, 64)
  189. if err != nil {
  190. return -1, err
  191. }
  192. return int(f), nil
  193. }
  194. // SetBool sets a cell's value to a boolean.
  195. func (c *Cell) SetBool(b bool) {
  196. if b {
  197. c.Value = "1"
  198. } else {
  199. c.Value = "0"
  200. }
  201. c.cellType = CellTypeBool
  202. }
  203. // Bool returns a boolean from a cell's value.
  204. // TODO: Determine if the current return value is
  205. // appropriate for types other than CellTypeBool.
  206. func (c *Cell) Bool() bool {
  207. // If bool, just return the value.
  208. if c.cellType == CellTypeBool {
  209. return c.Value == "1"
  210. }
  211. // If numeric, base it on a non-zero.
  212. if c.cellType == CellTypeNumeric {
  213. return c.Value != "0"
  214. }
  215. // Return whether there's an empty string.
  216. return c.Value != ""
  217. }
  218. // SetFormula sets the format string for a cell.
  219. func (c *Cell) SetFormula(formula string) {
  220. c.formula = formula
  221. c.cellType = CellTypeFormula
  222. }
  223. // Formula returns the formula string for the cell.
  224. func (c *Cell) Formula() string {
  225. return c.formula
  226. }
  227. // GetStyle returns the Style associated with a Cell
  228. func (c *Cell) GetStyle() *Style {
  229. if c.style == nil {
  230. c.style = NewStyle()
  231. }
  232. return c.style
  233. }
  234. // SetStyle sets the style of a cell.
  235. func (c *Cell) SetStyle(style *Style) {
  236. c.style = style
  237. }
  238. // GetNumberFormat returns the number format string for a cell.
  239. func (c *Cell) GetNumberFormat() string {
  240. return c.numFmt
  241. }
  242. func (c *Cell) formatToFloat(format string) (string, error) {
  243. f, err := strconv.ParseFloat(c.Value, 64)
  244. if err != nil {
  245. return c.Value, err
  246. }
  247. return fmt.Sprintf(format, f), nil
  248. }
  249. func (c *Cell) formatToInt(format string) (string, error) {
  250. f, err := strconv.ParseFloat(c.Value, 64)
  251. if err != nil {
  252. return c.Value, err
  253. }
  254. return fmt.Sprintf(format, int(f)), nil
  255. }
  256. // SafeFormattedValue returns a value, and possibly an error condition
  257. // from a Cell. If it is possible to apply a format to the cell
  258. // value, it will do so, if not then an error will be returned, along
  259. // with the raw value of the Cell.
  260. func (c *Cell) SafeFormattedValue() (string, error) {
  261. var numberFormat = c.GetNumberFormat()
  262. if isTimeFormat(numberFormat) {
  263. return parseTime(c)
  264. }
  265. switch numberFormat {
  266. case builtInNumFmt[builtInNumFmtIndex_GENERAL], builtInNumFmt[builtInNumFmtIndex_STRING]:
  267. return c.Value, nil
  268. case builtInNumFmt[builtInNumFmtIndex_INT], "#,##0":
  269. return c.formatToInt("%d")
  270. case builtInNumFmt[builtInNumFmtIndex_FLOAT], "#,##0.00":
  271. return c.formatToFloat("%.2f")
  272. case "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)":
  273. f, err := strconv.ParseFloat(c.Value, 64)
  274. if err != nil {
  275. return c.Value, err
  276. }
  277. if f < 0 {
  278. i := int(math.Abs(f))
  279. return fmt.Sprintf("(%d)", i), nil
  280. }
  281. i := int(f)
  282. return fmt.Sprintf("%d", i), nil
  283. case "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)":
  284. f, err := strconv.ParseFloat(c.Value, 64)
  285. if err != nil {
  286. return c.Value, err
  287. }
  288. if f < 0 {
  289. return fmt.Sprintf("(%.2f)", f), nil
  290. }
  291. return fmt.Sprintf("%.2f", f), nil
  292. case "0%":
  293. f, err := strconv.ParseFloat(c.Value, 64)
  294. if err != nil {
  295. return c.Value, err
  296. }
  297. f = f * 100
  298. return fmt.Sprintf("%d%%", int(f)), nil
  299. case "0.00%":
  300. f, err := strconv.ParseFloat(c.Value, 64)
  301. if err != nil {
  302. return c.Value, err
  303. }
  304. f = f * 100
  305. return fmt.Sprintf("%.2f%%", f), nil
  306. case "0.00e+00", "##0.0e+0":
  307. return c.formatToFloat("%e")
  308. }
  309. return c.Value, nil
  310. }
  311. // FormattedValue returns the formatted version of the value.
  312. // If it's a string type, c.Value will just be returned. Otherwise,
  313. // it will attempt to apply Excel formatting to the value.
  314. func (c *Cell) FormattedValue() string {
  315. value, err := c.SafeFormattedValue()
  316. if err != nil {
  317. return err.Error()
  318. }
  319. return value
  320. }
  321. // parseTime returns a string parsed using time.Time
  322. func parseTime(c *Cell) (string, error) {
  323. f, err := strconv.ParseFloat(c.Value, 64)
  324. if err != nil {
  325. return c.Value, err
  326. }
  327. val := TimeFromExcelTime(f, c.date1904)
  328. format := c.GetNumberFormat()
  329. // Replace Excel placeholders with Go time placeholders.
  330. // For example, replace yyyy with 2006. These are in a specific order,
  331. // due to the fact that m is used in month, minute, and am/pm. It would
  332. // be easier to fix that with regular expressions, but if it's possible
  333. // to keep this simple it would be easier to maintain.
  334. replacements := []struct{ xltime, gotime string }{
  335. {"yyyy", "2006"},
  336. {"yy", "06"},
  337. {"dd", "02"},
  338. {"d", "2"},
  339. {"mmm", "Jan"},
  340. {"mmss", "0405"},
  341. {"ss", "05"},
  342. {"hh", "15"},
  343. {"h", "3"},
  344. {"mm:", "04:"},
  345. {":mm", ":04"},
  346. {"mm", "01"},
  347. {"am/pm", "pm"},
  348. {"m/", "1/"},
  349. {".0", ".9999"},
  350. }
  351. for _, repl := range replacements {
  352. format = strings.Replace(format, repl.xltime, repl.gotime, 1)
  353. }
  354. // If the hour is optional, strip it out, along with the
  355. // possible dangling colon that would remain.
  356. if val.Hour() < 1 {
  357. format = strings.Replace(format, "]:", "]", 1)
  358. format = strings.Replace(format, "[3]", "", 1)
  359. format = strings.Replace(format, "[15]", "", 1)
  360. } else {
  361. format = strings.Replace(format, "[3]", "3", 1)
  362. format = strings.Replace(format, "[15]", "15", 1)
  363. }
  364. return val.Format(format), nil
  365. }
  366. // isTimeFormat checks whether an Excel format string represents
  367. // a time.Time.
  368. func isTimeFormat(format string) bool {
  369. dateParts := []string{
  370. "yy", "hh", "am", "pm", "ss", "mm", ":",
  371. }
  372. for _, part := range dateParts {
  373. if strings.Contains(format, part) {
  374. return true
  375. }
  376. }
  377. return false
  378. }