kintoneでjsカスタマイズ時の日付と小数点アリの計算をするときのポイント

# 概要
日付の計算と小数点ありの場合の計算についての対処方法について学びましょう！
kintoneアプリのテンプレートもダウンロードできるので、実際に操作しながらご確認いただけます！
 

# ポイント
* 日付・時刻の計算は、思ったよりも複雑(日またぎ、月またぎ、年またぎ、うるう年など)なので、積極的にライブラリを使いましょう。
* サイボウズが提供している **[CDN](https://cybozu.dev/ja/kintone/sdk/library/cybozu-cdn/)** に日付ライブラリとして **[Luxon](https://moment.github.io/luxon/#/)** が置いてあるので、それを使うとよいかなと思います。
* 軽さですと **[Day.js](https://day.js.org/)** などもおすすめです。
* ちなみに、**[developer network](https://cybozu.dev/ja/)** には、**moment.js** についての記述が散見されますが、現在moment.jsは**メンテナンスモード**になっているので、**使わない**ようにしましょう。
* 色々なやり方がありますが、今回は、小数点ありの数値計算をするときには整数値になるように10^nを掛けて、計算した後に、10^nで割り算するようにします。
* もしくは数値計算用のライブラリを使いましょう。
    * **[bignumber.js](https://mikemcl.github.io/bignumber.js/)**
    * **[big.js](https://github.com/MikeMcl/big.js)**
    * **[decimal.js](https://mikemcl.github.io/decimal.js/)**
* コンピューターでの小数点ありの数値計算においては、計算誤差が出るのは致し方ないです。
    * 基本情報処理試験の勉強してみると良いです。
    * 「javascript 小数点 計算 誤差」等でググってみましょう。
    * [小数計算の誤差 0.1 + 0.2 が 0.30000000000000004 になる理由](https://blog.apar.jp/program/8900/)


# 準備
* **[こちら](https://github.com/AISIC-DL/advent_calendar_2023)** から **日付と小数点あり計算.zip** ダウンロードしてください。
* ダウンロードしたファイルはテンプレートファイルなので、そのままkintoneにアプリとして追加してください。(※zipファイルは展開しないでねー)


# 実際に動かしてみる
![image-20231024-082941.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319512/c4ecc015-62c9-a845-532f-09d5d3f510b6.png)
* 必要な項目に入力して、計算ボタンを押下してください
* アチコチ手抜きなので、必須チェックなどは入っていません
* 必要そうな項目に入力してないと、計算ボタン押下時にコケます(笑)


# ソースの解説
## ポイント
* 日付や日時フィールドをluxonオブジェクトにするには、`fromISO()` を使います。
* 日付フィールドにluxonオブジェクトの値をセットするときには、`.toFormat('yyyy-MM-dd')` を使って文字列にします。
* 日時フィールドにluxonオブジェクトをセットするときには、luxonオブジェクトをそのままセットします。
* 小数点アリの計算時には、「べき乗を掛けて、べき乗で割る」ようにします。
* 足し算・引き算と掛け算・割り算では、掛け方・割り方が違うので注意しましょう。

(以下、プログラムの抜粋です)
``` javascript
const objRecord = kintone.app.record.get();


// 日付の計算
objRecord.record.結果_日付.value = luxon.DateTime.fromISO(objRecord.record.初期値_日付.value)
  .plus({ days: Number(objRecord.record.経過日数_日付.value) }).toFormat('yyyy-MM-dd');


// 日時の計算
objRecord.record.結果_日時.value = luxon.DateTime.fromISO(objRecord.record.初期値_日時.value)
  .plus({ days: Number(objRecord.record.経過日数_日時.value), hours: Number(objRecord.record.経過時間_日時.value) });


// そのまま計算
let calc1 = 0;
if (objRecord.record.演算子1.value === '＋') {
  calc1 = Number(objRecord.record.値1_1.value) + Number(objRecord.record.値1_2.value);
} else if (objRecord.record.演算子1.value === '－') {
  calc1 = Number(objRecord.record.値1_1.value) - Number(objRecord.record.値1_2.value);
} else if (objRecord.record.演算子1.value === '×') {
  calc1 = Number(objRecord.record.値1_1.value) * Number(objRecord.record.値1_2.value);
} else if (objRecord.record.演算子1.value === '÷') {
  calc1 = Number(objRecord.record.値1_1.value) / Number(objRecord.record.値1_2.value);
} else {
  calc1 = 0;
}

objRecord.record.結果_計算1.value = calc1;


// 整数値にして計算
let calc2 = 0;
const exp = 1000;
if (objRecord.record.演算子2.value === '＋') {
  calc2 = (Number(objRecord.record.値2_1.value) * exp + Number(objRecord.record.値2_2.value) * exp) / exp;
} else if (objRecord.record.演算子2.value === '－') {
  calc2 = (Number(objRecord.record.値2_1.value) * exp - Number(objRecord.record.値2_2.value) * exp) / exp;
} else if (objRecord.record.演算子2.value === '×') {
  calc2 = (Number(objRecord.record.値2_1.value) * exp * Number(objRecord.record.値2_2.value) * exp) / (exp * exp);
} else if (objRecord.record.演算子2.value === '÷') {
  calc2 = (Number(objRecord.record.値2_1.value) * exp / Number(objRecord.record.値2_2.value) * exp) / (exp * exp);
} else {
  calc2 = 0;
}

objRecord.record.結果_計算2.value = calc2;


kintone.app.record.set(objRecord);
```


# 最後に
プログラミングのハードルがグッと下がってきて、気軽にプログラミングを始める方も増えてきました。人間的には簡単に簡単にできそうなことでも、コンピューターの特性を知った上で上手に使っていかないと、思わぬ落とし穴にハマることがあります。
また、なんでも自分で書くのではなく、積極的にライブラリを使うことや、(今回は触れませんでしたが)開発用フレームワークを使うなどして、開発の標準化や平準化を図ることも重要なポイントです。


# 宣伝…
## その1
上記で触れたフレームワークを開発しているので、よろしければお使いくださいませ！
**[gameni(がめに)](https://github.com/j-kume/gameni)** 

## その2
**kintone開発者向けコミュニティ [devkin meetup!](https://devkin.connpass.com/)** を始めました。
次回 **vol.2** を **2024/1/23(火) 21:00-23:00** に**オンライン**にて開催することが決定しております！
connpassをフォローいただいたり、X(旧twitter) #devkinmeetup などで情報をキャッチアップいただければ幸いです！