#Unixtimeの時刻表現
多くのエンジニアがご存知であろうUNIX時間(ユニックスじかん、UNIX time)。
wikipediaには以下のように書かれている(抜粋)。
UNIX時間(UNIX time)とはコンピューターシステム上での時刻表現の一種。UNIXエポック、すなわち協定世界時 (UTC) での1970年1月1日午前0時0分0秒から形式的な経過秒数(すなわち、実質的な経過秒数から、その間に挿入された閏秒を引き、削除された閏秒を加えたもの)として表される。
UNIX timeは、うるう年、ローカルタイム、サマータイムなどの扱いが必要ないシンプルな時刻表現だ(うるう秒の扱いはちょっと面倒なのかもしれないが)。
時系列の時刻管理が必要なツールを作る際に、とりあえずUnix timeにしておけば秒単位での順序付けが行える。
#21世紀ののUnix時間はほぼ10桁で表せる
普段目にするUnix時間の桁数は大抵10桁だ。
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時間と対応する時刻を計算できる。
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)
20世紀のUnix時間は9桁以下、21世紀や22世紀のUnix時間はだいたい10桁ということはTipsとして、知っておいてもいいだろう。
上1桁が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のキーを扱う。』 で
redisがBase91の文字列を扱えることは確認済なので、redisのキーの一部にBASE91ベースのUnix時間を突っ込むイメージ。
例えば請求を種別に管理する場合
請求種別A-XXXXX
とキーの末尾が時刻表現となるイメージ
base91ではいろんな記号が使われちゃっているけれども、マイナス(-)は使われてないので、マイナスを区切り文字に使うと良い。(base91関連の情報は以下に)
http://base91.sourceforge.net/
ということで、以下のような書捨てコードで検証してみた:
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はけっこう長い期間5桁で表せる。
結果。どうやらbase91表現のUnixtimeは、1972年から2167年の間は5桁で表せる模様。
桁数を減らすことが目的で可読性は期待していなかったけど、上1桁の文字が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まで。