日付フォーマットなど 日付系処理


## 日付をフォーマットする

日付をフォーマットして返す。フォーマット（第二引数）を省略した場合`2014-01-23 01:23:45.678`みたいな形で返す。

```javascript:formatDate
/**
 * 日付をフォーマットする
 * @param  {Date}   date     日付
 * @param  {String} [format] フォーマット
 * @return {String}          フォーマット済み日付
 */
var formatDate = function (date, format) {
  if (!format) format = 'YYYY-MM-DD hh:mm:ss.SSS';
  format = format.replace(/YYYY/g, date.getFullYear());
  format = format.replace(/MM/g, ('0' + (date.getMonth() + 1)).slice(-2));
  format = format.replace(/DD/g, ('0' + date.getDate()).slice(-2));
  format = format.replace(/hh/g, ('0' + date.getHours()).slice(-2));
  format = format.replace(/mm/g, ('0' + date.getMinutes()).slice(-2));
  format = format.replace(/ss/g, ('0' + date.getSeconds()).slice(-2));
  if (format.match(/S/g)) {
    var milliSeconds = ('00' + date.getMilliseconds()).slice(-3);
    var length = format.match(/S/g).length;
    for (var i = 0; i < length; i++) format = format.replace(/S/, milliSeconds.substring(i, i + 1));
  }
  return format;
};
```

```javascript:e.g.
formatDate(new Date('2014/1/23'), 'MM月DD日'); // 01月23日
```

## 日付を加算する

ある日付に時間を加算した日付を返す。加算する単位（第三引数）を省略した場合、日付単位で加算する。

```javascript:addDate
/**
 * 日付を加算する
 * @param  {Date}   date       日付
 * @param  {Number} num        加算数
 * @param  {String} [interval] 加算する単位
 * @return {Date}              加算後日付
 */
var addDate = function (date, num, interval) {
  switch (interval) {
    case 'YYYY':
      date.setYear(date.getYear() + num);
      break;
    case 'MM':
      date.setMonth(date.getMonth() + num);
      break;
    case 'hh':
      date.setHours(date.getHours() + num);
      break;
    case 'mm':
      date.setMinutes(date.getMinutes() + num);
      break;
    case 'ss':
      date.setSeconds(date.getSeconds() + num);
      break;
    default:
      date.setDate(date.getDate() + num);
  }
  return date;
};
```

```javascript:e.g.
addDate(new Date('2014/1/23'), 1); // 2014/1/24
addDate(new Date('2014/2/23'), 1, 'MM'); // 2014/2/23 月が加算される
```

## 2つの日付の差を計算する

第二引数の日付から第一引数の日付を引いた差を数値で返す。差の単位（第三引数）を省略した場合、差を日付単位で返す。
単位以下の差は切り捨て（差がマイナスの場合は切り上げ）。

```javascript:dateDiff
/**
 * 2つの日付の差を計算する
 * @param  {Date}   date1      日付1
 * @param  {Date}   date2      日付2
 * @param  {String} [interval] 差の単位
 * @return {Number}            2つの日付の差
 */
var dateDiff = function (date1, date2, interval) {
  var diff = date2.getTime() - date1.getTime();
  switch (interval) {
    case 'YYYY':
      var d1 = new Date(date1.getTime());
      var d2 = new Date(date2.getTime());
      d1.setYear(0);
      d2.setYear(0);
      var i;
      if (diff >= 0) {
        i = d2.getTime() < d1.getTime() ? -1 : 0;
      } else {
        i = d2.getTime() <= d1.getTime() ? 0 : 1;
      }
      return date2.getYear() - date1.getYear() + i;
      break;
    case 'MM':
      var d1 = new Date(date1.getTime());
      var d2 = new Date(date2.getTime());
      d1.setYear(0);
      d1.setMonth(0);
      d2.setYear(0);
      d2.setMonth(0);
      var i;
      if (diff >= 0) {
        i = d2.getTime() < d1.getTime() ? -1 : 0;
      } else {
        i = d2.getTime() <= d1.getTime() ? 0 : 1;
      }
      return ((date2.getYear() * 12) + date2.getMonth()) - ((date1.getYear() * 12) + date1.getMonth()) + i;
      break;
    case 'hh':
      return ~~(diff / (60 * 60 * 1000));
      break;
    case 'mm':
      return ~~(diff / (60 * 1000));
      break;
    case 'ss':
      return ~~(diff / 1000);
      break;
    default:
      return ~~(diff / (24 * 60 * 60 * 1000));
  }
};
```

