質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.31%
Python

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

意見交換

クローズ

17回答

1906閲覧

任意の週番号から2週前を取得したい

kumafumo

総合スコア1

Python

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

1グッド

1クリップ

投稿2023/09/20 09:18

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)を入れたいので、入力した数字を使おうと思っていました。

rumachi👍を押しています

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

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

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

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

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

回答17

#1

can110

総合スコア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

TakaiY

総合スコア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

ikedas

総合スコア4443

投稿2023/09/20 13:02

編集2023/09/21 04:23

与えられた週番号の週の最初の日の14日前の日の週番号です。

#2

週番号は取り得る値の範囲が0から53まであるのです

[訂正] 週番号の方式によって0から53まで、1から53まで、1から54までの場合がありえます (ほかにはないと思う……多分)。

ちなみに、1から52までということはありえません。それだと1年のうちの364日間しか表せないからです。

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

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

#4

TakaiY

総合スコア14291

投稿2023/09/20 14:19

週番号は取り得る値の範囲が0から53まである

うーん、やはり、何が問題なのかまったくわかりません。

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

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

#5

ikedas

総合スコア4443

投稿2023/09/20 22:06

編集2023/09/20 22:48

#4

質問者さんのおっしゃっている方法では年をまたいだ週の計算ができないのは事実です。しかし、TakaiYさんのおっしゃる方法でも、結果が0や53の付近になるような場合を正しく扱えないことがありますよね。

ちなみに週番号には、年の第1週初日の決定方法や前年から始まっている週の数え方などによって、いくつかの方式がありえます (これらの中には何らかの標準として定められているものもありますが、特定の実装が標準に準拠しているとは限りません)。

どのような方式を採用するのか明確にしていただいたほうがコードの提示などはしやすいかもしれません。が、それが難しければ投稿者各自で前提とする方式を述べていただくと認識の齟齬が起きにくいと思います。

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

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

#6

xebme

総合スコア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

xebme

総合スコア1109

投稿2023/09/21 05:46

編集2023/09/21 05:56

日付データがあれば第n週は無関係

日付データがあれば週の番号nは無関係ですね。やりたいことを整理すると次のようになります。

  • 基準日dの14日前の日付d1を求める。
  • d1を含む週の開始日w1と終了日w2を求める
  • [w1,w2]の範囲に含まれるデータを選択する

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

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

#8

jbpb0

総合スコア7658

投稿2023/09/21 09:15

ファイル名には週番号(1〜52)がついています。

7*52=364
で、1年の365日(うるう年は366日)よりもちょっと少ないですが、ファイル名に53が付く年は無いのでしょうか?

たとえば、1月1日を含む週を1週目とする「アメリカ式」では、
2022年は53週
2023年は52週
ですが

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

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

#9

xebme

総合スコア1109

投稿2023/09/21 09:33

編集2023/09/21 10:58

#8
うるう年で1/1が土曜日の年なら12/31が日曜日になります。2028年は何週ありますか。

ただし、2028年の第1週を前年の最後の週に含めると53になります。
週給で生活したり週単位で予算を組む文化では、週の区切りで会計月や会計年度を取り決めています。

やはり仕様を確認するのが先ですね。

1月の第1日曜日で始まる週をその年の第1週とすれば最大53週しかなくなります。
ルール変更に合わせてコードを修正しましょう。

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

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

#10

jbpb0

総合スコア7658

投稿2023/09/21 11:15

#9

2028年は何週ありますか。

週の始まりが日曜日で、1月1日を含む週を第1週とする アメリカ式 なら、53週だと思います

・2027年12月26日〜2028年1月1日が、2028年の第1週 (2028年1月1日を含むため)
・2028年12月24〜30日が、2028年の第53週
・2028年12月31日〜2029年1月6日が、2029年の第1週 (2029年1月1日を含むため)

 

やはり仕様を確認するのが先ですね。

そうですね

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

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

#11

xebme

総合スコア1109

投稿2023/09/21 21:36

編集2023/09/21 22:44

#10

アメリカ方式(週は日曜日開始)だと、12/31が土曜日以外なら最後の週はないものと考えて、ある年の週の数は次の式で求めます。

python

1math.ceil((ある年の日数 - (その年の12/31の曜日コード + 1)) / 7) # 曜日コードは 0: 日曜、...、6: 土曜

12/31が土曜日の場合を追記します。

python

1math.ceil(ある年の日数 / 7)

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

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

#12

ikedas

総合スコア4443

投稿2023/09/22 03:50

どうも#3 で述べた方法では十分ではないかもしれません。

週番号の方式には、年を越すと週の途中でも週番号をリセットするものがよくあります (むしろISO 8601などの、年をまたいでも前年の週番号が続く方式のほうが例外的かもしれません)。ですから単に2つ前の週番号を計算するだけだと、もうひとつの番号候補を見落としますね。

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

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

#13

kumafumo

総合スコア1

投稿2023/09/22 04:05

たくさんのご意見ありがとうございます。
単に2週前を取得すると年によって変わると思いましたので、任意の日付から2週前の日付を取得し、その週番号を取得するという方向で検討し直しています。
そして最初に月曜がくる週を1週目、たとえば2024年12月30週は53週目、2025年1/6を1週目としたいのですが、ISO方式だと木曜を含む週になるので計算が合いません。
最初の月曜日から数えることはできるでしょうか?

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

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

#14

ikedas

総合スコア4443

投稿2023/09/22 04:26

編集2023/09/22 05:13

#13

週番号はお客さんが振っているのですよね。おっしゃっている方式はお客さんの採用している方式でしょうか。

そうだとして、既存のライブラリなどが望み通りの方式に対応しているとはかぎりません。ですので、対応していなければ自分でその方式の週番号を処理するプログラムを書くしかないでしょう。

で、おっしゃっている方式について言うと、似たような結果を出せそうなものをみつけました。datetimeモジュールに含まれるstrftime/strptimeで、%W書式文字列を使えば似たようなものになります。ただし、この方式では前年から続く週は途中で週番号をリセットされて新年の「第0週」として扱われる、というところが異なりますね。ですので、strftimeの出した結果が「今年の第00週」だったら「前年の最終週」に置き換える、といった改造が必要です。

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

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

#15

can110

総合スコア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)

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

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

#16

kumafumo

総合スコア1

投稿2023/09/22 14:09

strftime/strptimeと%Wで無事に週番号を出すことができました。
ありがとうございました。

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

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

#17

ikedas

総合スコア4443

投稿2023/09/23 04:52

#16
できれば、どのようなコードで実現したのかを見せていただけるとうれしいです。

# strptimeで罠にかからなかったのかなーとか気になる

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

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

最新の回答から1ヶ月経過したため この意見交換はクローズされました

意見をやりとりしたい話題がある場合は質問してみましょう!

質問する

関連した質問