Python カスタム関数§09:100年日記、4桁で年月日を表現する

Python便利なカスタム関数

カスタム関数シリーズでは、便利に使えるオリジナル関数を紹介しています。

※カスタム関数は、一般的には「ユーザー定義関数」と呼ばれています

この記事が役に立つと思われる対象の人

1.pythonで日付を取り扱う方法を調べている人

2.日付の文字列を処理したい人

3.年月日の表現を少ない文字数で表現したいと考えている人(この記事では4桁で表現します)

4.百年通用する日記、スケジュールがほしい人 (^^;)

 

Pythonのdatetimeライブラがリーで日付を簡単に扱える

 

まず、pythonで日付を扱う方法を勉強しました。クイックリファレンス(python忘備録)の記事に記述していますので、ぜひ参考にしてください。→ pythonで日付を取り扱う

日付のフォーマットも含めて、よく忘れるので忘備録にしました。あまり親切な説明がないのですが、一度理解した方であれば、逆にシンプルでよいと思います。

 

ファイル名に使う日付の表現方法 「2020-09-12」 「20200912」「 200912」  をお使いですか?

 

年月日を使って、ファイル名をつけることって、よくありますよね。2020年9月12日だったとしたら

「20200912_営業議事録.xlsx」なんて、超あるあるですね。この年月日表現だと20200912と8文字です。年を下二桁にすると「200912」と6文字に減りました。さらに年を下一桁にすると00912になりますが、ちょっとやばいですよね。10年以上仕事を続ける人がほとんどですし、ファイル名が重複すること間違いなしですね。(^^;)

ということで、年月日をなんと「4桁」で表現する方法を考えました。しかも100年間通用します。

年を一桁、月を一桁、日を二桁の合計4桁です。

実は正直に告白します。年に使う文字を、あらかじめ100個用意しておきます。半角で使えて、わりと順番がわかりやすい文字がアルファベット、数字、半角カタカナですね。半角カタカナは、ちょっと抵抗ある人もいるかな?

でも、誤解が多いのですが、半角カタカナもUTFコードが割り当てられているので、決して「機種依存コード」ではないのです。パソコンのファイルシステムでトラブルことはまずないと考えていいでしょう。ただし、ネットの世界で、「ISO-2022-JP」という規格に変換するときだけ問題が起こるかもしれないと知っておいてください。

どうしてもいやな方は、仕事などで使う年数、例えば入社して40年~50年くらいの間は、アルファベットと数字で、それ以外は半角カタカナでプライベートの記録に使うというのはどうでしょうか?

今回、この一文字で表現する例が、こうです。

ycode_str=’ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzアイウエオカクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨワン1234567890′

このycode_strという変数に101個の文字をセットしているのが、ミソです。この順番を入れ替えたりすることで、ある程度自由度があると考えてください。

そして、月が一桁です。これは10月、11月、12月だけ一文字で表現すればよいので、簡単ですね。工場などで、製品のロット番号を扱う場合もよくやる方法ですが、10月をX、11月をY、12月をZとする方法を採用しました。

日は、そのまま01~31の二桁を使います。これを一桁で表現すれば、さらに文字は減りますが、あまりに視認性がわるいですので、4桁にしました。

次にコードを説明していきますので、そこで理解が進むと思います。

100年通用する4桁で年月日を表現する ycode()関数

まず、ライブラリーをインポートします。

import datetime
from dateutil.relativedelta import relativedelta

datetimeライブラリーは、pythonで日付を扱う標準のライブラリーです。dateutilは、pipインストールが必要ですが、日付の計算をするときにとても役立ちますので、ぜひとも導入してください。

 

関数の引数と出力について

def ycode(start_date='2020/1/1',filename='diary100years.txt',option_flg=False):

最初の引数 start_date=’2020/1/1’ は、デフォルトが2020/1/1になっています。この変数には、100年の最初の日付を設定します。おすすめは、誕生日です。

filenameは、100年日記のテキストデータを出力するファイル名を指定します。pythonのプログラムのあるフォルダに出力されます。

option_flgはTrueかFalseのboolean値をとります。Falseにすると、年月日日付と略号記号が出力されます。Trueにすると・・・楽しみにしておいてください。

    date_str = start_date
    date_dt = datetime.datetime.strptime(date_str, '%Y/%m/%d')

ここで、日付文字列をdatetime型に変換しています。スラッシュを使っているので、さきほど説明した引数の文字列もスラッシュを使った「年/月/日」の書式にしてください。

 

    yobi=["月","火","水","木","金","土","日"]
    ycode_str='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzアイウエオカクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨワン1234567890'