```javascript:e.g.
dateDiff(new Date('2014/1/1'), new Date('2012/1/2')); // 1
dateDiff(new Date('2014/1/1 12:00:00'), new Date('2012/1/2 00:00:00')); // 0 翌日だけど24時間経っていないので0
dateDiff(new Date('2014/1/1'), new Date('2013/1/1'), 'YYYY'); // -1
```

## CoffeeScript
以下CoffeeScriptでも書いてみたけれどあんまりテストはしていない

```coffeescript:formatDate
###*
 * 日付をフォーマットする
 * @param  {Date}   date     日付
 * @param  {String} [format] フォーマット
 * @return {String}          フォーマット済み日付
###
formatDate = (date, format = 'YYYY-MM-DD hh:mm:ss.SSS') ->
  format = format.replace /YYYY/g, date.getFullYear()
  format = format.replace /MM/g, ('0' + (date.getMonth() + 1)).slice(-2)
  format = format.replace /DD/g, ('0' + date.getDate()).slice(-2)
  format = format.replace /hh/g, ('0' + date.getHours()).slice(-2)
  format = format.replace /mm/g, ('0' + date.getMinutes()).slice(-2)
  format = format.replace /ss/g, ('0' + date.getSeconds()).slice(-2)
  if format.match /S/g
    milliSeconds = ('00' + date.getMilliseconds()).slice(-3)
    length = format.match(/S/g).length
    format.replace /S/, milliSeconds.substring(i, i + 1) for i in [0...length]
  return format
```

```coffeescript:addDate
###*
 * 日付を加算する
 * @param  {Date}   date       日付
 * @param  {Number} num        加算数
 * @param  {String} [interval] 加算する単位
 * @return {Date}              加算後日付
###
addDate = (date, num, interval) ->
  switch interval
    when 'YYYY'
      date.setYear date.getYear() + num
    when 'MM'
      date.setMonth date.getMonth() + num
    when 'hh'
      date.setHours date.getHours() + num
    when 'mm'
      date.setMinutes date.getMinutes() + num
    when 'ss'
      date.setSeconds date.getSeconds() + num
    else
      date.setDate date.getDate() + num
  return date
```

```coffeescript:dateDiff
###*
 * 日付を加算する
 * @param  {Date}   date       日付
 * @param  {Number} num        加算数
 * @param  {String} [interval] 加算する単位
 * @return {Date}              加算後日付
###
dateDiff = (date1, date2, interval) ->
  diff = date2.getTime() - date1.getTime()
  switch interval
    when 'YYYY'
      d1 = new Date date1.getTime()
      d2 = new Date date2.getTime()
      d1.setYear 0
      d2.setYear 0
      if diff >= 0
        i = d2.getTime() < d1.getTime() ? -1 : 0
      else
        i = d2.getTime() <= d1.getTime() ? 0 : 1
      return date2.getYear() - date1.getYear() + i
    when 'MM'
      d1 = new Date date1.getTime()
      d2 = new Date date2.getTime()
      d1.setYear 0
      d1.setMonth 0
      d2.setYear 0
      d2.setMonth 0
      if diff >= 0
        i = d2.getTime() < d1.getTime() ? -1 : 0
      else
        i = d2.getTime() <= d1.getTime() ? 0 : 1
      return ((date2.getYear() * 12) + date2.getMonth()) - ((date1.getYear() * 12) + date1.getMonth()) + i;
    when 'hh'
      return ~~(diff / (60 * 60 * 1000))
    when 'mm'
      return ~~(diff / (60 * 1000))
    when 'ss'
      return ~~(diff / 1000)
    else
      return ~~(diff / (24 * 60 * 60 * 1000))
```

## 蛇足

[Moment.js](http://momentjs.com/)というライブラリを使う方法も書いた。
http://qiita.com/osakanafish/items/5ef636bbcb2c3ef94953
(2015/1追記)。