Slim3 の Timezone の取り扱いについて

Slim3タイムゾーンの挙動が複雑なことに気が付いた。

  1. FrontController では、タイムゾーンUTC に設定されている。
  2. TestCase から FrontController で設定されているタイムゾーンはローカル時間。
    この場合、自分は日本時間に設定しているので、JST で設定されている。
  3. TestCase で使う Controller のタイムゾーンはローカル時間。
    この場合も JST で設定されている。しかし、org.slim3.util.DateUtil 利用した際のタイムゾーンUTC になる。
  4. org.slim3.util.DateUtil を利用すると、web.xml で設定している時間帯に自動的に変換される。

FrontController のタイムゾーンの挙動

コントローラー側の記述。

public class TimezoneController extends Controller {
    @Override
    public Navigation run() throws Exception {
        TimeZone tz = TimeZone.getDefault();
        requestScope("timeId", tz.getID());
        requestScope("timeZoneName", tz.getDisplayName());
        requestScope("offset", tz.getRawOffset());
        return forward("timezone.jsp");
    }
}

JSP の記述。

<%@page pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%@taglib prefix="f" uri="http://www.slim3.org/functions"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>タイムゾーン</title>
</head>
<body>
    <p>${f:h(timeId)}</p>
    <p>${f:h(timeZoneName)}</p>
    <p>${f:h(offset)}</p>
</body>
</html>

表示結果

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>タイムゾーン</title>
</head>
<body>
    <p>UTC</p>
    <p>協定世界時</p>
    <p>0</p>
</body>
</html>

コントローラーでローカルのタイムゾーンを設定した場合。

public class TimezoneController extends Controller {
    @Override
    public Navigation run() throws Exception {
        TimeZone tz = TimeZone.getTimeZone("Asia/Tokyo");
        requestScope("timeId", tz.getID());
        requestScope("timeZoneName", tz.getDisplayName());
        requestScope("offset", tz.getRawOffset());
        return forward("timezone.jsp");
    }
}

実行結果。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>タイムゾーン</title>
</head>
<body>
    <p>Asia/Tokyo</p>
    <p>日本標準時</p>
    <p>32400000</p>
</body>
</html>

FrontController のタイムゾーンの挙動と org.slim3.util.DateUtil 利用後のタイムゾーン

TimeZone.getTimeZone("Asia/Tokyo") の場合

public class TimezoneController extends Controller {
    @Override
    public Navigation run() throws Exception {
        TimeZone tz = TimeZone.getTimeZone("Asia/Tokyo");
        Calendar cal = Calendar.getInstance(tz);
        String datePattern = "yyyy-MM-dd HH:mm:ss z";
        requestScope("timeId", tz.getID());
        requestScope("timeZoneName", tz.getDisplayName());
        requestScope("offset", tz.getRawOffset());
        requestScope("calendarDateTime", cal.getTime());
        requestScope("dateDateTime", new Date());
        requestScope("dateUtilzedDateTimeOfCalendar", DateUtil.toString(cal.getTime(), datePattern));
        requestScope("dateUtilzedDateTimeOfDate", DateUtil.toString(new Date(), datePattern));
    }
}

実行結果。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>タイムゾーン</title>
</head>
<body>
    <p>Asia/Tokyo</p>
    <p>日本標準時</p>
    <p>32400000</p>
    <!-- Calendar から作成した日時 -->
    <p>Fri Jul 22 04:42:53 UTC 2011</p>
    <!-- Date を利用した日付 -->
    <p>Fri Jul 22 04:42:53 UTC 2011</p>
    <!-- org.slim3.util.DateUtil を利用した Calendar の日付 -->
    <p>2011-07-22 13:42:53 JST</p>
    <!-- org.slim3.util.DateUtil を利用した Date の日付 -->
    <p>2011-07-22 13:42:53 JST</p>
</body>
</html>

TimeZoneLocator.get() の場合。

public class TimezoneController extends Controller {
    @Override
    public Navigation run() throws Exception {
        TimeZone tz = TimeZoneLocator.get();
        Calendar cal = Calendar.getInstance(tz);
        String datePattern = "yyyy-MM-dd HH:mm:ss z";
        requestScope("timeId", tz.getID());
        requestScope("timeZoneName", tz.getDisplayName());
        requestScope("offset", tz.getRawOffset());
        requestScope("calendarDateTime", cal.getTime());
        requestScope("dateDateTime", new Date());
        requestScope("dateUtilzedDateTimeOfCalendar", DateUtil.toString(cal.getTime(), datePattern));
        requestScope("dateUtilzedDateTimeOfDate", DateUtil.toString(new Date(), datePattern));
    }
}

実行結果。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>タイムゾーン</title>
</head>
<body>
    <p>Asia/Tokyo</p>
    <p>日本標準時</p>
    <p>32400000</p>
    <!-- Calendar から作成した日時 -->
    <p>Fri Jul 22 04:46:15 UTC 2011</p>
    <!-- Date を利用した日付 -->
    <p>Fri Jul 22 04:46:15 UTC 2011</p>
    <!-- org.slim3.util.DateUtil を利用した Calendar の日付 -->
    <p>2011-07-22 13:46:15 JST</p>
    <!-- org.slim3.util.DateUtil を利用した Date の日付 -->
    <p>2011-07-22 13:46:15 JST</p>
</body>
</html>

Oh...
予想では、TimeZone.getTimeZone("Asia/Tokyo") と TimeZoneLocator.get() で明示して設定した cal.getTime() から日本時間(Fri Jul 22 13:46:15 JST 2011)が帰ってくると思っていたが、UTC の時間が表示されている。
また、TimeZone.getTimeZone("Asia/Tokyo") と TimeZoneLocator.get() で明示して設定した後に、

        TimeZone tz = TimeZone.getTimeZone("Asia/Tokyo");
        Calendar cal = Calendar.getInstance(tz);
        cal.setTimeZone(tz);
        cal.setTime(new Date());
        requestScope("calendarDateTime", cal.getTime());

とCalendar クラスにタイムゾーンを設定しても、

    <!-- Calendar から作成した日時 -->
    <p>Fri Jul 22 04:46:15 UTC 2011</p>
    <!-- Date を利用した日付 -->
    <p>Fri Jul 22 04:46:15 UTC 2011</p>

タイムゾーンは変わらなかった。

DateFormat クラスと SimpleDateFormat クラス

日付を Date クラスから出力する場合は、DateFormat クラスか SimpleDateFormat クラスを経由して任意のタイムゾーンの日付に変換する必要があるのが、(やっと)わかった。
上記の Controller の場合、

public class TimezoneController extends Controller {
    @Override
    public Navigation run() throws Exception {
        TimeZone tz = TimeZone.getTimeZone("Asia/Tokyo");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
        sdf.setTimeZone(tz);
        DateFormat df = DateFormat.getInstance();
        df.setTimeZone(tz);
        Calendar cal = Calendar.getInstance();
        String datePattern = "yyyy-MM-dd HH:mm:ss z";
        requestScope("timeId", tz.getID());
        requestScope("timeZoneName", tz.getDisplayName());
        requestScope("offset", tz.getRawOffset());
        requestScope("calendarDateTime", cal.getTime());
        requestScope("dateFormat", df.format(cal.getTime()));
        requestScope("simpleDateFormat", sdf.format(cal.getTime()));
        requestScope("dateUtilzedDateTimeOfCalendar", DateUtil.toString(cal.getTime(), datePattern));
        requestScope("dateUtilzedDateTimeOfDate", DateUtil.toString(new Date(), datePattern));
    }
}

そして JSP は、

<%@page pageEncoding="UTF-8" isELIgnored="false" session="false"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%@taglib prefix="f" uri="http://www.slim3.org/functions"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>タイムゾーン</title>
</head>
<body>
    <p>${f:h(timeId)}</p>
    <p>${f:h(timeZoneName)}</p>
    <p>${f:h(offset)}</p>
    <!-- Calendar から作成した日時 -->
    <p>${f:h(calendarDateTime)}</p>
    <!-- DateFormat を利用した日付 -->
    <p>${f:h(dateFormat)}</p>
    <!-- SimpeDateFormat を利用した日付 -->
    <p>${f:h(simpleDateFormat)}</p>
    <!-- org.slim3.util.DateUtil を利用した Calendar の日付 -->
    <p>${f:h(dateUtilzedDateTimeOfCalendar)}</p>
    <!-- org.slim3.util.DateUtil を利用した Date の日付 -->
    <p>${f:h(dateUtilzedDateTimeOfDate)}</p>
</body>
</html>

そして結果は、

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>タイムスタンプ</title>
</head>
<body>
    <p>Asia/Tokyo</p>
    <p>日本標準時</p>
    <p>32400000</p>
    <!-- Calendar から作成した日時 -->
    <p>Fri Jul 22 07:28:40 UTC 2011</p>
    <!-- DateFormat を利用した日付 -->
    <p>11/07/22 16:28</p>
    <!-- SimpeDateFormat を利用した日付 -->
    <p>2011-07-22 16:28:40 JST</p>
    <!-- org.slim3.util.DateUtil を利用した Calendar の日付 -->
    <p>2011-07-22 16:28:40 JST</p>
    <!-- org.slim3.util.DateUtil を利用した Date の日付 -->
    <p>2011-07-22 16:28:40 JST</p>
</body>
</html>

これで意図通りの結果が得られるようになった…。