十年前、僕は光の戦士として生を受け、様々な困難を乗り越えながら広大なエオルゼア大陸を駆け巡る、冒険者稼業の日々を送っていた...
という茶番は置いといて、僕は ファイナルファンタジー14 というオンラインゲームを遊んでいます。
ここ数年は半ば活動休止状態ですが...
ゲームの舞台となる「エオルゼア」という世界には、現実世界とは異なる独自の時間軸が設定されています。
エオルゼアの時間は現実世界の時間から算出可能ということなので、今回はそれをやってみようと思います。
現実世界との差異
時間軸に関する現実世界とエオルゼアの差異は3点あります。
- 閏年は存在しない
- 毎月の日数は
32
で固定 - 時間の進行速度は
3600 / 175
=144 / 7
≒20.6
倍- 現実世界の
175
秒がエオルゼアの3600
秒
- 現実世界の
上記以外は現実世界と同等になります。
また、これは恐らくゲーム開発による都合だろうと思いますが、現実世界の 1970-01-01T00:00:00Z
つまりUNIX時間の基準点が、エオルゼアの 0001-01-01T00:00:00
つまり起点となります。
そのため、後述のサンプルコードは年数まで取得できますが、その年数が物語設定と関係しているかまでは分かりません。
恐らくあまり意味はないと思います。
実装
上記のように、現実世界と異なる条件が存在するため、日付計算ライブラリは使用できません。
そのため、泥臭く四則演算を駆使しなければなりませんが、毎月固定日数なことやUNIX時間が基準なことを踏まえると、計算はかなり簡単になります。
また、四則演算縛りということは、どの言語でも簡単に実装できます。
インターネットの大海原は広いもので、既に様々な解説記事やサンプルコードが漂流していますが、この記事では「エオルゼアエポック秒」法を紹介したいと思います。今命名しました。
UNIX時間から年月日時分秒に変換することは現実世界でもよくあるため、それをエオルゼア時間にも当てはめて直感的に記述できるようにしたのがこの方法です。
エオルゼアエポック秒は、前述の通りUNIX時間を 144 / 7
倍すればいいだけですから、簡単に導出できます。
あとは現実世界と同じように、エオルゼアエポック秒から年月日時分秒を算出すればいいだけです。
今回はとりあえずTypeScriptとShellScriptで書いてみました。
const SEC_MINUTES = 60;
const SEC_HOURS = SEC_MINUTES * 60;
const SEC_DATE = SEC_HOURS * 24;
const SEC_MONTH = SEC_DATE * 32;
const SEC_YEAR = SEC_MONTH * 12;
function eorzeatime(unixtime: number) {
const epoch = Math.floor(unixtime * 144 / 7);
const r1 = epoch % SEC_YEAR;
const r2 = r1 % SEC_MONTH;
const r3 = r2 % SEC_DATE;
const r4 = r3 % SEC_HOURS;
const year = Math.floor(epoch / SEC_YEAR) + 1;
const month = Math.floor(r1 / SEC_MONTH) + 1;
const date = Math.floor(r2 / SEC_DATE) + 1;
const hours = Math.floor(r3 / SEC_HOURS);
const minutes = Math.floor(r4 / SEC_MINUTES);
const seconds = r4 % SEC_MINUTES;
return {epoch, year, month, date, hours, minutes, seconds};
}
// 動作確認
console.log(eorzeatime(Math.floor(Date.now() / 1000)));
#!/bin/sh
set -eu
readonly SEC_MINUTES=60
readonly SEC_HOURS=$((${SEC_MINUTES} * 60))
readonly SEC_DATE=$((${SEC_HOURS} * 24))
readonly SEC_MONTH=$((${SEC_DATE} * 32))
readonly SEC_YEAR=$((${SEC_MONTH} * 12))
function eorzeatime {
local epoch=$((${1} * 144 / 7))
local r1=$((${epoch} % ${SEC_YEAR}))
local r2=$((${r1} % ${SEC_MONTH}))
local r3=$((${r2} % ${SEC_DATE}))
local r4=$((${r3} % ${SEC_HOURS}))
local year=$((${epoch} / ${SEC_YEAR} + 1))
local month=$((${r1} / ${SEC_MONTH} + 1))
local date=$((${r2} / ${SEC_DATE} + 1))
local hours=$((${r3} / ${SEC_HOURS}))
local minutes=$((${r4} / ${SEC_MINUTES}))
local seconds=$((${r4} % ${SEC_MINUTES}))
echo "${year} ${month} ${date} ${hours} ${minutes} ${seconds}"
}
# 動作確認
eorzeatime $(date +%s)