intra-mart Accel Platform SAStruts+S2JDBC プログラミングガイド 第19版 2024-06-28

ユーザのタイムゾーンや日付と時刻の形式に対応するためのサンプルプログラム

本章では、ユーザが設定したタイムゾーンや日付と時刻の形式に従って、画面表示したり、画面から入力できるようにするためのサンプルプログラムを紹介します。 本章で紹介するサンプルプログラムは以下の考え方に基づいています。

前提

サンプルプログラムは、以下のテーブルが作成されていることを前提としたプログラムです。
  • テーブル定義

    CREATE TABLE example_table (
        user_cd     VARCHAR(100) NOT NULL,
        update_date TIMESTAMP  NOT NULL,
        PRIMARY KEY (user_cd)
    );
    

example_table テーブルの参照、更新を行うために、次のクラスが用意されていることを前提とします。
  • データベースアクセス

    example_table のレコード情報を格納するためのモデルクラスです。
    ExampleTableModel
    
    example_table の参照、更新を行うクラスです。
    SampleService
    

また、入力値や出力結果は以下の設定を前提として記載します。
  • 各種設定値
設定項目 設定値
アカウントタイムゾーン (ユーザのタイムゾーン) (GMT+09:00) 日本 / 東京
システムタイムゾーン (GMT+00:00) UTC
日付と時刻の形式 英語形式
日付(標準表示) MMM d, yyyy
日付(簡易表示) MMM d
日付(入力) yyyy/MM/dd
時刻(標準表示) h:mm a
時刻(タイムスタンプ表示) h:mm:ss a
時刻(入力) HH:mm

日付

ユーザが設定したタイムゾーンや日付と時刻の形式に従って、以下のように日付を相対的に扱うための流れを説明します。

日付を保存する

画面から入力された日付データをサーバ側で解析して、データベースに保存するまでの流れを説明します。
画面には、ユーザの日付入力形式で次の値が入力され、サーバに送信されたとします。
2012/09/19
サーバ側のプログラムは以下の通りです。
import java.util.Date;

import jp.co.intra_mart.foundation.context.Contexts;
import jp.co.intra_mart.foundation.context.model.AccountContext;
import jp.co.intra_mart.foundation.i18n.datetime.format.AccountDateTimeFormatter;
import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatIds;
import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatterException;
import jp.co.intra_mart.foundation.i18n.sa.sample.model.ExampleTableModel;
import jp.co.intra_mart.foundation.i18n.sa.sample.service.SampleService;
import jp.co.intra_mart.foundation.i18n.sa.sample.service.SampleServiceException;

/**
 * サンプル
 */
public class SampleDate {

    /**
     * 画面から送信された日付をデータベースに保存します。
     * <br />
     * @param inputDate 画面から送信された日時文字列
     * @throws DateTimeFormatterException
     * @throws SampleServiceException
     */
    public void sample(final String inputDate) throws DateTimeFormatterException, SampleServiceException {

        /*
         * 1. 画面から送信された日付文字列を解析します。
         */
        final Date date = AccountDateTimeFormatter.parse(inputDate, SystemTimeZone.getDefaultTimeZone(), Date.class, DateTimeFormatIds.IM_DATETIME_FORMAT_DATE_INPUT);

        /*
         * 2. モデルを利用して、データベースへ日付を保存します。
         */
        final ExampleTableModel model = new ExampleTableModel();
        model.setUserCd(Contexts.get(AccountContext.class).getUserCd());
        model.setDate(date);

        final SampleService service = SampleService.getInstance();
        service.update(model);

    }
}
ユーザの入力形式に沿った日時文字列を解析するためには、AccountDateTimeFormatter を使用します。
日付文字列の場合、時刻部分は「00:00:00」として解析されます。
AccountDateTimeFormatter にシステムタイムゾーンを指定すると、システムタイムゾーンのデータとして以下のように解析されます。
2012-09-19T00:00:00+00:00
データベースには、システムタイムゾーンに変換された日付データを保存します。
以下のようなデータが保存されます。
2012-09-19 00:00:00.000

保存されている日付を画面に表示する

データベースに保存されている日付を、ユーザの日付の表示形式を使って日付文字列に整形し、画面に表示するまでの流れを説明します。
サーバ側のプログラムは以下の通りです。
import jp.co.intra_mart.foundation.context.Contexts;
import jp.co.intra_mart.foundation.context.model.AccountContext;
import jp.co.intra_mart.foundation.i18n.datetime.format.AccountDateTimeFormatter;
import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatIds;
import jp.co.intra_mart.foundation.i18n.sa.sample.model.ExampleTableModel;
import jp.co.intra_mart.foundation.i18n.sa.sample.service.SampleService;
import jp.co.intra_mart.foundation.i18n.sa.sample.service.SampleServiceException;

