cell.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. package xlsx
  2. import (
  3. "errors"
  4. "fmt"
  5. "math"
  6. "strconv"
  7. "time"
  8. )
  9. const (
  10. maxNonScientificNumber = 1e11
  11. minNonScientificNumber = 1e-9
  12. )
  13. // CellType is an int type for storing metadata about the data type in the cell.
  14. type CellType int
  15. // Known types for cell values.
  16. const (
  17. CellTypeString CellType = iota
  18. CellTypeFormula
  19. CellTypeNumeric
  20. CellTypeBool
  21. CellTypeInline
  22. CellTypeError
  23. CellTypeDate
  24. CellTypeGeneral
  25. )
  26. func (ct CellType) Ptr() *CellType {
  27. return &ct
  28. }
  29. // Cell is a high level structure intended to provide user access to
  30. // the contents of Cell within an xlsx.Row.
  31. type Cell struct {
  32. Row *Row
  33. Value string
  34. formula string
  35. style *Style
  36. NumFmt string
  37. parsedNumFmt *parsedNumberFormat
  38. date1904 bool
  39. Hidden bool
  40. HMerge int
  41. VMerge int
  42. cellType CellType
  43. }
  44. // CellInterface defines the public API of the Cell.
  45. type CellInterface interface {
  46. String() string
  47. FormattedValue() string
  48. }
  49. // NewCell creates a cell and adds it to a row.
  50. func NewCell(r *Row) *Cell {
  51. return &Cell{Row: r, NumFmt: "general"}
  52. }
  53. // Merge with other cells, horizontally and/or vertically.
  54. func (c *Cell) Merge(hcells, vcells int) {
  55. c.HMerge = hcells
  56. c.VMerge = vcells
  57. }
  58. // Type returns the CellType of a cell. See CellType constants for more details.
  59. func (c *Cell) Type() CellType {
  60. return c.cellType
  61. }
  62. // SetString sets the value of a cell to a string.
  63. func (c *Cell) SetString(s string) {
  64. c.Value = s
  65. c.formula = ""
  66. c.cellType = CellTypeString
  67. }
  68. // String returns the value of a Cell as a string. If you'd like to
  69. // see errors returned from formatting then please use
  70. // Cell.FormattedValue() instead.
  71. func (c *Cell) String() string {
  72. // To preserve the String() interface we'll throw away errors.
  73. // Not that using FormattedValue is therefore strongly
  74. // preferred.
  75. value, _ := c.FormattedValue()
  76. return value
  77. }
  78. // SetFloat sets the value of a cell to a float.
  79. func (c *Cell) SetFloat(n float64) {
  80. c.SetValue(n)
  81. }
  82. //GetTime returns the value of a Cell as a time.Time
  83. func (c *Cell) GetTime(date1904 bool) (t time.Time, err error) {
  84. f, err := c.Float()
  85. if err != nil {
  86. return t, err
  87. }
  88. return TimeFromExcelTime(f, date1904), nil
  89. }
  90. /*
  91. The following are samples of format samples.
  92. * "0.00e+00"
  93. * "0", "#,##0"
  94. * "0.00", "#,##0.00", "@"
  95. * "#,##0 ;(#,##0)", "#,##0 ;[red](#,##0)"
  96. * "#,##0.00;(#,##0.00)", "#,##0.00;[red](#,##0.00)"
  97. * "0%", "0.00%"
  98. * "0.00e+00", "##0.0e+0"
  99. */
  100. // SetFloatWithFormat sets the value of a cell to a float and applies
  101. // formatting to the cell.
  102. func (c *Cell) SetFloatWithFormat(n float64, format string) {
  103. // beauty the output when the float is small enough
  104. if n != 0 && n < 0.00001 {
  105. c.Value = strconv.FormatFloat(n, 'e', -1, 64)
  106. } else {
  107. c.Value = strconv.FormatFloat(n, 'f', -1, 64)
  108. }
  109. c.NumFmt = format
  110. c.formula = ""
  111. c.cellType = CellTypeNumeric
  112. }
  113. var timeLocationUTC, _ = time.LoadLocation("UTC")
  114. func TimeToUTCTime(t time.Time) time.Time {
  115. return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), timeLocationUTC)
  116. }
  117. func TimeToExcelTime(t time.Time) float64 {
  118. return float64(t.UnixNano())/8.64e13 + 25569.0
  119. }
  120. // DateTimeOptions are additional options for exporting times
  121. type DateTimeOptions struct {
  122. // Location allows calculating times in other timezones/locations
  123. Location *time.Location
  124. // ExcelTimeFormat is the string you want excel to use to format the datetime
  125. ExcelTimeFormat string
  126. }
  127. var (
  128. DefaultDateFormat = builtInNumFmt[14]
  129. DefaultDateTimeFormat = builtInNumFmt[22]
  130. DefaultDateOptions = DateTimeOptions{
  131. Location: timeLocationUTC,
  132. ExcelTimeFormat: DefaultDateFormat,
  133. }
  134. DefaultDateTimeOptions = DateTimeOptions{
  135. Location: timeLocationUTC,
  136. ExcelTimeFormat: DefaultDateTimeFormat,
  137. }
  138. )
  139. // SetDate sets the value of a cell to a float.
  140. func (c *Cell) SetDate(t time.Time) {
  141. c.SetDateWithOptions(t, DefaultDateOptions)
  142. }
  143. func (c *Cell) SetDateTime(t time.Time) {
  144. c.SetDateWithOptions(t, DefaultDateTimeOptions)
  145. }
  146. // SetDateWithOptions allows for more granular control when exporting dates and times
  147. func (c *Cell) SetDateWithOptions(t time.Time, options DateTimeOptions) {
  148. _, offset := t.In(options.Location).Zone()
  149. t = time.Unix(t.Unix()+int64(offset), 0)
  150. c.SetDateTimeWithFormat(TimeToExcelTime(t.In(timeLocationUTC)), options.ExcelTimeFormat)
  151. }
  152. func (c *Cell) SetDateTimeWithFormat(n float64, format string) {
  153. c.Value = strconv.FormatFloat(n, 'f', -1, 64)
  154. c.NumFmt = format
  155. c.formula = ""
  156. c.cellType = CellTypeDate
  157. }
  158. // Float returns the value of cell as a number.
  159. func (c *Cell) Float() (float64, error) {
  160. f, err := strconv.ParseFloat(c.Value, 64)
  161. if err != nil {
  162. return math.NaN(), err
  163. }
  164. return f, nil
  165. }
  166. // SetInt64 sets a cell's value to a 64-bit integer.
  167. func (c *Cell) SetInt64(n int64) {
  168. c.SetValue(n)
  169. }
  170. // Int64 returns the value of cell as 64-bit integer.
  171. func (c *Cell) Int64() (int64, error) {
  172. f, err := strconv.ParseInt(c.Value, 10, 64)
  173. if err != nil {
  174. return -1, err
  175. }
  176. return f, nil
  177. }
  178. // GeneralNumeric returns the value of the cell as a string. It is formatted very closely to the the XLSX spec for how
  179. // to display values when the storage type is Number and the format type is General. It is not 100% identical to the
  180. // spec but is as close as you can get using the built in Go formatting tools.
  181. func (c *Cell) GeneralNumeric() (string, error) {
  182. return generalNumericScientific(c.Value, true)
  183. }
  184. // GeneralNumericWithoutScientific returns numbers that are always formatted as numbers, but it does not follow
  185. // the rules for when XLSX should switch to scientific notation, since sometimes scientific notation is not desired,
  186. // even if that is how the document is supposed to be formatted.
  187. func (c *Cell) GeneralNumericWithoutScientific() (string, error) {
  188. return generalNumericScientific(c.Value, false)
  189. }
  190. // SetInt sets a cell's value to an integer.
  191. func (c *Cell) SetInt(n int) {
  192. c.SetValue(n)
  193. }
  194. // SetInt sets a cell's value to an integer.
  195. func (c *Cell) SetValue(n interface{}) {
  196. switch t := n.(type) {
  197. case time.Time:
  198. c.SetDateTime(n.(time.Time))
  199. return
  200. case int, int8, int16, int32, int64, float32, float64:
  201. c.setGeneral(fmt.Sprintf("%v", n))
  202. case string:
  203. c.SetString(t)
  204. case []byte:
  205. c.SetString(string(t))
  206. case nil:
  207. c.SetString("")
  208. default:
  209. c.SetString(fmt.Sprintf("%v", n))
  210. }
  211. }
  212. // SetInt sets a cell's value to an integer.
  213. func (c *Cell) setGeneral(s string) {
  214. c.Value = s
  215. c.NumFmt = builtInNumFmt[builtInNumFmtIndex_GENERAL]
  216. c.formula = ""
  217. c.cellType = CellTypeGeneral
  218. }
  219. // Int returns the value of cell as integer.
  220. // Has max 53 bits of precision
  221. // See: float64(int64(math.MaxInt))
  222. func (c *Cell) Int() (int, error) {
  223. f, err := strconv.ParseFloat(c.Value, 64)
  224. if err != nil {
  225. return -1, err
  226. }
  227. return int(f), nil
  228. }
  229. // SetBool sets a cell's value to a boolean.
  230. func (c *Cell) SetBool(b bool) {
  231. if b {
  232. c.Value = "1"
  233. } else {
  234. c.Value = "0"
  235. }
  236. c.cellType = CellTypeBool
  237. }
  238. // Bool returns a boolean from a cell's value.
  239. // TODO: Determine if the current return value is
  240. // appropriate for types other than CellTypeBool.
  241. func (c *Cell) Bool() bool {
  242. // If bool, just return the value.
  243. if c.cellType == CellTypeBool {
  244. return c.Value == "1"
  245. }
  246. // If numeric, base it on a non-zero.
  247. if c.cellType == CellTypeNumeric || c.cellType == CellTypeGeneral {
  248. return c.Value != "0"
  249. }
  250. // Return whether there's an empty string.
  251. return c.Value != ""
  252. }
  253. // SetFormula sets the format string for a cell.
  254. func (c *Cell) SetFormula(formula string) {
  255. c.formula = formula
  256. c.cellType = CellTypeFormula
  257. }
  258. // Formula returns the formula string for the cell.
  259. func (c *Cell) Formula() string {
  260. return c.formula
  261. }
  262. // GetStyle returns the Style associated with a Cell
  263. func (c *Cell) GetStyle() *Style {
  264. if c.style == nil {
  265. c.style = NewStyle()
  266. }
  267. return c.style
  268. }
  269. // SetStyle sets the style of a cell.
  270. func (c *Cell) SetStyle(style *Style) {
  271. c.style = style
  272. }
  273. // GetNumberFormat returns the number format string for a cell.
  274. func (c *Cell) GetNumberFormat() string {
  275. return c.NumFmt
  276. }
  277. func (c *Cell) formatToFloat(format string) (string, error) {
  278. f, err := strconv.ParseFloat(c.Value, 64)
  279. if err != nil {
  280. return c.Value, err
  281. }
  282. return fmt.Sprintf(format, f), nil
  283. }
  284. func (c *Cell) formatToInt(format string) (string, error) {
  285. f, err := strconv.ParseFloat(c.Value, 64)
  286. if err != nil {
  287. return c.Value, err
  288. }
  289. return fmt.Sprintf(format, int(f)), nil
  290. }
  291. func (c *Cell) getNumberFormat() *parsedNumberFormat {
  292. if c.parsedNumFmt == nil || c.parsedNumFmt.numFmt != c.NumFmt {
  293. c.parsedNumFmt = parseFullNumberFormatString(c.NumFmt)
  294. }
  295. return c.parsedNumFmt
  296. }
  297. // FormattedValue returns a value, and possibly an error condition
  298. // from a Cell. If it is possible to apply a format to the cell
  299. // value, it will do so, if not then an error will be returned, along
  300. // with the raw value of the Cell.
  301. //
  302. // This is the documentation of the "General" Format in the Office Open XML spec:
  303. //
  304. // Numbers
  305. // The application shall attempt to display the full number up to 11 digits (inc. decimal point). If the number is too
  306. // large*, the application shall attempt to show exponential format. If the number has too many significant digits, the
  307. // display shall be truncated. The optimal method of display is based on the available cell width. If the number cannot
  308. // be displayed using any of these formats in the available width, the application shall show "#" across the width of
  309. // the cell.
  310. //
  311. // Conditions for switching to exponential format:
  312. // 1. The cell value shall have at least five digits for xE-xx
  313. // 2. If the exponent is bigger than the size allowed, a floating point number cannot fit, so try exponential notation.
  314. // 3. Similarly, for negative exponents, check if there is space for even one (non-zero) digit in floating point format**.
  315. // 4. Finally, if there isn't room for all of the significant digits in floating point format (for a negative exponent),
  316. // exponential format shall display more digits if the exponent is less than -3. (The 3 is because E-xx takes 4
  317. // characters, and the leading 0 in floating point takes only 1 character. Thus, for an exponent less than -3, there is
  318. // more than 3 additional leading 0's, more than enough to compensate for the size of the E-xx.)
  319. //
  320. // Floating point rule:
  321. // For general formatting in cells, max overall length for cell display is 11, not including negative sign, but includes
  322. // leading zeros and decimal separator.***
  323. //
  324. // Added Notes:
  325. // * "If the number is too large" can also mean "if the number has more than 11 digits", so greater than or equal to
  326. // 1e11 and less than 1e-9.
  327. // ** Means that you should switch to scientific if there would be 9 zeros after the decimal (the decimal and first zero
  328. // count against the 11 character limit), so less than 1e9.
  329. // *** The way this is written, you can get numbers that are more than 11 characters because the golang Float fmt
  330. // does not support adjusting the precision while not padding with zeros, while also not switching to scientific
  331. // notation too early.
  332. func (c *Cell) FormattedValue() (string, error) {
  333. fullFormat := c.getNumberFormat()
  334. returnVal, err := fullFormat.FormatValue(c)
  335. if fullFormat.parseEncounteredError {
  336. return returnVal, errors.New("invalid number format")
  337. }
  338. return returnVal, err
  339. }