1
1
テーマ、知りたいこと
毎週顧客からデータが届きます。
たまに遅れる時もありますが、先週の分、今週の分、というように届きます。ファイル名には週番号(1〜52)がついています。
中身のデータは実際には2週遅れで、たとえば2023年34週目に届いたデータには2023-32のデータが入っております。
ですがたまにバグで違うものが混ざっていることがあるので2023-32のものだけをフィルターで取り出しています。
こちらをpythonで自動化したいと考えています。
最初にデータの週ナンバーをいれる。(基本的には今の週ナンバーをいれる、例34)
処理としては、ツールを起動した時点の年(2023)と、「入力した数字-2」(34-2)に一致するものを取得するというようにしようと思いました。
ですがこれだと2024年1〜2週目に必ずエラーになります。2023-52週目をを取得できない。2024-0とかになってしまう。
他にどんな方法があるでしょうか。
ツールを開いた時の週を自動で取得しようかと思いましたが遅れて届く場合があるので手入力がいいかと思いました。
もしくは最初の手入力を2023-32にするか迷いましたが、出来れば手入力の回数を減らせればと思い質問しました。また、新たに保存するファイル名にデータの週番号(34)を入れたいので、入力した数字を使おうと思っていました。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答17件
#1
総合スコア38352
投稿2023/09/20 10:28
ですがこれだと2024年1〜2週目に必ずエラーになります。2023-52週目をを取得できない。2024-0とかになってしまう。
ChatGPTの回答
Pythonを使用して、基準となる年、週番号、および何週前かを入力として受け取り、該当する年と週番号を計算する関数を示します。このために、datetime
モジュールを使用します。
以下がその関数です:
python
1import datetime 2 3def calculate_week_number(year, week_number, weeks_ago): 4 # 基準の日付を設定(年の1月1日) 5 reference_date = datetime.date(year, 1, 1) 6 7 # 指定された週番号と週数を計算 8 target_date = reference_date + datetime.timedelta(weeks=(week_number - 1) - weeks_ago) 9 10 # 計算された日付から年と週番号を取得 11 target_year = target_date.year 12 target_week_number = target_date.strftime("%U") 13 14 return target_year, int(target_week_number) 15 16# テスト 17year = 2023 # 基準の年 18week_number = 40 # 基準の週番号 19weeks_ago = 2 # 何週前か 20 21result_year, result_week_number = calculate_week_number(year, week_number, weeks_ago) 22print(f"基準年: {year}, 基準週番号: {week_number}") 23print(f"{weeks_ago}週前の年: {result_year}, 週番号: {result_week_number}")
この関数は、指定された基準年と週番号から、何週前かを考慮して該当する年と週番号を計算します。テストの例では、基準年が2023年、基準週番号が40週目で、2週前の年と週番号を計算しています。関数を使用すれば、任意の基準と週数に対して計算を行うことができます。
このコードはPythonのdatetime
モジュールを使用しており、日付の計算を行うのに便利です。
#2
総合スコア14291
投稿2023/09/20 10:28
何にひっかかっているのかわからないのですが、
ですがこれだと2024年1〜2週目に必ずエラーになります。2023-52週目をを取得できない。2024-0とかになってしまう。
たとえば、"2024, 1" のとき "2023, 51" が得られればいいのでしょうから、条件分岐してそのように計算すればいいだけではないかと思います。
python
1year_now = # 年 2week_now = #週 3 4week = week_now -2 5year = year_now 6if week < 1: 7 week = week + 52 8 year = year_now - 1 9two_week_before = [year, week]
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#3
総合スコア4443
投稿2023/09/20 13:02
編集2023/09/21 04:23与えられた週番号の週の最初の日の14日前の日の週番号です。
週番号は取り得る値の範囲が0から53まであるのです。
[訂正] 週番号の方式によって0から53まで、1から53まで、1から54までの場合がありえます (ほかにはないと思う……多分)。
ちなみに、1から52までということはありえません。それだと1年のうちの364日間しか表せないからです。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#5
総合スコア4443
投稿2023/09/20 22:06
編集2023/09/20 22:48質問者さんのおっしゃっている方法では年をまたいだ週の計算ができないのは事実です。しかし、TakaiYさんのおっしゃる方法でも、結果が0や53の付近になるような場合を正しく扱えないことがありますよね。
ちなみに週番号には、年の第1週初日の決定方法や前年から始まっている週の数え方などによって、いくつかの方式がありえます (これらの中には何らかの標準として定められているものもありますが、特定の実装が標準に準拠しているとは限りません)。
どのような方式を採用するのか明確にしていただいたほうがコードの提示などはしやすいかもしれません。が、それが難しければ投稿者各自で前提とする方式を述べていただくと認識の齟齬が起きにくいと思います。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#6
総合スコア1109
投稿2023/09/20 23:55
コード
議論のベースラインを提出します。週番号は1-54です。翌年1月の日を前年の31に加算すれば前年の週番号として見ることができます。
python
1# 2# 閏年の判定 3# 4def isLeapYear(yyyy): 5 return (yyyy % 400 == 0) or ((yyyy % 100 != 0) and (yyyy % 4 == 0)) 6 7# 8# 各月の日数(うるう年対応) 9# 10def daysMonths(yyyy): 11 if isLeapYear(yyyy): 12 return [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] 13 else: 14 return [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] 15 16# 17# 曜日を判定する(ツェラーの公式) 18# 19# 0: Sun, 1: Mon, 2: Tue, 3: Wed, 4: thu, 5: Fri, 6: Sat 20# 21def dayOfWeek(yyyy, mm, dd): 22 if mm in [1,2]: 23 yyyy = yyyy - 1 24 mm = mm + 12 25 return (yyyy + yyyy // 4 - yyyy // 100 + yyyy // 400 + (13 * mm + 8) // 5 + dd) % 7 26 27# 28# Julian Dateの作成 29# 30def julianDate(yyyy, mm, dd): 31 numDys = daysMonths(yyyy) 32 return sum(numDys[:mm-1]) + dd 33 34# 35# 第何週目か 36# 37def weekOfYear(year_, month_, day_): 38 return (dayOfWeek(year_, 1, 1) + julianDate(year_, month_, day_) - 1) // 7 + 1
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#7
総合スコア1109
投稿2023/09/21 05:46
編集2023/09/21 05:56日付データがあれば第n週は無関係
日付データがあれば週の番号nは無関係ですね。やりたいことを整理すると次のようになります。
- 基準日dの14日前の日付d1を求める。
- d1を含む週の開始日w1と終了日w2を求める
- [w1,w2]の範囲に含まれるデータを選択する
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#9
総合スコア1109
投稿2023/09/21 09:33
編集2023/09/21 10:58#8
うるう年で1/1が土曜日の年なら12/31が日曜日になります。2028年は何週ありますか。
ただし、2028年の第1週を前年の最後の週に含めると53になります。
週給で生活したり週単位で予算を組む文化では、週の区切りで会計月や会計年度を取り決めています。
やはり仕様を確認するのが先ですね。
1月の第1日曜日で始まる週をその年の第1週とすれば最大53週しかなくなります。
ルール変更に合わせてコードを修正しましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#11
総合スコア1109
投稿2023/09/21 21:36
編集2023/09/21 22:44アメリカ方式(週は日曜日開始)だと、12/31が土曜日以外なら最後の週はないものと考えて、ある年の週の数は次の式で求めます。
python
1math.ceil((ある年の日数 - (その年の12/31の曜日コード + 1)) / 7) # 曜日コードは 0: 日曜、...、6: 土曜
12/31が土曜日の場合を追記します。
python
1math.ceil(ある年の日数 / 7)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#14
総合スコア4443
投稿2023/09/22 04:26
編集2023/09/22 05:13週番号はお客さんが振っているのですよね。おっしゃっている方式はお客さんの採用している方式でしょうか。
そうだとして、既存のライブラリなどが望み通りの方式に対応しているとはかぎりません。ですので、対応していなければ自分でその方式の週番号を処理するプログラムを書くしかないでしょう。
で、おっしゃっている方式について言うと、似たような結果を出せそうなものをみつけました。datetimeモジュールに含まれるstrftime/strptimeで、%W
書式文字列を使えば似たようなものになります。ただし、この方式では前年から続く週は途中で週番号をリセットされて新年の「第0週」として扱われる、というところが異なりますね。ですので、strftimeの出した結果が「今年の第00週」だったら「前年の最終週」に置き換える、といった改造が必要です。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#15
総合スコア38352
投稿2023/09/22 04:57
- 週の始まりは月曜日
- 新年の最初の月曜日に先立つ日は前年の最終番号とする
であれば、以下でよいかと思います。
Python
1from datetime import date, timedelta 2 3def calculate_week_number(year, month, day, weeks_ago = 0): 4 5 # 基準の日付 6 reference_date = date(year, month, day) 7 8 # 指定された週数だけ過去の日付 9 target_date = reference_date + timedelta(weeks=-weeks_ago) 10 11 # 過去の日付の年と週番号を取得 12 target_year = target_date.year 13 target_week_number = int(target_date.strftime("%W")) 14 15 # 新年の最初の月曜日に先立つ日は 0週 -> 前年の最終番号とする 16 if target_week_number <= 0: 17 target_year -= 1 18 target_week_number = int(date(target_year, 12, 31).strftime("%W")) 19 20 return target_year, target_week_number 21 22 23# 指定した当日 24print(calculate_week_number(2024,12,30)) # (2024, 53) 25print(calculate_week_number(2025, 1, 1)) # (2024, 53) 26print(calculate_week_number(2025, 1, 6)) # (2025, 1) 27 28# 過去 29print(calculate_week_number(2025, 1, 6, 1)) # (2024, 53) 30print(calculate_week_number(2025, 1, 6, 2)) # (2024, 52)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。