📘 hkob-astro-notion-blog

これまではてなブログにて情報発信をしていましたが、令和5年3月22日より、こちらでの情報発信を始めました。2019年以前の古い記事は過去の Middleman 時代のものなので、情報が古いです。記録のためだけに残しています。

Formula 2.0 関数探求(1): parseDate編

1. はじめに

Formula 2.0 がリリースされました。以前紹介していた「逆引き Formula」も対応した「逆引き Formula 2.0」として、リリースに合わせて公開させていただきました。

https://hkob.notion.site/Formula-2-0-fbafcd96e1cc4f3982d914931af4969b?pvs=4

これを機会に Formula を学習したいという人もいるようなので、今回新しく追加された関数を一つずつ不定期に紹介していこうかと考えています。第一回目は逆引き Formula のほとんどの記事に影響のあった parseDate です。parseDate のマニュアルはこちらにありますので、同時に参照してみてください。

https://hkob.notion.site/parseDate-15f80223eed4410a918120876e5997e7?pvs=4

このページは複製できないようになっていますが、このページ内にある説明用のデータベースは複製可能にしてみました。以下のリンクから「複製」として、自分のページにコピーしていろいろと試してみてください。
https://hkob.notion.site/1898af9d82404838abf9bdf20d35d715?v=f5658386dc554ea5a9c5b2a896738522&pvs=4#

2. parseDate の解説

parseDate のマニュアルは以下のようになっています。「ISO8601標準に従って解析された日付を返します。」ということですね。

これは ISO8601標準を調べる必要がありそうです。ISO8601 をWikipediaで調べてみましょう。日付に関する国際規格とありますね。

説明内に基本形式と拡張形式があるようです。Notion API などでは拡張形式が使われていますので、基本形式については知りませんでした。Formula で使うとなると基本形式の方が応用が効きそうです。

3. さまざまな形式での変換

私の parseDate のマニュアルのスクリーンショットを見ながら、ISO8601 のどのパターンに対応しているのかを確認していきましょう。

  • func は関数形式の呼び出しです。
    parseDate(prop("date_str"))
  • method はメソッド形式の呼び出しです。
    prop("date_str").parseDate()
💡
Formula 2.0 からこのメソッド形式での記述が可能になりました。メソッド形式の場合、すでに計算したものに対して、後から処理を追加できます。関係形式の場合、既存のものの頭に関数を追加する形だったので、中から順番に読んでいかなければならなかったですが、メソッド形式では頭から順番に読んでいけばよいので、他人のものを読むのも簡単です。また、関数の時のような、フォーミュラの終わりのカッコの連続「 ))))))))のようなもの」がなくなります。今後はみんなメソッド形式で記述するようにしましょう。
3.1 年のみ

2023 のように年だけの文字列の場合、その年の1月1日の日付が得られます。

3.2 年月

2023-07 のように年と月を - で繋げると指定した月の1日の日付が得られます。1月から9月までの場合、 0 を頭に付けて二桁にする必要があります。ISO8601的には基本形式の六桁の数値 202307 は認められていないのですが、parseDate はこれでも受け付けてくれました。

3.3 年月日

基本形式の 20230708 または拡張形式の 2023-07-08 のように年月日の文字列から任意の日付が作成されます。これが一番使われる形式ではないかと思います。Notion の内部的には 3.1 から 3.3 までで作成した日付は Date という形式になっており、時刻情報は持っていません。

特に基本形式は単なる数値を文字列に変換したものなので、かなり応用が効きます。試しに、「年、月、日の3つの数値プロパティから日付を作成するには?」という逆引きを作ってみました。

https://hkob.notion.site/3-fcf89d94d7964597a266f579eb681452?pvs=4

ここで作成した Formula はこんな感じです。8桁の数値を作成するために年を 10000 倍、月を100倍して合計しています。拡張形式で作成していたときには一桁の数値を見つけて 0 を追加するというかなり面倒なことをしていました。基本形式の方が Formula にはマッチしていると思います。

/* 3つのプロパティからリストを作成 */
[prop("年"), prop("月"), prop("日")]
	/* 年を 10000 倍, 月を 100倍, 日を1倍する */
	.map(current * 100^(2-index))
	/* これらを合計 */
	.sum()
	/* 文字列に変換 */
	.format()
	/* 日付に変換 */
	.parseDate()

3.4 年月日時

ISO8601 では T の後ろに時刻が記述できます。基本形式では 20230708T10 、拡張形式では 2023-07-08T10 のようにすると時間まで設定されます。3.3 までと異なり Notion 内部では DateTime 形式となります。DateTime 形式ではタイムゾーン情報を持ちますが、Notion では省略時にはその地域のタイムゾーンが自動的に選択されます。この場合は、JST(日本標準時: +09:00) の午前10時となります。なお、ISO8601 では時刻は0から23までの24時制となっています。

3.5 年月日時分

基本形式では 20230708T1023 、拡張形式では 2023-07-08T10:23 のようにすると分の情報まで設定できます。なお、Notion 内部では分までしか保存されないので、秒を設定しても無視されます。

