きり丸の技術日記

技術検証したり、資格等をここに残していきます。

何をもってN月第1週とする?

普段N月M週という表現で何となく通じていますが、具体的な定義があるかをしらべました。

結論を先に述べると、明確な定義をしている表現はありませんでした。ですが、週について色々と調べたのでまとめておきます。

木曜日を起点として1年を週に分割する(ISO 8601/JIS X0301の定義)

正規表現で「YYYY-Www-D」と表記する方法があります。こちらの定義では、「最初の木曜日を含む週が、その年の第1週である」としています。

この定義に合わせて、最初の木曜日を含む週がその月の第1週と表現しても問題ないでしょう。ただし、あくまで1年間を週として分割する際の定義ですので、月に関してまでは厳密に定義はしていません。

曜日コードを基準にする(月曜日を起点・カレンダー通り)

曜日に関してはISO 8601でコードとして定義されています。月曜日は1、日曜日は7です。

曜日コードとしては月曜日が起点ですので、月初1日が月曜日の場合は第1週、それ以外の場合は最初の月曜日を含む日付までを第1週として起算したほうが良さそうです。

難しいこと書いていますが、基本的には日本の大多数のカレンダー通りです。(アメリカに関しては日曜始まりのカレンダーが多いらしいので、定義がズレてしまいますが)

歴週を基準とする(日曜日を起点)

歴週という日曜日から土曜日までを一週間とする考えがあります。

一九八八年に施行された「労働基準法の一部を改正する法律(昭和六二年法律第九九号)」でも、こちらの歴週を扱うような記載がありました。ただ、現在の労働基準法に該当の記載はなかったので、どこかのタイミングで改正はされたとは思います。

また、病院の診療報酬における「1週につき1回算定」とは特に断りがない場合には歴週のことを指すらしいです。

終わりに

具体的な定義はないようですが、色々調べてみると面白かったです。セクションとしては用意していませんでしたが、地動説から生まれた曜日から考えると、土曜日始まりの定義も昔はあったようです。

元々はこちらのツイートを見てからの再度色々調査をしていたのですが、官公庁から出ている調査等も見つかって面白かったです。ぜひ、参考情報の方も見ていただけると面白いのではないかと思います。

twitter.com

参考情報

Pytestにてネストしたテストケースを作成する

JUnit 5だと@Nestedアノテーションを付与すると、テストクラス内にさらにテストクラスを用意できます。

Pytestでも同様にテストクラスをネストさせたかったのですが、ググってもすぐには出てこなかったので、自分のブログにまとめます。

環境

  • Pytest
    • 7.1.1

分かること

  • Pytestでネストしたテストクラスを書ける
  • @pytest.fixtureを使用してもネストしたテストクラスを書ける

ユースケース

テストクラスを特定の粒度ごとに作成する。

最低でも、テストクラス -> テストメソッドの1段落ネストしておくのはオススメです。

- テストクラス1
    - テストメソッド1
        - テストメソッド条件1
    - テストメソッド2
        - テストメソッド条件1
            - テストメソッド条件1-1
        - テストメソッド条件2
            - テストメソッド条件2-1
            - テストメソッド条件2-2

コード

次のコードで表現できます。ネストしたテストメソッドには、第1引数にselfを取ることさえ分かれば、簡単です。

@pytest.fixtureを使用する場合も、第2引数以降にマッピングされます。

import pytest

class TestNested:
    class TestMethodA:
        def test_1(self):
            assert 1 == 1

    class TestMethodB:
        class TestConditionA:
            def test_1(self):
                assert 1 == 1

        class TestConditionB:
            def test_1(self, condition_a):
                assert condition_a == 1

            def test_2(self, condition_b):
                assert condition_b == 2

@pytest.fixture
def condition_a():
    return 1

@pytest.fixture
def condition_b():
    return 2

なお、次の状態で-vをオプションで付与して実行すると、次のメッセージでテストの構造が分かりやすくなります。

tests/unit/models/test_nested.py::TestNested::TestMethodA::test_1
tests/unit/models/test_nested.py::TestNested::TestMethodB::TestConditionA::test_1
tests/unit/models/test_nested.py::TestNested::TestMethodB::TestConditionB::test_1
tests/unit/models/test_nested.py::TestNested::TestMethodB::TestConditionB::test_2

ソースコード

終わりに

pytest nestedと記載したところ、ParameterizedTestのStackOverFlowの記事しか出てこなかったので分かりませんでした。

調べようにもネストさせる書き方が当たり前ですので、検索するキーワードも思いつきませんでした。結局のところ、さまざまなPytestの記事やTwitterの検索等を手あたり次第調べてようやくわかりました。

普段からPython書いている人であれば簡単でしょうが、メインをPythonで扱わないので慣れることが難しいですね。動的型付言語はスクラッチ開発に強い印象ですが、慣れるまではスクラッチ開発は難しいので、ガンガン素振りしていきたいです。

参考情報

開始日と解約"月"を元に暦上で日割のない解約"日"を求める(Java)

小ネタ。「今年の12月に解約したい。日割りが必要ない日付を教えてほしい」といった、解約する「年月」までは把握しているが、解約する「年月日」までは分からないといったケースに対応するロジックをJavaで求めます。

環境

  • Java
    • 17

対応

暦上の1ヵ月の定義については、こちらの記事を見てください。

雑に表現すると次のどちらかです。

  • 開始日の"日" -1日
  • 月末

月末はYearMonth型を使用すると非常に楽ですので、まずは「解約月」をYearMonth型に変換します。

YearMonth#isValidDayにて、指定日付が存在するかをチェックできます。YearMonth#atDayにて、指定の日付のLocalDate型に変換できます。それぞれのパラメータに「開始日の日-1日」を渡します。もし指定日付が存在すれば、その日付が「解約日」となります。存在しなければ、「解約日」は月末です。

public LocalDate from年月to日割りなし日付(LocalDate startDate, LocalDate endMonth) {
  YearMonth yearMonth = YearMonth.from(endMonth);
  if (yearMonth.isValidDay(localDate.getDayOfMonth() - 1)) {
    return yearMonth.atDay(localDate.getDayOfMonth() - 1);
  } else {
    return yearMonth.atEndOfMonth();
  }
}

なお、存在しない日付とは次のケースです。

  • 開始日が1日
    • パラメータが0日になるため
  • 存在しない日付
    • 2月30日 等々 閏年も含む

ソースコード

テストケースはこの記事参照してください。

終わりに

テストケースさえ思いつけばシンプルです。

LocalDateのまま処理するとチェックメソッドがないため、DateTimeExceptionが発生していたのですが、YearMonth#isValidDayのおかげで安全に処理できました。

地味な内容ですが、検証することでYearMonth#isValidDayの存在に気づけて良かったです。

類似情報