🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
DateTime

多くのプログラミング言語におけるDateTimeオブジェクトは、日付と時間に関する演算と出力を行います。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

1422閲覧

今日が月曜始まりの週の最初の平日か判定って可能?:Python

退会済みユーザー

退会済みユーザー

総合スコア0

DateTime

多くのプログラミング言語におけるDateTimeオブジェクトは、日付と時間に関する演算と出力を行います。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2020/11/21 18:40

編集2020/11/21 23:09

週の始めに週報をメール配信するよう指示されています。

if jpholiday.is_holiday(today)==True: sys.exit() ... if today.weekday()==0 or today.weekday()==1 and jpholiday.is_holiday(today+datetime.timedelta(days=-1))==True:   実行

これくらいでほぼ事足りるとは思いますが、これだとGWなどの連休明けの水曜や木曜日に配信されないことになります。
「連休明けの水/木曜日だ」というのをさらなるif文の追加やif文で判定したり、
水曜、木曜だけど実行する日のリストを用意する、
のではない何かスマートな方法がありますでしょうか。
なければ「休み関係なくとにかく月曜に配信」とするか、連休中はマシンをOFFし、例外の日は手動でプログラムを回す方が安全かと思っています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2020/11/21 22:26 編集

これをするためには、任意の日付が祝日だと判定する必要がありますが、その処理は実装できているんでしょうか
toast-uz

2020/11/21 22:45

jpholidayというライブラリがそれなんでしょうね。メンテされているようですが、私だったら使わないレベク感のライブラリですね・・。自分で実装した方が確実そう。
Zuishin

2020/11/21 23:45

割と広く使われていてメンテもされているようなので、仮にロジックが間違っていたらすぐに修正されるでしょう。toast-uz さんの作るものより確実そう。
Zuishin

2020/11/21 23:54

カレンダーの信頼性に疑問がある場合は Google Calendar と比較するのが手軽だし自動化も容易いです。 最近は大型連休を作りたがる傾向にあるので、if を並べるよりもその週の最初の月曜日からループで判定していき、最初に平日となった日付と今日の日付を比較するのが良いと思います。
guest

回答3

0

メルマガ(?)配信のために、連休「明け」を判定したいってことなんですかね?
もっと愚直に「連休明け」をデータとして持ってしまうってのも一つのやり方かと。
配信条件は、「月曜で休日ではない日」か「連休明けの日」の条件で定義できるようになります。

投稿2020/11/21 23:18

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

jpholidayを利用した回答。

Python

1import datetime 2import jpholiday 3 4 5def get_first_weekday_date(base_date): 6 monday = base_date - datetime.timedelta(days=base_date.weekday()) 7 for i in range(7): 8 dt = monday + datetime.timedelta(days=i) 9 if jpholiday.is_holiday(dt): 10 # print(f"skipped {dt} {jpholiday.is_holiday_name(dt)}") 11 continue 12 return dt 13 return None # 一週間全部holidayの場合 14 15 16today = datetime.date.today() 17# today = datetime.date(2020, 5, 5) # 試験用 18 19target_date = get_first_weekday_date(today) 20 21print(target_date) 22if target_date == today: 23 print("今がその時だ♪")

投稿2020/11/22 00:15

編集2020/11/22 00:15
Daregada

総合スコア11990

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/11/24 03:21 編集

コードありがとうございました! Githubの案内の通り下記で会社休みが追加できたので、会社独自の休みを追加しつつこちらのコードで運用させていただこうと思います(ゆくゆくはGoogle API(Googleカレンダー)に移行を目指して)。 import jpholiday import datetime class TestHoliday(jpholiday.OriginalHoliday):   def _is_holiday(self, date):   if date == datetime.date(2020, 12, 31):    return True   return False   def _is_holiday_name(self, date):    return '会社休み' a=jpholiday.year_holidays(2020) print(a) ### [(datetime.date(2020, 1, 1), '元日'), (datetime.date(2020, 1, 13), '成人の日'), (datetime.date(2020, 2, 11), '建国記念の日'), (datetime.date(2020, 2, 23), '天皇誕生日'), (datetime.date(2020, 2, 24), '天皇誕生日 振替休日'), (datetime.date(2020, 3, 20), '春分の日'), (datetime.date(2020, 4, 29), '昭和の日'), (datetime.date(2020, 5, 3), '憲法記念日'), (datetime.date(2020, 5, 4), 'みどりの日'), (datetime.date(2020, 5, 5), 'こどもの日'), (datetime.date(2020, 5, 6), '憲法記念日 振替休日'), (datetime.date(2020, 7, 23), '海の日'), (datetime.date(2020, 7, 24), 'スポーツの日'), (datetime.date(2020, 8, 10), '山の日'), (datetime.date(2020, 9, 21), '敬老の日'), (datetime.date(2020, 9, 22), '秋分の日'), (datetime.date(2020, 11, 3), '文化の日'), (datetime.date(2020, 11, 23), '勤労感謝の日'), (datetime.date(2020, 12, 29), '会社休み'), (datetime.date(2020, 12, 30), '会社休み'), (datetime.date(2020, 12, 31), '会社休み')]
guest

