Help us understand the problem. What is going on with this article?

デバッグ日付を使って未来へ過去へと行き来する

More than 3 years have passed since last update.

はじめに

 何を書こうかいろいろ迷いましたが、gloopsで行っている開発のちょっとしたテクニックとして
 個人ごとに"現在時刻"を変更できるデバッグ機能を紹介したいと思います。
 ガチャ開催中の画面を確認したい、イベントが終了した後の画面を確認したいなど
 開発を進めていく上で時間の変化によってのプログラムの挙動を確認したいことは頻繁にあります。
 この要件を解決するためにRedisを使った時刻変更デバッグ機能を用意しています。

デバッグ日付対応DateTimeクラスを作る

プログラム内で時間を取得する際、DateTimeを呼び出すのではなく下記のようなクラスを用意します。
(実際はもう少し複雑ですが、簡略化してます)

    public class DebugDate
    {
        /// <summary>
        /// 個人識別ID
        /// </summary>
        public static int PersonalId
        {
            get
            {
              var personalId = 1;
              //本来はHttpContextクラス等から個人識別IDを取得してIDを返す
              return personalId;
            }
        }

        /// <summary>
        /// プロジェクト内で使用する現在日付を返す
        /// </summary>
        public static DateTime Now
        {
            get
            {
#if DEBUG
                return GetDatabaseTime(PersonalId);
#else
                return DateTime.Now;
#endif
            }
        }

#if DEBUG

        /// <summary>
        /// 現在時刻を取得する(Debug用)
        /// </summary>
        public static DateTime GetDatabaseTime(int personalId)
        {
            var databaseTime = DateTime.Now;

            TimeSpan? debugSpan;

            //RedisからTimeSpan?オブジェクトを取得
            var redisKey = "debug_time_test:" + personalId;
            var  isGetData = SampleRedisClass.TryGet(redisKey, out debugSpan);

            //debugSpanの値がある場合は現実時間に時間差分(debugSpan)加えて返す
            return isGetData  && debugSpan.HasValue
                ? databaseTime.Add(debugSpan.Value)
                : databaseTime;
        }
#endif
    }
}

ポイントとなるのはGetDatabaseTimeメソッドの部分で
RedisからTimeSpanクラスを取得し...

            //RedisからTimeSpan?オブジェクトを取得
            var redisKey = "debug_time_test:" + personalId;
            var  isGetData = SampleRedisClass.TryGet(redisKey, out debugSpan);

現在時刻にTimeSpanを加算してから返すことで日付を偽装してます。

            //debugSpanの値がある場合は現実時間に時間差分(debugSpan)加えて返す
            return isGetData  && debugSpan.HasValue
                ? databaseTime.Add(debugSpan.Value)
                : databaseTime;

デバッグ日付設定用ページを作る

 適当なTextBoxとButtonを配置して下記のようなアクションを用意すれば準備完了です。
 あとはメインのプログラムでDebugDateクラスを呼び出すだけ

        /// <summary>
        /// デバッグ日付を設定する
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void OnEditDate(object sender, EventArgs e)
        {
            //画面で入力されたテキストの日付をDateTime変換
            DateTime resultDate;
            var debugTime = text_debug_time.Text;
            var debugDate = DateTime.TryParse(debugTime, out resultDate);
            if (!debugDate)
            {
                l_result_message.Text = "時間フォーマットが不正";
                return;
            }

            //変更したい時間と現在の時間の差を計算
            var timeSpan = resultDate - DateTime.Now;

            try
            {
                var personalId = txt_personal_id.Text;

                var redisKey = "debug_time_test:" + personalId; //redisに設定するキー
                var redisValue = timeSpan; //redisに設定する値
                var limit = TimeSpan.FromHours(2.0); //有効時間

                //RedisにTimeSpanを設定する
                SampleRedisClass.Set(redisKey, redisValue, limit);
            }
            catch (Exception ex)
            {
                l_result_message.Text = ex.Message;
            }

            text_debug_time.Text = DebugDate.Now.ToString("yyyy/MM/dd HH:mm:ss");
            l_result_message.Text = "変更成功";
        }

メインページでの呼び出し方

呼び出し方はこんな感じです

    public partial class main : SampleDebugPage
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            var now = DebugDate.Now; //デバッグ用の日付を取得する
            l_debug_time.Text = now.ToString("yyyy/MM/dd HH:mm:ss");
            l_message.Text = GetMassage(now);
        }

        private string GetMassage(DateTime now)
        {
            if (now.Year == 2005 && now.Month == 8 && now.Day == 2)
            {
                return "gloops 設立!";

            } else if (now.Year == 2017 && now.Month == 12 && now.Day == 18)
            {
                return "ちょうど1年後!";
            }
            else if(now.Year == 2016 && now.Month == 12 && now.Day == 25)
            {
                return "お仕事中...";

            }

            return "-";
        }
    }

実行結果

デバッグ画面で日付を設定して・・・
image

メインページでの表示はこのとおり
image

※なお設定した時間はその時刻で固定されることなく進行していきます
image

これを使えば・・
image

おりゃ!!!
image

ほれ!!!
image

このように未来にも過去にも自由自在!
開発メンバーは自分だけのすきな時間軸で開発・テストをすすめることができるのです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした