【javascript】まだよくわかってないClassを使って日付操作【勉強】

前回の記事で日付の続きでもあります。

https://qiita.com/noenture/items/f683edf24fc2af3d6168

日付処理は有用なライブラリがありますが、経験値積むためなのでお許しを。

#目的

**Dateを継承**して以下のようなメソッドチェーンにしたかった。

```javascript
const time = new Time(1999,7,7,16,30,30,500);
const f = 'YYYY/MM/DD H:mm:ss.fff(DDD)';

console.log( time.term(1990, 2, 3) );	// -297621030500
console.log( time.getWeekday() );		// Sat
console.log( time.getWeekday('ja') );	// 土
console.log( time.format(f) );						// 1999/08/07 16:30:30.500(Sat)
console.log( time.advance(1).format(f) );			// 2000/08/07 16:30:30.500(Mon)
console.log( time.advanceDays(-3,5).format(f) );	// 2000/08/04 21:30:30.500(Fri)
console.log( time.reset().format(f) );				// 1999/08/07 16:30:30.500(Sat)
```

#コード

 - 追記1：`time.term()`のミリ秒以外で出力するメソッドを追加。
 - 追記2：`time.reset()`関連の修正。**引数now**を追加。
 - 追記3：`time.termDays()`系の結果を四捨五入から切り上げに変更。**time.splitTerm()**を追加

```javascript
class Time extends Date {
	constructor(...args) {
		super(...args);
		this.default = super.toISOString();
	}
	reset(now) {
		const d = now===true ? new Date() : new Date(this.default);
		super.setFullYear(d.getFullYear());
		super.setMonth(d.getMonth());
		super.setDate(d.getDate());
		super.setHours(d.getHours());
		super.setMinutes(d.getMinutes());
		super.setSeconds(d.getSeconds());
		super.setMilliseconds(d.getMilliseconds());
		return this
	}
	advance() {
		if (arguments[0]) super.setFullYear(super.getFullYear() + arguments[0]);
		if (arguments[1]) super.setMonth(super.getMonth() + arguments[1]);
		if (arguments[2]) super.setDate(super.getDate() + arguments[2]);
		if (arguments[3]) super.setHours(super.getHours() + arguments[3]);
		if (arguments[4]) super.setMinutes(super.getMinutes() + arguments[4]);
		if (arguments[5]) super.setSeconds(super.getSeconds() + arguments[5]);
		if (arguments[6]) super.setMilliseconds(super.getMilliseconds() + arguments[6]);
		return this
	}
	advanceDays() {
		if (arguments[0]) super.setDate(super.getDate() + arguments[0]);
		if (arguments[1]) super.setHours(super.getHours() + arguments[1]);
		if (arguments[2]) super.setMinutes(super.getMinutes() + arguments[2]);
		if (arguments[3]) super.setSeconds(super.getSeconds() + arguments[3]);
		if (arguments[4]) super.setMilliseconds(super.getMilliseconds() + arguments[4]);
		return this
	}
	term() {
		return new Date(...arguments) - this;
	}
	termSeconds() {
		return Math.ceil((new Date(...arguments) - this) / 1000);
	}
	termMinuts() {
		return Math.ceil((new Date(...arguments) - this) / 60000);
	}
	termHours() {
		return Math.ceil((new Date(...arguments) - this) / 3600000);
	}
	termDays() {
		return Math.ceil((new Date(...arguments) - this) / 86400000);
	}
	splitTerm() {
		const term = new Date(...arguments) - this;
		const res = term < 0 ? [-term, '-'] : [term, '+'];
		
		for (const div of [86400000, 3600000, 60000, 1000]) {
			res.push( Math.floor(res[0]/div) );
			res[0] %= div;
		}
		res.push( res.shift() );
		return res
	}
	getWeekday(langStr) {
		const n = super.getDay();
		switch (langStr){
			case 'ja': return '日月火水木金土'.charAt(n);
			default: return ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][n];
		}
	}
	format(formatStr) {
		const weekdays = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
		const pad = (num, dig) => ('000' + num).slice(-dig);
		return formatStr.replace(/([YMDHhmsf])\1*/g, match => {
			switch (match) {
				case 'YYYY':return super.getFullYear();
				case 'YY':	return pad(super.getFullYear(), 2);
				case 'M':	return super.getMonth()+1;
				case 'MM':	return pad(super.getMonth()+1, 2);
				case 'D':	return super.getDate();
				case 'DD':	return pad(super.getDate(), 2);
				case 'H':	return super.getHours();
				case 'HH':	return pad(super.getHours(), 2);
				case 'm':	return super.getMinutes();
				case 'mm':	return pad(super.getMinutes(), 2);
				case 's':	return super.getSeconds();
				case 'ss':	return pad(super.getSeconds(), 2);
				case 'fff':	return pad(super.getMilliseconds(), 3);
				case 'DDD':	return weekdays[super.getDay()];
				default: return match;
			}
		})
	}
}

```

#メソッド解説
##reset
||*time*.reset( boolean now )|
|:--|:--|
|引数|true or other|
|返値|date date|
|説明|後述のadvance/advanceDayの処理で変化した日付をインスタンス生成時のものに戻す。引数を**true**にした場合のみ、このメソッドを実行した時間に上書きする。|

##advance
||*time*.advance( number [y,[m,[d,[h,[mm,[s,[ms]]]]]]]] )|
|:--|:--|
|引数|number 第一引数を**年**、**月,日,時,分,秒,ミリ秒**と続く|
|返値|date date|
|説明|time.advance(0,1,1)で一月一日分加算され、time.advance(-1)で1年戻る|

##advanceDays
||*time*.advanceDays( number [d,[mm,[s,[ms]]]] )|
|:--|:--|
|引数|number 第一引数を**日**、**時,分,秒,ミリ秒**と続く|
|返値|date date|
|説明|advance()の年月を省いたもの|

##term
||*time*.term()|
|:--|:--|
|引数|new Date()に指定する引数と同じもの|
|返値|number milliseconds|
|説明|インスタンス生成した日付と、ここで指定した**日付の差が何ミリ秒**かを出力|

##termSeconds...
||*time*.termSeconds() / *time*.termMinutes() / *time*.termHours() / *time*.termDays()|
|:--|:--|
|引数|new Date()に指定する引数と同じもの|
|返値|number seconds/minutes/hours/days|
|説明|各単位の対応版|

##splitTerm
||*time*.splitTerm()|
|:--|:--|
|引数|new Date()に指定する引数と同じもの|
|返値|Array [string '+'｜'-'、number days, number hr, mi, sc, ms]|
|説明|ミリ秒を日数を最大にした各単位で分割して配列に出力。**['+', 7, 1, 0, 3, 555]**で**7日と1時間3秒555ミリ秒 後**。**+**は基準より後、**-**は基準より前。|

##getWeekday
||*time*.getWeekday( string lang )|
|:--|:--|
|引数|string 言語指定|
|返値|string weekday|
|説明|**'ja'**を指定すれば日本の曜日、それ以外は英語の曜日|

##format
||*time*.format( string format )|
|:--|:--|
|引数|string 出力形式|
|返値|string date|
|説明|詳細は前回の記事。**'YYYY/MM/DD'**と指定すれば**2000/08/04**のように返す。|


#私感

`super`の使い方これでいいのかとか、他のメソッドでも使いたい**weekdays**のような曜日の配列を`constructor`に置いても良いのか（外から書き換えられそう）とか、他にも多分色々おかしいところがあるかもしれない。