0

もはや作ってしまった方が早いです。

jpholidayはメンテはされているようですが、一般的に使うライブラリである、という感じはうけません。また特別休日の追加はできるようなのですが、ベースとなる休日を削除はできなさそうなので、質問者の会社が「来週の月曜振替休日は年間の調整で出勤日にします!」みたいな状況には対応できないかもです。

また、最初は面倒ですが、このように作っておくことで、以下メリットがあると思います。

  • 来年の予定の登録や、今年の日程の修正が必要になった際に、登録がやりやすい(会社の休日一覧表とか、自分の年休日とかをそのまま登録すればよく、何か変更して別の日を登録するといった、登録に頭を悩ませることは不要)
  • 今後「週報の暫定版を、休日では無い週末に提出せよ!」みたいな別の要件が発生した場合に拡張がしやすい

データを、外側でファイル定義するとかは、もはや応用なので、ご自分でカスタマイズしてみてください。terateilはプログラマーの問題解決の場ですので、「完成されて後はコード見なくてもOK!といった回答」ではなく、「質問者様のコードに組み込んでどんどん拡張していただける元となる回答」を心がけました。

Python

1class MyDateTime: 2 # Prioritize upper set of days, ignore lower duplicated elements. 3 # Of courese, you must register the future calendars, 4 # in odrder not to work on many days! :-) 5 special_workdays = {} 6 special_holidays = { 7 '2020-1-2', '2020-1-3', '2020-8-11', '2020-8-12', '2020-8-13', '2020-8-14', 8 '2020-12-29', '2020-12-30', '2020-12-31' 9 } 10 national_holidays = { 11 '2020-1-1', '2020-1-13', '2020-2-11', '2020-2-23', '2020-2-24', 12 '2020-3-20', '2020-4-29', '2020-5-3', '2020-5-4', '2020-5-5', '2020-5-6', 13 '2020-7-23', '2020-7-24', '2020-8-10', '2020-9-21', '2020-9-22', 14 '2020-11-3', '2020-11-23' 15 } 16 17 @classmethod 18 def strptime(cls, s): 19 tdatetime = datetime.datetime.strptime(s, '%Y-%m-%d') 20 return datetime.date(tdatetime.year, tdatetime.month, tdatetime.day) 21 22 @classmethod 23 def is_workday(cls, day): 24 if day in map(cls.strptime, cls.special_workdays): 25 return True 26 if day in map(cls.strptime, cls.special_holidays): 27 return False 28 if day in map(cls.strptime, cls.national_holidays): 29 return False 30 return not (day.weekday() == 5 or day.weekday() == 6) 31 32 @classmethod 33 def is_holiday(cls, day): 34 return not cls.is_workday(day) 35 36 @classmethod 37 def is_sad_day(cls, day): # the 1st workday of the week 38 for i in range(day.weekday()): 39 if cls.is_workday(day - datetime.timedelta(days=day.weekday()-i)): 40 return False 41 return cls.is_workday(day) 42 43for day in ['2020-11-21', '2020-11-22', '2020-11-23', '2020-11-24', '2020-11-25']: 44 print(day, '= sad day?', MyDateTime.is_sad_day(MyDateTime.strptime(day))) 45 46#2020-11-21 = sad day? False 47#2020-11-22 = sad day? False 48#2020-11-23 = sad day? False 49#2020-11-24 = sad day? True 50#2020-11-25 = sad day? False

投稿2020/11/21 23:58

編集2020/11/22 01:22
toast-uz

総合スコア3266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/11/22 01:02 編集

jpholiday を使わずデータを用意してそれを参照するというのは間違っていません。 しかし、そのデータの作成方法が問題です。まずここに挙げられたデータが間違っていないかどうか確認するところから始めなければいけないし、このデータだけでは将来の実用に不十分です。来年以降のデータ作成を手作業で行うことになります。 データの作成方法に言及しないというのであれば、わざわざこんな中途半端なロジックを実行時に走らせなくても、te2ji さんの回答のように配信日そのものをデータとして持っていればいいと思います。そうすればデータ作成と判定でロジックが分散しないのでメンテしやすくなるでしょう。 そもそもコードの中に大量のデータをぶち込んでそれをメンテするとか、なかなか気持ちの悪い設計です。
can110

2020/11/22 00:28

とりあえず「special_workdays = {'2020-11-23'}」としてみましたが、'2020-11-23'の月曜日はFalseとなりました。使い方が間違っているでしょうか?
toast-uz

2020/11/22 00:39

can110様、ご指摘ありがとうごさいます。specialは優先判断しないといけないですね。修正してみましたのでご確認ください。
can110

2020/11/22 00:49

確認してみました。 あと気になったのがspecial_holidaysとspecial_workdaysに同じ日を登録し(てしまっ)たときの挙動です。 special_workdaysを優先するか、同日登録をチェックしてほしいかと思いました。
toast-uz

2020/11/22 01:06