/**
 * サンプル
 */
public class SampleDateView {

    /**
     * データベースに保存されている日付をユーザの画面に表示します。
     *
     * @return String 日付文字列
     * @throws SampleServiceException
     */
    public String sample() throws SampleServiceException {

        /*
         * 1. データベースから日時を取得します。
         */
        final ExampleTableModel model = SampleService.getInstance().get(Contexts.get(AccountContext.class).getUserCd());

        /*
         * 2. 日付文字列に整形します。
         */
        return AccountDateTimeFormatter.format(model.getDate(), SystemTimeZone.getDefaultTimeZone(), DateTimeFormatIds.IM_DATETIME_FORMAT_DATE_STANDARD);
    }
}
データベースには、システムタイムゾーンに変換された日付データが保存されています。
具体的には以下のようなデータが保存されていたとします。
2012-09-19 00:00:00.000
ユーザの日付と時刻の表示形式で整形する場合、AccountDateTimeFormatter を使用します。
以下の結果が得られます。
Sep 19, 2012

クライアント側で日付を扱う

クライアント側で、ユーザのタイムゾーンの今日から3日間の日付を生成し、最後の日付をサーバ側へ送信するまでの流れを説明します。
このサンプルを通して、csjs で日付や日時を扱う際の注意点を説明します。

1. ユーザのタイムゾーンの今日を取得する

ユーザのタイムゾーンにおける「今日」を csjs で取得するためには、intra-mart Accel Platform から提供されている ImDate を使用します。

注意

ユーザのタイムゾーンにおける「今日」の取得に、csjs の new Date を利用しないでください。
csjs の new Date はクライアント OS のタイムゾーンにおける現在日時データを返しますが、ユーザのタイムゾーンがクライアント OS のタイムゾーンと一致しているとは限りません。
<script type="text/javascript" src="im_i18n/timezone/im_date_timezone.js"></script>
<script type="text/javascript">
var firstDate = ImDate.now();
</script>

2. 今日から3日間の日付を生成する

Date に標準で用意されているメソッドを使用して構いません。
var dateArray = new Array();
var date = firstDate;
for (var i = 0; i < 3; i++) {
    dateArray[i] = date;
    date.setDate(date.getDate() + 1);
}

3. 日付をサーバ側へ送信する

年月日の値から日付文字列を作ります。
var lastDate = dateArray[2];
var lastDateStr = lastDate.getFullYear() + "-" + (lastDate.getMonth() + 1) + "-" + lastDate.getDate();

注意

ImDate.now() で生成した Date のエポックミリ秒は送信しないでください。

ImDate.now() の返す Date は、ユーザのタイムゾーンにおける「今日」の年月日時分秒を持っていますが、エポックミリ秒は正しいとは限りません。
理由は、クライアント側で Date を生成しているためです。
Date の持つエポックミリ秒は、クライアント OS のタイムゾーンで計算された値となり、ユーザのタイムゾーンで計算された値と一致しない可能性があります。

4. クライアント側から送信された日付文字列から Date を生成する

サーバ側のプログラムは以下の通りです。
import java.sql.Date;
import java.util.TimeZone;

import javax.servlet.http.HttpServletRequest;

import jp.co.intra_mart.foundation.i18n.timezone.SystemTimeZone;
import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatter;
import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatterException;

/**
 * サンプル
 */
public class SampleDTF {

    /**
     * クライアント側から送信された日付文字列から Date を生成します。
     * @param request リクエスト
     * @throws DateTimeFormatterException
     */
    public void sample(final HttpServletRequest request) throws DateTimeFormatterException {

        /*
         * 1. クライアント側から送信された日付文字列を取得します。
         */
        final String inputDateStr = request.getParameter("inputDate");

        /*
         * 2. DateTimeFormatter を使用して、日付文字列から Date を生成します。
         */
        final DateTimeFormatter formatter = DateTimeFormatter.withPattern("yyyy-MM-dd");
        formatter.setTimeZone(SystemTimeZone.getDefaultTimeZone());
        final Date inputDate = formatter.parse(inputDateStr, Date.class);
    }
}
日時文字列がユーザの日付と時刻の入力形式に沿っていない場合、DateTimeFormatter を使用します。
DateTimeFormatter は、直接フォーマットパターンを指定できます。

