行動すれば次の現実

テック中心の個人ブログ

【Axlsx】Cellのtypeに:dateを指定しているのに日付型のセル書式にならない

前回同様、またAxlsx関連のマニアック話ですが、なぞ仕様に嵌ってしまったので記録として残しておきます。 同じように悩んでしまっている方の一助になれば幸いです。

Cellのtypeに:dateを指定しているのに日付型のセル書式にならない

以下のようにadd_cellで日付型オブジェクト(Date.today)、typeに:dateを指定しているのにも関わらず、セルの書式が日付型として入力されない事象が発生しました。

p = Axlsx::Package.new
ws = p.workbook.add_worksheet

header_style = ws.styles.add_style(border: { style: :thin, color: '000000' }, bg_color: 'E4E4E4')
value_style = ws.styles.add_style(border: { style: :thin, color: '000000' })

row = ws.add_row
row.add_cell('日付', style: header_style, type: :string)
row.add_cell(Date.today, style: value_style, type: :date)

▼日付型ではなく数値データ入力されている

なお、add_cellメソッドというのはCellをnewしているだけのシンプルなプログラムです。

# Adds a single cell to the row based on the data provided and updates the worksheet's autofit data.
# @return [Cell]
def add_cell(value = '', options = {})
  c = Cell.new(self, value, options)
  self << c
  worksheet.send(:update_column_info, self, [])
  c
end

axlsx/row.rb at 8e7b4b3b7259103452c191f73ce0bf64f66033fe · randym/axlsx · GitHub

ちなみにこの事象は、以下のようにstyleは未指定、type :dateのみ指定する場合だと正しく日付型で入力されます。

p = Axlsx::Package.new
ws = p.workbook.add_worksheet

row = ws.add_row
row.add_cell('日付', type: :string)
row.add_cell(Date.today, type: :date)

▼日付型として入力されている

どうやら、Cellをnewする時にstyleとtype :dateを併用するとセルの書式設定が日付型として認識されないという動きのようです。

styleに明示的にnum_fmtを指定すると日付型の書式が適用される

小一時間ほど悩んでいましたが、以下のドキュメントに答えが記載されていました。

Method: Axlsx::Styles#add_style — Documentation for randym/axlsx (master)

styleにnum_fmtというオプションで日付フォーマットを指定することで、セルの書式に日付型が適用されるようです。

p = Axlsx::Package.new
ws = p.workbook.add_worksheet

header_style = ws.styles.add_style(border: { style: :thin, color: '000000' }, bg_color: 'E4E4E4')
date_style = ws.styles.add_style(num_fmt: Axlsx::NUM_FMT_YYYYMMDD, border: { style: :thin, color: '000000' })

row = ws.add_row
row.add_cell('日付', style: header_style, type: :string)
row.add_cell(Date.today, style: date_style, type: :date)

▼日付型として入力されている

Cellをnewする際に、styleとtype :dateを併用する場合は、明示的にnum_fmtを指定する必要があるようです。

なぜこのような動きになるかというと、Cellクラスのコードを見るとわかるように、デフォルトの日付用style(STYLE_DATE)がオプションで指定したstyleで上書きされてしまうからです。

def cast_value(v)
  return v if v.is_a?(RichText) || v.nil?
  case type
  when :date
    self.style = STYLE_DATE if self.style == 0
    v

axlsx/cell.rb at 8e7b4b3b7259103452c191f73ce0bf64f66033fe · randym/axlsx · GitHub

Cellに対してオプションでstyleを指定してしまうと、typeごとに定義されたデフォルトのstyleが上書きされてしまい、セルの書式設定が無効となるようです。