次に曜日のための漢字のリストを用意しています。この部分をたとえば

yobi=[“Mon”,”Tue”,”Wed”,”Thu”,”Fri”,”Sat”,”Sun”]などとしてもよいでしょう。

そして、ycodeですが、101文字用意してください。この順番は自分の好きなように変えてもらっていいと思います。たとえば100年分もいらないからアルファベットと数字だけで、60年分はユニークな記号を確保するという考えもありますね。

そのときは

ycode_str=’ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm’

こんな感じに重複を許してもいいかもしれませんね。

    date_dt2=date_dt
    with open(filename,'w') as f:
        for i in range(int(100*365.25)+1):            #100年分の日数をループさせる
            yobi_s=yobi[date_dt2.weekday()]         #曜日を日本語にする
            nenrei =relativedelta(date_dt2,date_dt) #満年齢を計算
            delta_y=date_dt2.year-date_dt.year      #短縮コードを生成するための年数を計算
            m=date_dt2.month                        #月の値を取得
            m_s='123456789XYZ'[m-1]                 #月は10月はX、11月はY、12月はZにする
            d=date_dt2.day                          #日の値を取得
            d_s=('0'+str(d))[-2:]                   #日は0埋めして2桁にする

 

これが、100年計算させているところです。内容はコメントに説明しているとおりですが、曜日を一文字の漢字にしたり、月を一文字に変換したりしている部分が工夫しているところですね。

 

            if option_flg:
                #全部入り
                print(f"{date_dt2.strftime('%Y-%m-%d')},{yobi_s},{'w'+('0'+str(w))[-2:]},{str(nenrei.years)+'y'+('0'+str(nenrei.months))[-2:]},{delta_y},{ycode_str[delta_y]+m_s+d_s},{str(i)+'d'}")
                f.write(f"{date_dt2.strftime('%Y-%m-%d')},{yobi_s},{'w'+('0'+str(w))[-2:]},{str(nenrei.years)+'y'+('0'+str(nenrei.months))[-2:]},{delta_y},{ycode_str[delta_y]+m_s+d_s},{str(i)+'d'},\n")
            else:
                #日付と短縮コードのみ
                print(f"{date_dt2.strftime('%Y-%m-%d')},{yobi_s},{ycode_str[delta_y]+m_s+d_s}")
                f.write(f"{date_dt2.strftime('%Y-%m-%d')},{yobi_s},{ycode_str[delta_y]+m_s+d_s},\n")
       date_dt2 += datetime.timedelta(days=1) #1日づつ増やす

 

ここもforループの中で実行していますが、4桁の年月日コードを出力するときに 生成しています。

ちょっと、横着ですね(^^;)

 

{ycode_str[delta_y]+m_s+d_s}

これがフォーマット文字列の変数部分ですが、年を示す一文字はycode_strの順番を指定して取り出しています。m_sが月を示す一文字、d_sは日を示します。これはゼロ埋めして必ず二桁にしています。

print文とf.write文の中身は同じで、ディスプレイ出力とファイル出力を両方行っています。

 

ycode()関数の使い方

引数を設定するだけなので、これまで説明したとおりです。以下がコードの全文です。

import datetime
from dateutil.relativedelta import relativedelta

def ycode(start_date='2020/1/1',filename='diary100years.txt',option_flg=False):
    #100年分の日記を出力。年月日を4桁で表現できるアイデア入り
    #option_flg=Trueの場合は、週番号、何年何カ月生きたか、何日生きたかなども出力
    date_str = start_date
    date_dt = datetime.datetime.strptime(date_str, '%Y/%m/%d')

    yobi=["月","火","水","木","金","土","日"]
    ycode_str='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm'
    
    date_dt2=date_dt
    with open(filename,'w') as f:
        for i in range(int(100*365.25)):            #100年分の日数をループさせる
            date_dt2 += datetime.timedelta(days=1)
            a=date_dt2.strftime('%a')
            w=date_dt2.strftime('%U')
            yobi_s=yobi[date_dt2.weekday()]
            nenrei =relativedelta(date_dt2,date_dt)
            delta_y=date_dt2.year-date_dt.year
            m=date_dt2.month
            m_s='123456789XYZ'[m-1]
            d=date_dt2.day
            d_s=('0'+str(d))[-2:]
            #print(date_dt2.strftime('%Y-%m-%d'),yobi_s,'w'+('0'+str(w))[-2:],str(nenrei.years)+'y'+('0'+str(nenrei.months))[-2:],delta_y,ycode[delta_y]+m_s+d_s,str(i)+'d')
            #print(date_dt2.strftime('%Y-%m-%d'),yobi_s,'w'+('0'+str(w))[-2:],str(nenrei.years)+'y'+('0'+str(nenrei.months))[-2:],delta_y,ycode_str[delta_y]+m_s+d_s,str(i)+'d')
            
            if option_flg:
                print(f"{date_dt2.strftime('%Y-%m-%d')},{yobi_s},{'w'+('0'+str(w))[-2:]},{str(nenrei.years)+'y'+('0'+str(nenrei.months))[-2:]},{delta_y},{ycode_str[delta_y]+m_s+d_s},{str(i)+'d'}")
                f.write(f"{date_dt2.strftime('%Y-%m-%d')},{yobi_s},{'w'+('0'+str(w))[-2:]},{str(nenrei.years)+'y'+('0'+str(nenrei.months))[-2:]},{delta_y},{ycode_str[delta_y]+m_s+d_s},{str(i)+'d'},\n")
            else:
                print(f"{date_dt2.strftime('%Y-%m-%d')},{yobi_s},{ycode_str[delta_y]+m_s+d_s}")
                f.write(f"{date_dt2.strftime('%Y-%m-%d')},{yobi_s},{ycode_str[delta_y]+m_s+d_s},\n")