日時

ユーザが設定したタイムゾーンや日付と時刻の形式に従って、以下のように日時を絶対的に扱うための流れを説明します。

日時を保存する

画面から入力された日時をサーバ側で解析して、データベースに保存するまでの流れを説明します。
画面には、ユーザの日付と時刻の入力形式で次の値が入力され、サーバに送信されたとします。
2012/09/19 03:46
サーバ側のプログラムは以下の通りです。
import java.util.Date;

import jp.co.intra_mart.foundation.context.Contexts;
import jp.co.intra_mart.foundation.context.model.AccountContext;
import jp.co.intra_mart.foundation.i18n.datetime.format.AccountDateTimeFormatter;
import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatIds;
import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatterException;
import jp.co.intra_mart.foundation.i18n.sa.sample.model.ExampleTableModel;
import jp.co.intra_mart.foundation.i18n.sa.sample.service.SampleService;
import jp.co.intra_mart.foundation.i18n.sa.sample.service.SampleServiceException;

/**
 * サンプル
 */
public class SampleDateTime {

    /**
     * 画面から送信された日時をデータベースに保存します。
     *
     * @param inputDate 画面から送信された日時文字列
     * @throws DateTimeFormatterException
     * @throws SampleServiceException
     */
    public void sample(final String inputDate) throws DateTimeFormatterException, SampleServiceException {

        /*
         * 1. 画面から送信された日時文字列を解析します。
         */
        final Date date = AccountDateTimeFormatter.parse(inputDate, Date.class,
                DateTimeFormatIds.IM_DATETIME_FORMAT_DATE_INPUT,
                DateTimeFormatIds.IM_DATETIME_FORMAT_TIME_INPUT);

        /*
         * 2. モデルを利用して、データベースへ日時を保存します。
         */
        final ExampleTableModel model = new ExampleTableModel();
        model.setUserCd(Contexts.get(AccountContext.class).getUserCd());
        model.setDate(date);

        SampleService.getInstance().update(model);

    }
}
ユーザの入力形式に沿った日時文字列を解析するためには、AccountDateTimeFormatter を使用します。
AccountDateTimeFormatter にタイムゾーンを指定しなければ、ログインユーザのタイムゾーンのデータとして以下のように解析されます。
2012-09-18T18:46:00+00:00
データベースには、システムタイムゾーンに変換された日時データを保存します。
以下のようなデータが保存されます。
2012-09-18 18:46:00.000

保存されている日時を画面に表示する

データベースに保存されている日時を、ユーザのタイムゾーン、日付と時刻の表示形式を使って日時文字列に整形し、画面に表示するまでの流れを説明します。
サーバ側のプログラムは以下の通りです。
import jp.co.intra_mart.foundation.context.Contexts;
import jp.co.intra_mart.foundation.context.model.AccountContext;
import jp.co.intra_mart.foundation.i18n.datetime.format.AccountDateTimeFormatter;
import jp.co.intra_mart.foundation.i18n.datetime.format.DateTimeFormatIds;
import jp.co.intra_mart.foundation.i18n.sa.sample.model.ExampleTableModel;
import jp.co.intra_mart.foundation.i18n.sa.sample.service.SampleService;
import jp.co.intra_mart.foundation.i18n.sa.sample.service.SampleServiceException;

/**
 * サンプル
 */
public class SampleDateTimeView {

    /**
     * データベースに保存されている日時をユーザの画面に表示します。
     *
     * @return String 日時文字列
     * @throws SampleServiceException
     */
    public String sample() throws SampleServiceException {

        /*
         * 1. データベースから日時を取得します。
         */
        final ExampleTableModel model = SampleService.getInstance().get(Contexts.get(AccountContext.class).getUserCd());

        /*
         * 2. 日時文字列に整形します。
         */
        return AccountDateTimeFormatter.format(model.getDate(),
                DateTimeFormatIds.IM_DATETIME_FORMAT_DATE_STANDARD,
                DateTimeFormatIds.IM_DATETIME_FORMAT_TIME_STANDARD);
    }
}
データベースには、システムタイムゾーンに変換された日時データが保存されています。
具体的には以下のようなデータが保存されていたとします。
2012-09-18 18:46:00.000
ユーザの表示形式に沿った日時文字列に整形するためには、AccountDateTimeFormatter を使用します。
AccountDateTimeFormatter は、ログインユーザのタイムゾーンにおける時刻を計算します。
以下の結果が得られます。
Sep 19, 2012 3:46 AM