can110様、ご指摘ありがとうごさいます。希少性からspecial_workdaysを優先させた方がよいのは同意です。それ以上は、基本的には質問者様のコードに組み込んでカスタマイズしていただくことが前提ですので、注意文章を冒頭に入れておくまで、としました。ご確認ください。
Zuishin

2020/11/22 01:49 編集

保守性と拡張性と信頼性に乏しく、既存のライブラリを使う方が良いと思います。 スペシャルなんとかこそ質問で全くふれられていない応用で、回答として蛇足ですが、その蛇足を除くとこの回答には見るべきところが何もありません。 それらもデータをあらかじめ作成するのであれば、データ使用時ではなく作成時に演算すべきことです。
kyoya0819

2020/11/22 14:59

> 一般的に使うライブラリである、という感じはうけません。 これの理由の解説をいただけると幸いです。
toast-uz

2020/11/22 15:41 編集

kyoya0819様、理由は以下の3つの観点の総合です ・【正式さ】バージョン0点台 ・【開発体制や更新頻度】ほぼ1人でメンテしている ・【利用の多さ】terateilを3か月やってるけど使っている質問者様を初めて見た
Zuishin

2020/11/23 00:40 編集

つまりこの回答のコードのバージョンは 1 点以上と。 より信頼性の高いライブラリを紹介するならわかりますが、誰もメンテしない未完成の自作を持ってくる理由としては意味不明です。 現にあなたのコードはバグ入りだったわけですし。
退会済みユーザー

退会済みユーザー

2020/11/23 07:04 編集

皆さんご回答本当にありがとうございます。 Pythonというかプログラミング自体始めたばかりで、teratailの皆さんの熱さ親切さに驚いています。 ご回答/ご指摘いただいて”ライブラリの信頼性”という観点すら持ち合わせていないことに気づきました。 今回の背景は ・「毎日の在庫状況レポートをメール配信するよう」という指示を受ける →ここで休みには配信が行かないようにjpholidayを導入しました。 ・いざ出来上がって配信を始めたら「週初めには先週のダイジェストもメールの中に入れるように」という指示を受ける →ここで質問を投稿した次第です。 つまり稼働は営業日すべてになるので、例外としての”休み”が簡単にリストアップできるjpholidayを使い続けることになると思います(toast-uzさんせっかくコード書いてくださったのにすみません。これはこれで保存して勉強させていただいてます)。 ご指摘を受けて、長期休み前に確認のためにjpholidayの中身を自分自身に配信するスクリプトを作っておこうと思いました。 どんな手段を用いたとしても、小さい会社なので休みは直前に社長からの通達で決まりますので、メンテが必要になります。その時に併せてjpholidayに休みを追加したり中身の検証をすればそれでよいかと思ったのですがどうでしょうか? toast-uzさんやZuishinさんのコメントを拝見して、今後としてはGoogle APIの使い方を覚えて祝日の取得先をjpholidayからGoogleカレンダーに移行するのがより信頼性が高く一番ローメンテになりそうなのなかな?と思いました。 ー自分も日常的に使うのでアクセシビリティがいい ー会社休みをGoogleカレンダーで管理するようになって休みを他人に勝手に入力してもらう道筋もある という観点で。
toast-uz

2020/11/23 07:58 編集

質問者様がよいと思われたやり方で、よいと思います。 ただ、jpholidayの独自休日追加は、少し難しいように思います(if文で日付を直接記述して判定するような公式サンプルです)のと、休日営業日は設定できないようですので、ご注意ください。 https://pypi.org/project/jpholiday/ また、開発者ご本人が「個人で使っているものをpythonに書き換える際にせっかくなのでPyPIに公開しました」と述べられています。それ自体はとても尊敬すべきことですが、利用する側が「PyPI公開なので素晴らしいものに違いない」と過剰に期待されないように注意すべきと思います。GitHubのコードもざっと見ましたが、コードの中にいろいろな数字(マジックナンバー)が埋め込まれており、ご本人以外にはメンテが難しいように思います。 https://www.lalcs.com/2017/10/01/5ef8aa0226e8dc0001e82144/
Zuishin

2020/11/23 08:03

完全に詐欺師のやり方。 マジックナンバーって日付でしょう。建国記念日は 2 月 11 日なので 2 と 11 という数字が必要になるのは当然です。
kyoya0819

2020/11/24 01:09

完全に主観を言わせていただくと、toast-uzさんのコードを使うなら、該当のレポジトリを使った方が良いですし、できることならGoogleカレンダーAPIで祝日を取ってくるのがいいと思います。 参考)https://www.yoheim.net/blog.php?q=20160501
toast-uz

2020/11/24 03:57 編集

kyoya0819様、コメントありがとうごさいます。私の回答の主張は、私のコードを使う or ライブラリを使う のuse or useの選択ではなく、(私のコードを参考に)自ら質問者様が作る or ライブラリを使う、のmake or useの選択を提示したまでです(後者でも一部makeは必要なのでイチゼロ議論ではありません)。回答者様はそれをご理解された上で後者を選択されたものと思います。kyoya0819様としてご理解の上でのコメントでしたら余計な返答すみません。
Zuishin

2020/11/24 04:12

> もはや作ってしまった方が早いです。 と書いてあります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問