#■メイン
if __name__ == "__main__":
    ycode('2000/1/1','diary100years222.txt',option_flg=True)
    a=input('Hit enter key!')

出力結果

出力したファイルのはじめの部分だけ示します。

ycode_str=’ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklm’という風に重複はありで、アルファベットと数字だけで構成しました。

2000-01-01,土,A101,
2000-01-02,日,A102
2000-01-03,月,A103,
2000-01-04,火,A104,
2000-01-05,水,A105,
2000-01-06,木,A106,
2000-01-07,金,A107,
2000-01-08,土,A108,
2000-01-09,日,A109,
2000-01-10,月,A110,
2000-01-11,火,A111,
2000-01-12,水,A112,
2000-01-13,木,A113,
2000-01-14,金,A114,
2000-01-15,土,A115,
2000-01-16,日,A116,
2000-01-17,月,A117,
2000-01-18,火,A118,
2000-01-19,水,A119,
2000-01-20,木,A120,
2000-01-21,金,A121,
2000-01-22,土,A122,
2000-01-23,日,A123,
2000-01-24,月,A124,
2000-01-25,火,A125,
2000-01-26,水,A126,
2000-01-27,木,A127,
2000-01-28,金,A128,
2000-01-29,土,A129,
2000-01-30,日,A130,
2000-01-31,月,A131,
2000-02-01,火,A201,
2000-02-02,水,A202,
2000-02-03,木,A203,

省略

2099-12-25,金,lZ25,
2099-12-26,土,lZ26,
2099-12-27,日,lZ27,
2099-12-28,月,lZ28,
2099-12-29,火,lZ29,
2099-12-30,水,lZ30,
2099-12-31,木,lZ31,
2100-01-01,金,m101,

この例は、2000年1月1日に生まれた人の誕生日を基準にして出力しています。2100年1月1日の100歳の誕生日まで出力できています。

カンマで区切られているのでエクセルでも使えます。そのときは、ファイルの拡張子をtxtから

csvに変えてくださいね。

おっと忘れるところでした。option_flgがTrueのときの出力結果を示します。

2020-09-10,木,w36,20y08,20,U910,7557d,
2020-09-11,金,w36,20y08,20,U911,7558d,
2020-09-12,土,w36,20y08,20,U912,7559d,
2020-09-13,日,w37,20y08,20,U913,7560d,
2020-09-14,月,w37,20y08,20,U914,7561d,
2020-09-15,火,w37,20y08,20,U915,7562d,
2020-09-16,水,w37,20y08,20,U916,7563d,
2020-09-17,木,w37,20y08,20,U917,7564d,
2020-09-18,金,w37,20y08,20,U918,7565d,
2020-09-19,土,w37,20y08,20,U919,7566d,
2020-09-20,日,w38,20y08,20,U920,7567d,

こんな感じで、さきほどより多くの情報が出力されています。

左から順番に
標準年月日、曜日、年の第何週、20歳8か月、生まれて20年目、4桁コード、生まれて7567日目
2020-09-20, 日, w38,     20y08,     20,     U920,    7567d,

ということになっています。生まれて今日で何日目なんて、日ごろは気にしませんよね。

ちょっと、時間を大切にしなければという思いが出るかもしれません。

以上が100年日記と4桁コードのアイデアの紹介でした。

読んでくださり、ありがとうございました。

 

コメント

タイトルとURLをコピーしました