（Tips）これから100年のunix時間は10桁数字。５桁の固定長文字列でも表現できる。

#Unixtimeの時刻表現

多くのエンジニアがご存知であろうUNIX時間（ユニックスじかん、UNIX time）。
wikipediaには以下のように書かれている（抜粋）。

>UNIX時間（UNIX time）とはコンピューターシステム上での時刻表現の一種。UNIXエポック、すなわち協定世界時 (UTC) での1970年1月1日午前0時0分0秒から形式的な経過秒数（すなわち、実質的な経過秒数から、その間に挿入された閏秒を引き、削除された閏秒を加えたもの）として表される。

UNIX timeは、うるう年、ローカルタイム、サマータイムなどの扱いが必要ないシンプルな時刻表現だ（うるう秒の扱いはちょっと面倒なのかもしれないが）。
時系列の時刻管理が必要なツールを作る際に、とりあえずUnix timeにしておけば秒単位での順序付けが行える。

#２１世紀ののUnix時間はほぼ10桁で表せる
普段目にするUnix時間の桁数は大抵１０桁だ。

>Unix時間　対応する時刻(JST)
1017378540 2002-03-29 14:09:00+09:00
1490418540 2017-03-25 14:09:00+09:00
4107906540 2100-03-05 14:09:00+09:00

python3では以下のようなコードでUnix時間と対応する時刻を計算できる。

```現在時刻.py
from datetime import datetime, timezone, timedelta

JST = timezone(timedelta(hours=+9), 'JST')

now = int(datetime.now().timestamp())
now_loc = datetime.fromtimestamp(now, JST)
print("Unix時間　対応する時刻(JST)")
print(now, now_loc)
```
２０世紀のUnix時間は９桁以下、２１世紀や22世紀のUnix時間はだいたい10桁ということはTipsとして、知っておいてもいいだろう。

上１桁が5になるのは100年ちょっとあと（カンマ区切りを入れた）。
>5,022,450,540　2129-02-26 14:09:00+09:00
2001年から計算してみると30年ちょっとに一回上1桁が大きくなっていくらしい。


#BASE91に変換してみる。
さて、10桁固定で比較もできて便利なUnix時間であるが、可読性は低い。
どうせ可読性が低いならば、BASEエンコードしてしまって、桁数を減らしてデータベースに格納してしまっても良いのではと思ったので実験してみた。

元にしたのは以下の文字を使うBASE91:
###ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~"

