「コンピュータ演習」の授業,今年最後の「13日」を記念した特別企画。
本日,2023年12月13日は(水曜日だけど)今年最後の「13日」。また,今年最初の「13日」,2023年1月13日は金曜日であった。いわゆる「13日の金曜日」。
なぜ「13日の金曜日」が特別に扱われるのかについては,素養が必要であるので,各自調査すること。ここでは,Wikipedia をあげておく。
2023年のカレンダーの確認(13日の金曜日)
各自のスマホ等で 2023 年のカレンダーを確認すること。
参考までに,情報基盤センターの「学年暦」では,日本の祝日や弘前大学学年暦を表示している。各自のスマホやパソコンのカレンダーにも登録できる。
Python の calendar
を使う
calendar
を import して,月のカレンダーを出力します。以下のセルを「実行」してください。
calendar モジュールの import
import calendar as cal
# 2023年1月の月カレンダーを出力
cal.prmonth(2023, 1)
# ヨーロッパ的慣習に従い,月曜日 (Mo) 始まり
Python の locale
で曜日を日本語に
既定では,英語表記で週のはじまりが月曜日(Mo)になっています。これを日本語表記にし,週のはじまりを日曜日にするには,以下のようにします。(曜日が日本語表示になると,レイアウトが崩れてしまいます。)
locale モジュールの import
import locale
# locale を日本語に設定。これ以後は日本語表示に。
locale.setlocale(locale.LC_TIME, 'ja_JP.UTF-8')
# locale を 日本語に設定した後の「曜日」
print(cal.day_abbr[:]) # 短縮名
print(cal.day_name[:]) # 曜日名
# 週の始まりを日曜日に。calendar.SUNDAY = 6 のこと。
cal.setfirstweekday(cal.SUNDAY)
cal.prmonth(2023, 1)
# レイアウトが崩れる...
# 曜日表示の間のスペースが1個多い...
参考:日本語表示時の曜日 header ずれ対策
本題ではありませんが,日本語表示時に曜日ヘッダに余計なスペースがはいってレイアウトが崩れる件について,とりあえず(やっつけの)対策をしてみます。(日本語等幅フォントが適切に設定されているという前提です。Safari だと対策後もレイアウトがずれて見えます。iOS だと Safari 以外のたとえば Firefox であっても表示は Safari と同じです。)
曜日ヘッダは,cal.weekheader()
で設定可能です。以下では,.rstrip()
で右端のスペース(があったらそれ)を取り除いています。
# 曜日ヘッダのスペースは,以下のように設定可能
headerold = cal.weekheader(2).rstrip()
headernew = cal.weekheader(1).rstrip()
print(headerold)
print(headernew)
formatmonth()
でひと月分のカレンダーを文字列としてとり,曜日ヘッダの部分を replace()
で headernew
に置き換える関数を jprmonth()
として定義します。
# import calendar as cal
# import locale
# locale.setlocale(locale.LC_TIME, 'ja_JP.UTF-8')
def jprmonth(theyear, themonth):
headerold = cal.weekheader(2).rstrip()
headernew = cal.weekheader(1).rstrip()
tmp = cal.TextCalendar(firstweekday=6).formatmonth(theyear,themonth)
tmp1 = tmp.replace(headerold, headernew)
print(tmp1)
jprmonth(2023, 12)
年間カレンダー表示は
cal.pryear()
ではなくて
cal.TextCalendar().pryear()
のようです。
cal.TextCalendar(firstweekday=6).pryear(2023)
以上のように,年間カレンダーも曜日ヘッダがずれているので,対策をしてみます。
formatyear()
で一年分のカレンダーを文字列としてとり,曜日ヘッダの部分を replace()
で置き換える関数を jpryear()
として定義します。
# import calendar as cal
# import locale
# locale.setlocale(locale.LC_TIME, 'ja_JP.UTF-8')
def jpryear(theyear):
tmp = cal.TextCalendar(firstweekday=6).formatyear(theyear)
headerold = cal.weekheader(2).rstrip()
headernew = cal.weekheader(1).rstrip()
yhdrold = ((headerold + ' '*7)*3).rstrip()
yhdrnew = ((headernew + ' '*6)*3).rstrip()
print(tmp.replace(yhdrold, yhdrnew))
jpryear(2023)
参考: !
で cal
コマンド
Python の calendar モジュールは日本語表示にすると,微妙に表示がずれてしまいます。(対策はしましたが… )
弘大 JupyterHub サーバは Linux ですから,JupyterHub のホームの「新規」から「端末」を選ぶと,bash のプロンプトに続いてコマンドを打ち込むことができます。
わざわざ「新規」から「端末」を選ばなくても,Python 3 のノートブックであれば,以下のように!
と書いたあとにコマンドを入力して「▶︎ Run」(または Shift Enter)すると,結果が表示されます。こちらは,日本語表示でもレイアウトの崩れはありません。
! cal
# 今月のカレンダーが表示される
表示する月や年を指定するには,以下のように。
cal (Month) Year
引数が2つの場合は,最初が月で次が年,引数が1つの場合は年をあらわします。
# 2023 年 1 月のカレンダーを表示する
! cal 1 2023
# 2023 年の年間カレンダーを表示する
! cal 2023
# イギリス(アメリカを含む)でグレゴリオ暦になったとき
! cal 9 1752
# calendar モジュールは理想化されたカレンダー
# つまり現在のグレゴリオ暦を過去と未来両方に無限に拡張したものを使用
jprmonth(1752, 9)
練習問題 2:閏年
来年,2024年は閏年である。2月のカレンダーを表示して,このことを確認し,あわせて西暦1900年,2000年,2100年の2月のカレンダーを表示して閏月の確認をし,その意味するところを述べよ。
# 2024年は4で割り切れるので閏年
! cal 2 2024
jprmonth(2024, 2)
# 1900 も 2000 も 2100 も 4 で割り切れるが...
! cal 2 1900
! cal 2 2000
! cal 2 2100
jprmonth(1900, 2)
jprmonth(2000, 2)
jprmonth(2100, 2)
西暦1900年,2000年,2100年はそれぞれ4で割り切れる年なので閏年のはず… と思いきや…
Python の datetime
を使う
日付や曜日を扱う datetime
を import して,曜日を調べてみます。
datetime モジュールの import
import datetime as dt
2023年1月13日の曜日を表示する例です。
thedate = dt.date(2023, 1, 13)
print(thedate.weekday())
出力された数字が何曜日を示しているかは,以下のようにすればわかります。
for i in range(7):
print('cal.day_abbr[%d] = %s' % (i, cal.day_abbr[i]))
for i in range(7):
print('cal.day_name[%d] = %s' % (i, cal.day_name[i]))
13日の金曜日に関する問題
問題 1
2023年の1月から12月までの13日の曜日を全て表示せよ。
theyear = 2023
theday = 13
for month in range(1, 13):
thedate = dt.date(theyear, month, theday)
youbi = cal.day_name[thedate.weekday()]
print('%4d年%2d月%2d日は %s' % (theyear, month, theday, youbi))
問題 2
2023年の1月から12月まで,13日が金曜日である月のみを表示せよ。
theyear = 2023
theday = 13
print('%2d日が金曜日なのは' % theday)
for month in range(1, 13):
thedate = dt.date(theyear, month, theday)
youbi = cal.day_name[thedate.weekday()]
if youbi == '金曜日':
print(' %4d年%2d月' % (theyear, month))
問題 3
2023年から2122年までの100年間に,13日の金曜日は1年あたり平均何回あるか。
# 13日の金曜日の回数
count = 0
year0 = 2023
year1 = 2123
for year in range(year0, year1):
for month in range(1, 13):
thedate = dt.date(year, month, 13)
youbi = cal.day_name[thedate.weekday()]
if youbi == '金曜日':
# count = count + 1 のこと
count += 1
print('13日の金曜日は... ')
print('%d年間で %d回,年平均 %.2f回'
% ((year1-year0), count, (count/100))
)
問題 4
13日の金曜日は1年に必ず1回以上あることを示せ。
ヒント:2023年のように,1月1日が日曜日の場合は,1月13日が金曜日となる。では,1月1日が他の曜日の場合はどうなるか。残りの曜日の場合を調べればよいことになる。
例えば,1月1日が日曜日(weekday = 6
)なら,各月末までの日数の和を 7 で割った余りが 0 なら,次の月初めが日曜日ということになる。
print('月初めの一日が日曜日となる月を表示する。')
# 閏年でない場合
print('閏年でない場合')
# 各月の日数
mdays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
# 日曜日から計算してもらおう
wrange = [6,0,1,2,3,4,5]
for weekday in wrange:
print(' 1月1日が%sなら... ' % cal.day_name[weekday], end=' ')
if (cal.day_name[weekday]) == '日曜日':
print(' 1月1日が日曜日', end=' ')
tmp = 0
for i in range(11):
tmp += mdays[i]
# 月の日数の和を 7 で割った余りで
# 次の月初めの曜日が決まるから...
if tmp % 7 == 6 - weekday:
print('%2d月1日が日曜日' % (i+2), end=' ')
print('')
print('')
# 閏年の場合
print('閏年の場合')
# 2月の日数のみを 29 に変更
mdays[1] = 29
# 以下は閏年でない場合と同じ
for weekday in wrange:
print(' 1月1日が%sなら... ' % cal.day_name[weekday], end=' ')
if (cal.day_name[weekday]) == '日曜日':
print(' 1月1日が日曜日', end=' ')
tmp = 0
for i in range(11):
tmp += mdays[i]
# 月の日数の和を 7 で割った余りで
# 次の月初めの曜日が決まるから...
if tmp % 7 == 6 - weekday:
print('%2d月1日が日曜日' % (i+2), end=' ')
print('')
print('')
print('したがって,閏年か否かにかかわらず')
print('1月1日が日〜土のいかなる曜日で始まっても')
print('その年には必ず1回以上,月初めの1日(ついたち)が日曜日となる月があり,')
print('その月の13日が金曜日となる。')
以上の結果が正しいか,1例をあげて検証してみます。
たとえば,1月1日が月曜日で閏年となる年を西暦2000年以降で数例,探してみます。
for year in range(2000, 2100):
date = dt.date(year, 1, 1)
youbi = cal.day_name[date.weekday()]
# 1月1日が月曜日で,年が4で割り切れる場合
if youbi == '月曜日' and year % 4 == 0:
print(year)
閏年である2024年の場合,1月1日が月曜日なら,9月1日と12月1日が日曜日となることを確認してみます。
# 閏年の 2024 年1月1日が月曜日であることを確認
jprmonth(2024, 1)
# 閏年の 2024 年の9月と12月のカレンダーを確認
jprmonth(2024, 9)
jprmonth(2024, 12)
問題 5
13日の金曜日が1年に3回あるのはどんな条件の年か。
解答:
問題 4 の結果から明らかなように,
閏年ではなくて,1月1日が「木曜日」の場合,2月13日,3月13日,11月13日の3回。
または閏年であって,1月1日が「日曜日」の場合,1月13日,4月13日,7月13日の3回。