0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

動機

fx-9750GIII や fx-CG50 には Finance アプリがあり、この中に日付・曜日計算機能がある。
一方、 Graph Math+ には今のところ Finance アプリが搭載されていない(2025年のアップデートで搭載予定とする情報もあるが)。
そこで MicroPython で曜日を求めるスクリプトを入れておこうと思い立った。

曜日判定はツェラーの公式を使う

Graph Math+ に搭載されている MicroPython では datetime モジュールなどを利用することができない。
そこでツェラーの公式を使って計算で求めるのが一般的な解決法。実際に Python コードを公開している人がいた。

そこでこれを電卓で入力しやすい形に微修正して…

zeller.py
def zeller(year, month, day):
  if month <= 2:
    year -= 1
    month += 10
  else:
    month -= 2
  w = day + int((13 * month - 1) / 5) + year + int(year / 4) - int(year / 100) + int(year / 400)
  x = w % 7
  return x

ws = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]

date = input('YYYYMMDD? ')

year = int(date[0:4])
month = int(date[4:6])
day = int(date[6:8])

x = zeller(year, month, day)

print('%d/%d/%d(%s)' % (year, month, day, ws[x]))

こんな感じに実行できる。

zeller.py 実行画面
YYYYMMDD? 20241201
2024/12/1(Sun)
>>>

日数計算

下記ブログ記事にあった「VB6のプログラムにあった計算方法」の式を使ってみる。

このやり方が秀逸なのは、3月を起点にした月数に30.59を掛けて整数化しているところ。
3月から前月までの累積日数と30違いで一致する。

日数計算
def datediff(y1, m1, d1, y2, m2, d2):
  if m1 == 1 or m1 == 2:
    m1 = m1 + 12
    y1 = y1 - 1
  
  if m2 == 1 or m2 == 2:
    m2 = m2 + 12
    y2 = y2 - 1
  
  days1 = int(365.25 * y1) + int(y1 / 400) - int(y1 / 100) + int(30.59 * (m1 - 2)) + d1
  days2 = int(365.25 * y2) + int(y2 / 400) - int(y2 / 100) + int(30.59 * (m2 - 2)) + d2
  days = days2 - days1
  return days

こんな感じで日数が求められる。

日数計算
YYYYMMDD? 20241127
2024/11/27(Wed)
Target? 20250101
20241127Wed-20250101Wed
Diff: 35

何日後・何日前も求めよう

上記の整数化された年月日は、0年3月1日を31としたシリアル値となっている。
このシリアル値から日付を求めることができれば、何日後・何日前の日付を求めることが可能だ。
400年、100年、4年、年、月、日と順にたどっていけば復元できるはず。
…が、簡単にはいかない。
かなりトリッキーに処理をした。もっとよい方法があると思う。

完成品

  • Graph Math+ が未着の段階で作成したので、 Google Colab と fx-CG50 のエミュレータで動作確認をした。 fx-CG50 でも使えるが、文字サイズが大きいため、一部の文字ははみ出して表示される。
  • エラー処理はしていない。
  • グレゴリオ暦以前(1582年以前)の日付は正しくない。
date.py
def ymd(date):
  year = int(date[0:4])
  month = int(date[4:6])
  day = int(date[6:8])
  return year, month, day

def zeller(year, month, day):
  if month <= 2:
    year -= 1
    month += 10
  else:
    month -= 2
  w = day + int((13 * month - 1) / 5) + year + int(year / 4) - int(year / 100) + int(year / 400)
  x = w % 7
  return x

def date_to_serial(year, month, day):
  if month == 1 or month == 2:
    month = month + 12
    year = year - 1
  s_day = int(365.25 * year) + int(year / 400) - int(year / 100) + int(30.59 * (month - 2)) + day
  return s_day

def serial_to_date(s_day):
  s_day = s_day - 31
  y400 = int(s_day / 146097)
  s_day = s_day - y400 * 146097
  y100 = int(s_day / 36524)
  if y100 == 4:
    y100 = 3; y4 = 0; y1 = 99; month = 11; day = 29
  else:
    s_day = s_day - y100 * 36524
    y4 = int(s_day / 1461)
    s_day = s_day - y4 * 1461
    y1 = int(s_day / 365)
    if y1 == 4:
      y1 = 3; month = 11; day = 29
    else:
      s_day = s_day - y1 * 365
      for i in range(12):
        if s_day < round((i+1)*30.6):
          month = i ; day = s_day - round(i*30.6) + 1 ; break
  year = y400*400 + y100*100 + y4*4 + y1
  month = month + 3
  if month > 12:
    year = year + 1
    month = month - 12
  return year, month, day

ws = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]

while True:
  date = input('YYYYMMDD? ')
  if len(date) != 8:
    break
  
  else:
    year, month, day = ymd(date)
    x = zeller(year, month, day)
    s_day1 = date_to_serial(year, month, day)
    print('{:04}/{:02}/{:02}({})'.format(year, month, day, ws[x]))
    date2 = input('Target/Diff? ')

    if len(date2) == 8:
      year_t, month_t, day_t = ymd(date2)
      y = zeller(year_t, month_t, day_t)
      s_day2 = date_to_serial(year_t, month_t, day_t)
      days = s_day2 - s_day1
      print('{:04}{:02}{:02}{}-{:04}{:02}{:02}{}'.format(year, month, day, ws[x], year_t, month_t, day_t, ws[y]))
      print('Diff: %d' % days)

    else:
      days = int(date2)
      s_day2 = s_day1 + days
      year_t, month_t, day_t = serial_to_date(s_day2)
      y = zeller(year_t, month_t, day_t)
      print('{:04}{:02}{:02}{}[{:+}d]'.format(year, month, day, ws[x], days))
      print('{:04}/{:02}/{:02}({})'.format(year_t, month_t, day_t, ws[y]))

使い方

  • 曜日だけ求めたい時は最初のInputで終わらせればよい(ACキーで止められる)。

  • 次のInputを8桁で入力すると、日数が表示される。
    python_date_1.png

  • 次のInputを8桁以外で入力すると、日付が表示される。負の値も入力可。
    python_date_2.png

  • 日数or日付の答を出力した後、最初の入力( YYYYMMDD? )に戻る。ここで8桁以外の入力(EXEキーのみも可)で正常終了する。
     

  • fx-CG50 や fx-9750GIII で動作させると以下のようになる(いずれもエミュレータ)。
    python_date_3.png
    python_date_4.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?