なお、面白い現象ですが、時刻を設定してもそれが0:00 だった場合には、Notion 内部では DateTime ではなく Date になります。これに関しては裏話があるのでまた後で。

3.6 タイムゾーンの設定

ローカルタイムではなく、別の国のタイムゾーンで時刻を設定したい場合には、時刻の後ろに GMT との時差を設定できます。ここで Z は GMT になります。海外に在住の人が日本の人に合わせて、日本の時刻を作成したい場合には、基本形式では +0900 、拡張形式では +09:00 を追記すればいいです。作成した時刻がローカルタイムで 0:00 になる場合には、3.5 で書いたように Date になるのでご注意ください。

3.7 年と週番号(+曜日)

その年の週番号からその週の月曜日の日付が作成されます。基本形式では 2023W08 、拡張形式では 2023-W07 のように記述します。週番号は必ず 2 桁で記述する必要があります。


さらに曜日番号(月曜が1、日曜日が7)を追加するとその週の該当する曜日の日付が得られます。基本形式では 2023W073、拡張形式では 2023-W07-7 のように記述します。こちらも週番号が2桁になるので、基本形式では3桁の数字が必要です。

3.8 年と日番号

その年の日番号から日付を作成できます。このとき、日番号は必ず3桁にする必要があります。例で示すように 1月1日が 1 、12月31日が 365(閏年でない場合) または 366(閏年の場合)になります。

4. 利用例

逆引き Formula 2.0 では日付に関するほとんどの関数で parseDate が使われています。特に formatDate との組み合わせがほとんどです。特殊な使い方をしているものをいくつか紹介してみます。

  • 「今月初日を得るには?」→ 3.2 の YYYY-MM を使うことで今月 1 日を得ています。
    /* 現在時刻を YYYYMM の文字列に変換 */
    now().formatDate("YYYY-MM")
     /* 作成した文字列から日付を作成 */
     .parseDate()

    https://hkob.notion.site/ce5e80fba5c745d5b836869e6cdb6544?pvs=4

  • 「タイトルから日付を作成するには」→ 基本形式の YYYYMMDD を文字列から作成しています。
    lets(
    	/* numbers 変数: 数字だけを取り出した配列 */
    	numbers, 
    		/* 年月日 の数値を取り出し */
    		prop("Name").match("\d+")
    			/* 文字列の配列を数値の配列に変更 */
    			.map(current.toNumber()),
    	/* ymd 変数, [年, 月, 日]の配列、年がなければ今年の年を追加 */
    	ymd,
    		/* 配列の長さが2の場合、先頭に今年を追加 */
    		numbers.length() == 2 ? [now().year(), numbers].flat() : numbers,
    	/* y を 10000 倍、 m を 100、d はそのままに。*/
    	/* 例 [2023, 9, 10] -> [20230000, 900, 10] */
    	ymd.map(current * 100^(2-index))
    		/* それらを加算。 例 [20230000, 900, 10] -> 20230910 */
    		.sum()
    		/* 文字列に変換 */
    		.format()
    		/* 日付に変換 */
    		.parseDate()
    )

    https://hkob.notion.site/f06a95d8925b43d783ccfc36d37888af?pvs=4

  • 「週番号からその週の月曜日の日付を取得するには」 → 基本形式の YYYYWww を現在の年度と与えられた週番号から作成しています。
    /* 週番号を二桁にした文字列を wnum にする */
    let(wnum,	
    	/* 週番号に100を足したものを3桁の文字列に変換 */	
    	(prop("週番号")+100).format()
    		/* 先頭の1を外して2桁の数字にする -> wnum に代入 */
    		.substring(1),
    	/* 現在の年と週番号を -W を使って連結 (例: 2023W01) */
    	[now().year(), wnum].join("W")
    	  /* ISO8601 の週番号文字列を日付に変換 */
    		.parseDate()
    )

    https://hkob.notion.site/d71f6ee4b12642bd8f683d4878971f3c?pvs=4

5. おまけ

当初、parseDate のテストをしていて、日付を作成した後に時間を足しても Date のままで時間が追加されない状況でした。当初、Date と DateTime はクラスが違うのでそういうものだと説明されたのですが、関数を数珠繋ぎで作っていくとそういう例はたくさんあると懇願していました。その時の Slack の要望はこちらです。

その後いろんな例を使って説明したところ、内部で Date で持っている情報に時間情報が追加された場合には、DateTime にクラスチェンジするという実装を追加してもらえました。今はちゃんと最初の例でも 0:30AM となるようになっています。

2ヶ月くらいのベータテストではこんな感じでアンバサダーが寄ってたかって、気になるところを指摘して改善するという作業を延々とやっていました。非常に濃い 2ヶ月でした。もしこのようなことも体験してみたいという人は、以下のページを読んで応募してみてください。

https://www.notion.so/Notion-0686a485162d4fe4aa6119eeb26c45b5

6. おわりに

今回は 1 回目で、かつ parseDate 自体も入力のバリエーションが多かったので、かなり大きな記事になってしまいました。今後は不定期に新しく追加された関数を中心にブログで解説をしていきたいと思います。解説してほしい関数がありましたら X で連絡してもらえればと思います。