1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaScript のDateオブジェクトにフォーマット関数 と 加減算の関数を追加

Last updated at Posted at 2016-12-07

日付のフォーマット関数と、MySQLのDATE_ADDに似せた、日付の加減算を行う関数です。
フォーマット関数はともかくとして、日付関数をわざわざ作ったのは、Javascriptの日付の加減算はタイムゾーンの変換の関係か、バグがあるので、ちょっと信用できないので作り直しました。

JavascriptのObject.defineProperty(Object.prototype, 'name', function)が既存クラスをカスタマイズできて面白いので、Date()に直接追加するライブラリにしてみました。

formatサンプル
var objDate = new Date();
objDate.format(); //"2016-12-08 00:08:39.873"
objDate.format('yyyy-MM-dd (ddd) hh-mm:ss'); //"2016-12-08 (木) 00:08:39"
objDate.format('yyyy-MM-dd (dddd) hh-mm:ss'); //"2016-12-08 (木曜) 00:08:39"
objDate.format('yyyy-MM-dd (ddddd) hh-mm:ss'); //"2016-12-08 (木曜日) 00:08:39"
addサンプル
var objDate = new Date();
objDate.format(); //"2016-12-08 00:08:39.873"
objDate.add(1, 'y').format(); //"2017-12-08 00:08:39.873"
objDate.add(1, 'M').format(); //"2017-01-08 00:08:39.873"
objDate.add(1, 'd').format(); //"2016-12-09 00:08:39.873"
objDate.add(1, 'h').format(); //"2016-12-08 01:08:39.873"
objDate.add(1, 'm').format(); //"2016-12-08 00:09:39.873"
objDate.add(1, 's').format(); //"2016-12-08 00:08:40.873"

ソースコード

add_date.js
Object.defineProperty(Date.prototype, 'format', {
	get: function () {
		return function (str_format) {
			var f = str_format;
			var o = this;
			if (!f) f = 'yyyy-MM-dd hh:mm:ss.SSS';
			var week = ["","","","","","",""];
			f = f.replace(/yyyy/g, o.getFullYear());
			f = f.replace(/MM/g, ('0' + (o.getMonth() + 1)).slice(-2));
			f = f.replace(/hh/g, ('0' + o.getHours()).slice(-2));
			f = f.replace(/mm/g, ('0' + o.getMinutes()).slice(-2));
			f = f.replace(/ss/g, ('0' + o.getSeconds()).slice(-2));
			f = f.replace(/ddddd/g, week[o.getDay()] + "曜日");
			f = f.replace(/dddd/g, week[o.getDay()] + "");
			f = f.replace(/ddd/g, week[o.getDay()]);
			f = f.replace(/dd/g, ('0' + o.getDate()).slice(-2));
			if (f.match(/S/g)) {
				var milliSeconds = ('00' + o.getMilliseconds()).slice(-3);
				var length = f.match(/S/g).length;
				for (var i = 0; i < length; i++) f = f.replace(/S/, milliSeconds.substring(i, i + 1));
			}
			return f;
		};
	}
});

Object.defineProperty(Date.prototype, 'add', {
	get: function () {
		return function (interval, str_target) {

			var t = str_target.toLowerCase();
			var o = this;

			if(t=='y' || str_target=='M'){
				var y, M, d;
				y = o.getFullYear();
				M = o.getMonth(); /* between 0 to 11 */
				d = o.getDate();

				if(t=='y'){/*Year*/
					y += interval;
				}
				else{ /*Month*/
					M += interval;
					y += Math.floor(M / 12);
					M = M % 12;
				}
				var max = [31, 28 + (M == 1 && y % 4 == 0 && (y % 100!=0 || y % 400==0)), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
				if(d > max[M]){ d = max[M]}

				return new Date(
					y + '-' +
					('0' + (M + 1)).slice(-2) + '-' +
					('0' + d).slice(-2) + ' ' +
					('0' + o.getHours()).slice(-2) + ':' +
					('0' + o.getMinutes()).slice(-2) + ':' +
					('0' + o.getSeconds()).slice(-2) + '.' +
					('00' + o.getMilliseconds()).slice(-3)
				);
			}

			else if(t=='d'){/*Day*/
				return new Date(o.getTime() + interval * 86400000);
			}
			else if(t=='h'){/*Hour*/
				return new Date(o.getTime() + interval * 3600000);
			}
			else if(str_target=='m'){/*Minute*/
				return new Date(o.getTime() + interval * 60000);
			}
			else if(t=='s'){/*Second*/
				return new Date(o.getTime() + interval * 1000);
			}
			else {
				return new Date(o)
			}
		};
	}
});

年と月の計算の部分は、最初はグレゴリオ暦の日数取得の公式を使って計算しようとしていました。

			if(t=='y' || str_target=='M'){
				var y, Y, M,MM, d, before_days, after_days;
				y = this.getFullYear();
				M = this.getMonth(); /* between 0 to 11 */
				d = this.getDate();
				
				/*days from DC1 */
				before_days = 365 * y + ~~(30.6 * (M + 2)) - 428 + ~~(y / 4) - ~~(y / 100) + ~~(y / 400) + d;

				if(t=='y'){/*Year*/
					y += interval;
				}
				else{ /*Month*/
					M += interval;
					y += ~~(M / 12);
					M = M % 12;
				}
				after_days = 365 * y + ~~(30.6 * (M + 2)) - 428 + ~~(y / 4) - ~~(y / 100) + ~~(y / 400) + d;

				/* incremented - before days */
				after_days -= before_days;

				return new Date(this.getTime() + after_days * 86400000);
			}

しかし、これを使うと、Javascriptオリジナルの月の加減算と同じく、日がその月の最大日数から溢れた場合等におかしな挙動を起します。
2016-01-31
1ヶ月加算
2016-03-01

普通の月の加減算でこんな結果を望む人はいない・・・

MySQLの月の加減算はこんな感じ。

mysql> select DATE_ADD('2016-01-31', interval 1 month);
+------------------------------------------+
| DATE_ADD('2016-01-31', interval 1 month) |
+------------------------------------------+
| 2016-02-29                               |
+------------------------------------------+
1 row in set (0.00 sec)

うん。素直。これですよね。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?