はい。進学しました。
続きを読むpytestでデフォルトはスキップのテストを作る
テストケースを書いておきたいが、常にテストしたくないこともある。 特に非常にテスト実行が重いケース。
続きを読むPythonを使って、macOSのファイル作成日時を取得する
macOSのマシンを使っている。 ローカルのファイルを整理するスクリプトを書いていて、ファイルの作成日時を取得した時の話をする。
ローカルに大量の作業用ファイルがある
ある。作業用ファイルといってもいろんな種類があるが。 直近で言えば、私は考え事を整理するときにXmindを使っているのだが、XMindのファイルがたくさんある。 そして普通に多いので、整理したい。
「作成日付ごとにディレクトリを切って、そこに入れておきたいな」と思った。
Finderだとファイルの作成日時がある
知っての通り、Finderで見ると、ファイルにはファイルの作成日時が表示されている。 だから、行けるはずだろうと持ってスクリプトを書いてみた。Pythonである。
(「書いてみた」と言ったが、実際はClaudeに指示を出してスクリプトを出力し動作確認していた。)
しかし、何かうまくいかない。特定のファイルがFinderの作成日時と違うディレクトリに移動される。
os.path.getctimeを使っていた
そのスクリプトではファイルの作成日時を取得するために、Pythonのos.path.getctimeを確認していた。
これが間違っている。
システムの ctime、Unix系など一部のシステムでは最後にメタデータが変更された時刻、Windows などその他のシステムでは path の作成時刻を返します。返り値はエポック (time モジュールを参照) からの経過時間を示す秒数になります。ファイルが存在しない、あるいはアクセスできなかった場合は OSError を送出します。
ctimeはUNIX系のシステムのファイルシステムの情報であるが、ファイルの作成日時ではない。ファイルシステムのメタデータの変更日時である。
じゃあ、どうすればいいのか?
ファイルシステムのメタデータの変更日時ではなくて、macOSのFinderで表示されている情報が欲しい。 と言うわけで調べてみた。
どうやらmacOSのファイルシステムに拡張メタデータがあり、それを見れば良さそうだ。
Pythonで取得する方法を探す
上記のスタックオーバーフローでは、コマンドラインから取得している。 が、こう言うのはたいていライブラリがある。と思って探してみた。
あった。
さらにそこから、以下のライブラリを紹介されていた。
これが良さそうに見える。あとは、属性名が分かれば取得できそうだ。
必要な属性を探す
macOSの開発者ドキュメントを見ながら、ファイルのメタデータで、欲しいものを探す。
kMDItemContentCreationDate
がそれっぽい。
Python経由で取得する
from osxmetadata import OSXMetaData, kMDItemContentCreationDate def get_creation_date(file_path: str)-> datetime.datetime: md = OSXMetaData(file_path) creation_date = md.get(kMDItemContentCreationDate) return creation_date
できた。
めでたしめでたし。
Djangoのtimezone.nowに関するモヤモヤを調べる
Djangoのtimezone.nowを使っていてモヤモヤした。特に、「なぜ、UTCの時刻を返すのか」と思ったので、調べてみた。 その記録。
背景
Djangoにはtimezoneのutilsがあり、nowという関数を持っている。 これを実行すると次のようになる。
>>> from django.utils import timezone >>> timezone.now() datetime.datetime(2024, 3, 27, 20, 49, 31, 114299, tzinfo=datetime.timezone.utc)
また、Djangoプロジェクトにはsettingsでタイムゾーンが設定できる。 例えば次のような感じ。
TIME_ZONE = "Asia/Tokyo"
しかし、タイムゾーンを設定していても timezone.now()
はUTC時刻を返す。
設定したタイムゾーンでの時刻にする場合は、 timezone.localtime()
を使えることを知っていた。
なので、次に私はこんな風に書いてみた。
>>> timezone.localtime(timezone.now()) datetime.datetime(2024, 3, 28, 5, 55, 30, 810238, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tokyo'))
めんどくさい。というか、私は何度も timezone.now()
で設定したタイムゾーンの時刻が返ってくると勘違いしている。
「あれ?なんでUTCの時刻返ってきてるんだ?あ、そうか。localtimeという概念あった。」
みたいなことを毎回考えている。モヤモヤするので、もうちょっとこの辺の経緯に関する情報を調べてみる。
ドキュメントを読む
とりあえず、Djangoのtimezone.nowに関するドキュメントを読んでみよう。 5.0でのドキュメントである。
Django ユーティリティ (django.utils) | Django ドキュメント | Django
次の記載がある。
USE_TZ が False の場合、システムのローカルタイムゾーンで現在の時刻を表す、関連するタイムゾーンのない naive な日時(タイムゾーンの関連がない日時)になります。
翻訳前
If USE_TZ is True, this will be an aware datetime representing the current time in UTC. Note that now() will always return times in UTC regardless of the value of TIME_ZONE; you can use localtime() to get the time in the current time zone.
USE_TZという概念が関係ありそうだ。
そもそも、 timezone.localtime()
のデフォルト
また、ドキュメントを読んでいる時点で
timezone.localtime()
はデフォルトでnowを返すことに気づいた。ドキュメントにそう書いてある。
value が省略された場合, デフォルトは now() になります。
Django ユーティリティ (django.utils) | Django ドキュメント | Django
つまり、タイムゾーンを意識した現在時刻は、これで取得すれば良い。
>>> timezone.localtime() datetime.datetime(2024, 3, 28, 6, 8, 8, 700251, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tokyo'))
具体的なコードも見てみたが、本当にそのままnowが実行されている。
django/django/utils/timezone.py at 617bcf611f3daa796e4054ba041089ece30a32fc · django/django · GitHub
というわけで、私は timezone.now()
ではなく timezone.localtime()
をもっと意識して使うと良さそうだ。
USE_TZについて
ここまで調べてみて、最初のめんどくささはある程度低減された。 ただ、せっかくなので、タイトルの問をもう少し深掘りしたい。
timezone.now()
のドキュメントで USE_TZ
の話が出てくるので、この設定値が関係してそうだ。
その辺をもう少し調べてみる。
USE_TZ
デフォルトで日時がタイムゾーンを意識するかどうかを指定する真偽値です。これが True に設定されている場合、Django は内部的にタイムゾーンを意識した日時を使用します。
Settings | Django documentation | Django
この記載を見て思うこととして、そもそも、この設定は必要なのか?(わざわざ、タイムゾーンを意識しない、という設定をすることがあり得るのか?)と思った。というのも、私は、Djangoを使い始めてから USE_TZ
の値を変更したことがない。「デフォルト値から変更しない設定値」という印象で使ってきた。
なので、この設定が導入された経緯を追いかけてみよう。
UZE_TZはいつ導入されたのか
ドキュメントに USE_TZ
の記載があるので、バージョンいくつから導入されているのかを確認してみよう
Djangoのドキュメントで閲覧できる最も古いバージョンは、1.8
である。そのドキュメントを見てみると、すでにUSE_TZがある。
Settings | Django documentation | Django
そこで次のことがわかった
- UZE_TZが指定されていない場合、 Falseで扱われる(つまり、タイムゾーンを意識せずに扱う)
django-admin startproject
でプロジェクトを作るとUSE_TZ = True
が追加される。
というわけで、 1.8
以前に導入されていたことが見えるし、上記の記載からなんとなく以下の状況が推測できた。
- 最初は、USE_TZがなかった。そして、タイムゾーンを意識せずに扱っていた。
- データベースに日時を入れたり、結局のところ、タイムゾーンを意識する必要性が高まってきた。というか常にタイムゾーンを意識した方が望ましい状況になってきた。
- 後方互換性を意識して、新規プロジェクトではデフォルトでタイムゾーンを意識させるように調整が入った。
これは事実かどうかの裏どりはしていない。が、面倒になってきたので、私の調査はここで終えるとする。
timezone.nowがUTCを返す理由もこの辺の兼ね合いなんだろうなあ、と想像した。
USE_TZの今後
少し余談だが、Django 5.0のドキュメントに USE_TZ
のデフォルト値はTrueで、古いバージョンではFalseにだった。との情報があった。
Changed in Django 5.0: In older versions, the default value is False.
Settings | Django documentation | Django
これも推測の裏どりをしていないが、やはりそもそもの話として、 USE_TZ
という設定値必要か?という話があるんだろうな、と想像した。
デフォルト値がTrueになったことで、 デフォルトの settings.pyから USE_TZ
は姿を消すことになるような気がする。
そうすると、この記事に書いたような疑問を解消するのは、少しハードルが上がるようにも思う。 だから、どうという話ではないですが。
終わり
今回は、ふと思ったことを調べてみました。
ではでは〜
データレイクやデータウェアハウスについて
データ分析の話題に関連して、データレイクやデータウェアハウスといった単語を聞くことがあります。以前、聞いて調べたこともあるのですが、いまいちピンとくる説明が見つかりませんでした。今は、以前と比較して「データレイクやデータウェアハウスって、こういうこと?」と言う理解が進んできました。今回は、現時点の知識を元に当時の私が知りたかった情報を説明してみます。
続きを読むBLOG HACKSという本を手に取る
BLOG HACKSという本を手に取りました。軽く眺めながら、つらつらと思うことを書いてみます。
続きを読む