Sheetshow.Value (Sheetshow v0.1.0)

Copy Markdown View Source

What a cell can hold.

KindElixirIn Sheets
:emptynilan empty cell
:numberinteger() or float()a number (a double)
:stringString.t()text
:booleantrue or falseTRUE / FALSE
:formula{:formula, "=SUM(A1:A9)"}a formula
:dateDate.t()a serial number
:datetimeNaiveDateTime.t() or DateTime.t()a serial number
:timeTime.t()a serial number

Sheets keeps dates as days since 1899-12-30 with the time of day as the fraction, and shows them as dates only through a number format. Writers use to_serial/1 and default_number_format/1; readers use from_serial/2. A DateTime is written as its own wall-clock time with the zone dropped, so what you see in Elixir is what you see in the sheet.

Integers beyond 2^53 and Decimals do not survive a double; store them as strings.

Summary

Functions

The number format that makes a temporal value readable in Sheets, or nil for values that need none. Writers apply it when a cell's style has no :number_format of its own.

A serial number back to a Date, NaiveDateTime or Time, rounded to the millisecond. Sub-second parts keep millisecond precision; whole seconds come back with none, so a second-precision value round-trips as ==.

The kind of a valid value. Raises ArgumentError for anything else; use validate/1 for the checked version.

A temporal value as a Sheets serial number.

Whether the term is a cell value.

Checks a value.

Types

kind()

@type kind() ::
  :empty | :number | :string | :boolean | :formula | :date | :datetime | :time

t()

@type t() ::
  nil
  | number()
  | String.t()
  | boolean()
  | {:formula, String.t()}
  | Date.t()
  | NaiveDateTime.t()
  | DateTime.t()
  | Time.t()

Functions

default_number_format(value)

@spec default_number_format(t()) :: String.t() | nil

The number format that makes a temporal value readable in Sheets, or nil for values that need none. Writers apply it when a cell's style has no :number_format of its own.

iex> Sheetshow.Value.default_number_format(~D[2026-09-12])
"yyyy-mm-dd"
iex> Sheetshow.Value.default_number_format(42)
nil

from_serial(serial, kind)

@spec from_serial(number(), :date | :datetime | :time) ::
  Date.t() | NaiveDateTime.t() | Time.t()

A serial number back to a Date, NaiveDateTime or Time, rounded to the millisecond. Sub-second parts keep millisecond precision; whole seconds come back with none, so a second-precision value round-trips as ==.

iex> Sheetshow.Value.from_serial(25569, :date)
~D[1970-01-01]
iex> Sheetshow.Value.from_serial(45292.5, :datetime)
~N[2024-01-01 12:00:00]
iex> Sheetshow.Value.from_serial(0.25, :time)
~T[06:00:00]

kind(v)

@spec kind(t()) :: kind()

The kind of a valid value. Raises ArgumentError for anything else; use validate/1 for the checked version.

iex> Sheetshow.Value.kind(2.5)
:number
iex> Sheetshow.Value.kind({:formula, "=A1*2"})
:formula
iex> Sheetshow.Value.kind(~N[2026-09-12 08:30:00])
:datetime

to_serial(date)

@spec to_serial(Date.t() | NaiveDateTime.t() | DateTime.t() | Time.t()) :: number()

A temporal value as a Sheets serial number.

iex> Sheetshow.Value.to_serial(~D[1970-01-01])
25569
iex> Sheetshow.Value.to_serial(~N[2024-01-01 12:00:00])
45292.5
iex> Sheetshow.Value.to_serial(~T[06:00:00])
0.25

valid?(v)

@spec valid?(term()) :: boolean()

Whether the term is a cell value.

validate(value)

@spec validate(term()) :: :ok | {:error, Sheetshow.Error.t()}

Checks a value.

iex> Sheetshow.Value.validate("hello")
:ok
iex> {:error, %Sheetshow.Error{reason: :invalid_value}} = Sheetshow.Value.validate({:formula, "SUM(A1)"})