cell.go 11 KB

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