以前のエントリー『[python+redisで、Base91のキーを扱う。](https://qiita.com/Nimimal/items/04c97be5f3b811bae505)』　で
redisがBase91の文字列を扱えることは確認済なので、redisのキーの一部にBASE91ベースのUnix時間を突っ込むイメージ。
例えば請求を種別に管理する場合

>請求種別A-XXXXX

とキーの末尾が時刻表現となるイメージ

base91ではいろんな記号が使われちゃっているけれども、マイナス(-)は使われてないので、マイナスを区切り文字に使うと良い。（base91関連の情報は以下に）
http://base91.sourceforge.net/

ということで、以下のような書捨てコードで検証してみた:

```unixtime2base91.py
from datetime import datetime, timezone, timedelta

base90 ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~"
base91=base90 + '"'

LEN = len(base91)
#base91表現のUnixtimeを取得
def get91(time, LEN=91):
    if time < LEN:
        return base91[time]
    str=""
    q=time
    while (q >= LEN ):
        q, mod = divmod(q,LEN)
        str += base91[mod]
    #print(q,mod, end=':')
    return (str + base91[q])[::-1] #反転する

#base91表現のUnixtimeを数値に戻す
def melt91(str, LEN=91):
    time=0
    lst = [base91.find(char) for char in str][::-1] #反転する
    for i, L in enumerate(lst):
       power = pow(LEN,i)
       time += L*power
    return time

JST = timezone(timedelta(hours=+9), 'JST')
now = int(datetime.now().timestamp())
now_loc = datetime.fromtimestamp(now, JST)
ft = now
str ="XXXXX"

print(f"######## before {now_loc}###########")
while (len(str) > 4):
    ft -=(60*60 *24 * 365)
    loc = datetime.fromtimestamp(ft, JST)
    str=get91(ft)
    print(str,ft,melt91(str),loc) 
print(f"######## after {now_loc}###########")
ft = now
while (len(str) < 6):
    ft +=(60*60 *24 * 365)
    loc = datetime.fromtimestamp(ft, JST)
    str=get91(ft)
    print(str,ft,melt91(str),loc) 


```


#base91表現のUnixtimeはけっこう長い期間５桁で表せる。

結果。どうやらbase91表現のUnixtimeは、1972年から2167年の間は５桁で表せる模様。
桁数を減らすことが目的で可読性は期待していなかったけど、上１桁の文字が2年ちょいは変わらないので
大体の年はひと目で分かりそうでちょっと良さげ
（例　2020年と2021年のbase91表現のUnixtimeは「X」ではじまる）。

```
######## before 2018-03-25 15:16:32+09:00###########
V&/"W 1490422592 1490422592 2017-03-25 15:16:32+09:00
VY|). 1458886592 1458886592 2016-03-25 15:16:32+09:00
U:Kvf 1427350592 1427350592 2015-03-26 15:16:32+09:00
UgYZ[ 1395814592 1395814592 2014-03-26 15:16:32+09:00
T[mEo 1364278592 1364278592 2013-03-26 15:16:32+09:00
（中略）
C@Bd+ 197446592 197446592 1976-04-04 15:16:32+09:00
CmPId 165910592 165910592 1975-04-05 15:16:32+09:00
B|c=? 134374592 134374592 1974-04-05 15:16:32+09:00
Btq4m 102838592 102838592 1973-04-05 15:16:32+09:00
BD4i} 71302592 71302592 1972-04-05 15:16:32+09:00
0+Nv 39766592 39766592 1971-04-06 15:16:32+09:00

######## after 2018-03-25 15:16:32+09:00###########
W7uqN 1553494592 1553494592 2019-03-25 15:16:32+09:00
XKg#2 1585030592 1585030592 2020-03-24 15:16:32+09:00
X0S`E 1616566592 1616566592 2021-03-24 15:16:32+09:00
YDFPt 1648102592 1648102592 2022-03-24 15:16:32+09:00
Ys]k{ 1679638592 1679638592 2023-03-24 15:16:32+09:00
Y{)6k 1711174592 1711174592 2024-03-23 15:16:32+09:00
Zl2?= 1742710592 1742710592 2025-03-23 15:16:32+09:00
Z?pKb 1774246592 1774246592 2026-03-23 15:16:32+09:00
aebf) 1805782592 1805782592 2027-03-23 15:16:32+09:00
a.N1S 1837318592 1837318592 2028-03-22 15:16:32+09:00
bW":7 1868854592 1868854592 2029-03-22 15:16:32+09:00
b$=FJ 1900390592 1900390592 2030-03-22 15:16:32+09:00
cP#ay 1931926592 1931926592 2031-03-22 15:16:32+09:00
c5xwA 1963462592 1963462592 2032-03-21 15:16:32+09:00
dIj*p 1994998592 1994998592 2033-03-21 15:16:32+09:00
dyV"] 2026534592 2026534592 2034-03-21 15:16:32+09:00
eBIVg 2058070592 2058070592 2035-03-21 15:16:32+09:00
eq`q/ 2089606592 2089606592 2036-03-20 15:16:32+09:00
e_,$X 2121142592 2121142592 2037-03-20 15:16:32+09:00
fj5`$ 2152678592 2152678592 2038-03-20 15:16:32+09:00
f=sQO 2184214592 2184214592 2039-03-20 15:16:32+09:00
gcel3 2215750592 2215750592 2040-03-19 15:16:32+09:00
g+Q7F 2247286592 2247286592 2041-03-19 15:16:32+09:00
hVC@u 2278822592 2278822592 2042-03-19 15:16:32+09:00
h!@K| 2310358592 2310358592 2043-03-19 15:16:32+09:00
iN&gl 2341894592 2341894592 2044-03-18 15:16:32+09:00
i301> 2373430592 2373430592 2045-03-18 15:16:32+09:00
　　（中略）
}l@P0 6063142592 6063142592 2162-02-18 15:16:32+09:00
}?&lC 6094678592 6094678592 2163-02-18 15:16:32+09:00
~e06r 6126214592 6126214592 2164-02-18 15:16:32+09:00
~.m?_ 6157750592 6157750592 2165-02-17 15:16:32+09:00
"XZKi 6189286592 6189286592 2166-02-17 15:16:32+09:00
"%Lf; 6220822592 6220822592 2167-02-17 15:16:32+09:00
BAP}1Z 6252358592 6252358592 2168-02-17 15:16:32+09:00
```
以上、Tipsまで。