Ubiregi Advent Calendar 2018の14日目です。
言いたいことはタイトル通りです。
やりたいこと
ユビレジでは売上データのcsvをダウンロードする機能があります。
その時に、アカウントのタイムゾーンによって、zipに圧縮するファイルの変更日時を変えたいという時があると思います。
なので、そんな感じでサンプルコードをやっていきます。
実装
require 'zip'
require 'time'
def compress(path, time)
buffer = Zip::OutputStream.open('data.zip') do |out|
zip_entry = Zip::Entry.new(out, "sample.csv", nil, nil, nil, nil, nil, nil, Zip::DOSTime.parse(time))
out.put_next_entry zip_entry
buffer = File.read(path)
out.write(buffer)
end
end
Zip::Entry.new のドキュメントを見ると、色々引数が指定できるみたいですね。最後の引数にZip::DOSTimeのインスタンスを渡してやれば良さそうなのでそうします。
テストコードをかく
テストコードも書いていきましょう。
あくまでもサンプルで、これだとローカルのファイルを用意しなきゃいけなかったり、ローカルに圧縮ファイルが作成されたりしちゃうので、実際にやる時はいい感じにやってください。
require 'minitest/autorun'
class CompressTest < Minitest::Test
def test_compress
compress('/Users/kitaindia/Documents/today.csv', '2018-12-24 15:15:15')
Zip::InputStream.open('data.zip') do |io|
assert_equal '2018-12-24 15:15:15 +0900', io.get_next_entry.time
end
end
end
実行してみます。
F
Failure:
CompressTest#test_compress [sample.rb:19]:
Expected: "2018-12-24 15:15:15 +0900"
Actual: 2018-12-24 15:15:14 +0900
はい。1秒ずれてしまいました。
解決
# Bits 0-4 2 second increments (0-29)
2秒ごとにインクリメントするのだそうです。
秒数は5bit(32通り)で表してるんだそうで・・・。
wikipedia によると
DOSのFATファイルシステムは2秒単位でタイムスタンプを保持し、ZIPファイルレコードはこれを模倣している。結果として、ZIPアーカイブ内にあるファイルのタイムスタンプも2秒単位で丸められる。
なるほど・・・。しかし、テストで偶然2分の1を踏んでしまうなんて、ついてないですね・・・。
まとめ
実際の慌て具合の様子。
解決の様子。