時隔兩個月了,這段時間,游戲籌備正式上線,根據游戲平台數據反饋,反響還不錯。
但是牽涉出新問題,就是活動。活動功能本身很簡單。問題就在於,時間配置上,什麼時間段開發活動。
配置多種多樣。比如,沒做星期2,4,6活動。每周的周六,周日,活動。指定月份和日期的活動。配置簡直是天花亂墜了。。。這尼瑪怎麼搞????
那麼有麼有萬能的配置方式呢?首先,我能想到的配置肯定是字符串格式的。
必須包含,年月日星期時間,這尼瑪不就犯難了嘛????我們C#的 DateTime 類型格式化只支持年月日,時分秒啊。星期怎麼控制???例如,我要每個星期的星期天搞一個活動,拉一拉充值消費我擦。。。
我自己都把自己繞暈了。。好吧。。。
後來想到一種方式,
[年][月][日][星期][時間]
[*][*][*][*][*]
這樣利於分割,配置,清晰。
然後就是驗證,時間在不在配置的時間開發內?
當然想到的*肯定是默認支持所有的
[2015][7][*][*][10:00-11:59]
這個格式,表示2015年的7月每一天的10點到12點為配置開啟時間
[2015][7-9][*][*][10:00-11:59]
這個格式,表示2015年的7月1日到9月30的每一天的10點到12點為配置開啟時間
[2015][7/9][*][*][10:00-11:59]
這個格式,表示2015年的7月或者9月的每一天的10點到12點為配置開啟時間
[2015][*][*][2/4/6][10:00-11:59]
這個格式,表示2015年的每一個星期2,星期4,星期6 的每一天的10點到12點為配置開啟時間
接下來,就是驗證這個時間格式。
1 #region 驗證當前時間 年,月,日,星期,是否符合 static bool VerifyDate(int nowItem, string items)
2 /// <summary>
3 /// 驗證當前時間 年,月,日,星期,是否符合
4 /// </summary>
5 /// <param name="items">1-7;表示 1 到 7 , 1/7 表示 1 或者 7</param>
6 /// <returns></returns>
7 static bool VerifyDate(int nowItem, string items)
8 {
9 string nowItemStr = nowItem.ToString();
10 if ("*".Equals(items) || nowItemStr.Equals(items)) { return true; }
11 else if (items.IndexOf("-") > 0)
12 {//區間劃分
13 string[] itemSplit = items.Split('-');
14 int item1 = 9999;
15 int.TryParse(itemSplit[0], out item1);
16 int item2 = 9999;
17 int.TryParse(itemSplit[1], out item2);
18
19 if (item1 <= nowItem && nowItem <= item2) { return true; }
20 }
21 else if (items.IndexOf("/") > 0)
22 {//或劃分
23 string[] weeksSplit = items.Split('/');
24 foreach (var item in weeksSplit)
25 {
26 if (nowItemStr.Equals(item)) { return true; }
27 }
28 }
29 return false;
30 }
31 #endregion
32
33 #region 驗證當期時間格式 static bool VerifyTime(DateTime date, string itemTime)
34 /// <summary>
35 /// 驗證當期時間格式
36 /// </summary>
37 /// <param name="date"></param>
38 /// <param name="itemTime"></param>
39 /// <returns></returns>
40 static bool VerifyTime(DateTime date, string itemTime)
41 {
42 bool ret = false;
43 if (!"*".Equals(itemTime))
44 {
45 var items = Regex.Split(itemTime, @"/");
46 foreach (var item in items)
47 {
48 string[] itemTimes = item.Split('-');
49 var hhmm = Regex.Split(itemTimes[0], @":|:");
50 int hh = 24;
51 int.TryParse(hhmm[0], out hh);
52 int mm = 60;
53 int.TryParse(hhmm[1], out mm);
54 if (date.Hour > hh || (date.Hour == hh && date.Minute >= mm))
55 {
56 if (itemTimes.Length > 1)
57 {
58 var hhmm1 = Regex.Split(itemTimes[1], @":|:");
59 int hh1 = 24;
60 int.TryParse(hhmm1[0], out hh1);
61 int mm1 = 60;
62 int.TryParse(hhmm1[1], out mm1);
63 if (date.Hour < hh1 || (date.Hour == hh1 && date.Minute < mm1)) { ret = true; }
64 else { ret = false; }
65 }
66 else { ret = true; }
67 }
68 else { ret = false; }
69 if (ret)
70 {
71 break;
72 }
73 }
74 }
75 else { ret = true; }
76 return ret;
77 }
78 #endregion
看看結果
這樣挺萬能的吧?
如果每一天有兩檔活動開放
[2015][7][*][*][10:00-11:59/14:00-16:59]

當我完成了這個需求的時候,,新的需求又來了,,,媽蛋,,,需要倒計時,,活動還有多長時間開始。。
臥槽。。
好吧,,有需求就是大爺。。只能苦逼的程序去搞定了,需求一句話,我卻花了一天時間啊。。。
我的思路是分解出,所包含的年月日,時間段開始。
1 #region 獲取配置的年月日星期等信息 static List<int> GetConfigDate(DateTime date, int p1, string p3)
2 /// <summary>
3 /// 獲取配置的年月日星期等信息
4 /// </summary>
5 /// <param name="date"></param>
6 /// <param name="p1"></param>
7 /// <param name="p3"></param>
8 /// <returns></returns>
9 static List<int> GetConfigDate(DateTime date, int p1, string p3)
10 {
11 List<int> rets = new List<int>();
12 string p1Str = p1.ToString();
13 if ("*".Equals(p3) || p1Str.Equals(p3))
14 {
15 rets.Add(p1);
16 rets.Add(p1 + 1);
17 }
18 else if (p3.IndexOf("-") > 0)
19 {
20 string[] weekSplit = p3.Split('-');
21 int week1 = 9999;
22 int.TryParse(weekSplit[0], out week1);
23
24 int week2 = 9999;
25 int.TryParse(weekSplit[1], out week2);
26 for (int i = week1; i < week2 + 1; i++)
27 {
28 rets.Add(i);
29 }
30 }
31 else if (p3.IndexOf("/") > 0)
32 {
33 string[] weeksSplit = p3.Split('/');
34 foreach (var item in weeksSplit)
35 {
36 int temp = 0;
37 if (int.TryParse(item, out temp))
38 {
39 rets.Add(temp);
40 }
41 }
42 }
43 else
44 {
45 int temp = 0;
46 if (int.TryParse(p3, out temp))
47 {
48 rets.Add(temp);
49 }
50 }
51 return rets;
52 }
53 #endregion
54
55 #region 獲取配置的時間字符串 static List<string> GetConfigTimeStr(string itemTime)
56 /// <summary>
57 /// 獲取配置的時間字符串
58 /// </summary>
59 /// <param name="itemTime">必須類似的格式 單條 00:00-23:59 多條00:00-23:59/00:00-23:59</param>
60 /// <returns></returns>
61 static List<string> GetConfigTimeStr(string itemTime)
62 {
63 List<string> retObjs = new List<string>();
64 // 00:00-23:59
65 if (!"*".Equals(itemTime))
66 {
67 var items = Regex.Split(itemTime, @"/");
68 foreach (var item in items)
69 {
70 string[] itemTimes = item.Split('-');
71 retObjs.Add(itemTimes[0]);
72 }
73 }
74 else
75 {
76 retObjs.Add("00:00");
77 }
78 return retObjs;
79 }
80 #endregion
這裡有一個蛋疼的問題,就是包含了星期,那麼無疑與日期就要牽涉跨星期跨月,跨年了,

在這裡特別鳴謝兄弟幫忙的分析。。
所以我分析出來,檢查包含的年月日來構造datetime 然後完成7天構造器。來分析時間段。
如果是本月那麼就從當前的日期開始,如果不是本月那麼就從1號開始,
1 #region 處理星期包含的日期 日 static void ActionWeekDay(int weekmin, int weekmax, ref List<int> days, ref List<int> months, ref List<int> years)
2 /// <summary>
3 /// 處理星期包含的日期 日
4 /// </summary>
5 /// <param name="weekmin"></param>
6 /// <param name="weekmax"></param>
7 /// <param name="days"></param>
8 /// <param name="months"></param>
9 /// <param name="years"></param>
10 static void ActionWeekDay(int weekmin, int weekmax, ref List<int> days, ref List<int> months, ref List<int> years)
11 {
12 DateTime nowWeekDate = DateTime.Now;
13 List<int> tempDays, tempMonths, tempYears;
14 tempYears = years.ToList();
15 tempMonths = months.ToList();
16 tempDays = days.ToList();
17 foreach (var itemYear in tempYears)
18 {
19 foreach (var itemMonth in tempMonths)
20 {
21 int itemDay = 1;
22 if (nowWeekDate.Month == itemMonth)
23 {
24 itemDay = nowWeekDate.Day;
25 }
26 DateTime date = new DateTime(itemYear, itemMonth, itemDay);
27 for (int i = 0; i < 7; i++)
28 {
29 int week = (int)date.DayOfWeek;
30 if (week == 0)
31 {
32 week = 7;
33 }
34 if (weekmin <= week && week <= weekmax)
35 {
36 if (!days.Contains(date.Day))
37 {
38 days.Add(date.Day);
39 }
40 if (!months.Contains(date.Month))
41 {
42 months.Add(date.Month);
43 }
44 if (!years.Contains(date.Year))
45 {
46 years.Add(date.Year);
47 }
48 }
49 date = date.AddDays(1);
50 }
51 }
52 }
53 }
54 #endregion
驗證器
1 #region 驗證時間:[*][*][20/22][*][10:00-11:59/16:00-17:59] static public long VerifyDateTime(string timeStr)
2 /// <summary>
3 /// 驗證時間:[*][*][20/22][*][10:00-11:59/16:00-17:59]
4 /// <para>第一個是年,,第二個是月,第三個是日期,第四個是星期,第五個是時間,</para>
5 /// <para>每一個參數,"-" 表示 到 如:“2015-2017”表示 2015 到 2017, "/" 表示 或者 如: “2015/2017”表示2015 或者 2017</para>
6 /// <para>返回值 -1 表示永久過期,0 表示在時間規則內,大於 0 表示倒計時</para>
7 /// </summary>
8 static public long VerifyDateTime(string timeStr)
9 {
10 var items = Regex.Split(timeStr, @";|;");
11 items.Reverse();
12 long ret = -1;
13 DateTime date = DateTime.Now;
14 foreach (var item in items)
15 {
16 //驗證時間匹配
17 if (VerifyConfigTimeStr(date, item))
18 {
19 ret = 0;
20 goto Lab_Exit;
21 }
22 //未通過時間匹配,檢查返回剩余時間
23 List<string> strs = new List<string>();
24 string[] timeStrs = item.Split(new char[] { ']' });
25 for (int i = 0; i < timeStrs.Length - 1; i++)
26 {
27 string time = timeStrs[i].Replace("[", "");
28 strs.Add(time);
29 }
30
31 string times = strs[4];
32 string weeks = strs[3];
33 string days = strs[2];
34 string months = strs[1];
35 string years = strs[0];
36
37 int hour = 0, minute = 0, second = 0;
38 var tempYears = GetConfigDate(date, date.Year, years);
39 var tempMonths = GetConfigDate(date, date.Month, months);
40 var tempDays = GetConfigDate(date, date.Day, days);
41 //由於星期比較特殊所以獲取與星期相關的日期的時候有點詭異。
42 if (!"*".Equals(weeks))
43 {
44 if (weeks.IndexOf("-") > 0)
45 {
46 //星期的間隔模式
47 string[] weekSplit = weeks.Split('-');
48 int weekmin = 9999;
49 int.TryParse(weekSplit[0], out weekmin);
50 int weekmax = 9999;
51 int.TryParse(weekSplit[1], out weekmax);
52 ActionWeekDay(weekmin, weekmax, ref tempDays, ref tempMonths, ref tempYears);
53 }
54 else if (weeks.IndexOf("/") > 0)
55 {
56 //星期的或模式
57 string[] weeksSplit = weeks.Split('/');
58 int tempWeek;
59 if (int.TryParse(weeksSplit[0], out tempWeek))
60 {
61 if (0 <= tempWeek && tempWeek <= 7)
62 {
63 ActionWeekDay(tempWeek, tempWeek, ref tempDays, ref tempMonths, ref tempYears);
64 }
65 }
66 }
67 else
68 {
69 //特定星期的模式
70 int tempweek = 0;
71 if (int.TryParse(weeks, out tempweek))
72 {
73 ActionWeekDay(tempweek, tempweek, ref tempDays, ref tempMonths, ref tempYears);
74 }
75 }
76 }
77 else
78 {
79 //未指定星期的模式
80 ActionWeekDay(1, 7, ref tempDays, ref tempMonths, ref tempYears);
81 }
82
83 var tempHHMMs = GetConfigTimeStr(times);
84
85 //進行簡單的排序
86 tempYears.Sort();
87 tempMonths.Sort();
88 tempDays.Sort();
89 tempHHMMs.Sort();
90
91 //接下來這裡是天坑,就是構造時間器比較,然後計算出倒計時
92 for (int y = 0; y < tempYears.Count; y++)
93 {
94 for (int m = 0; m < tempMonths.Count; m++)
95 {
96 for (int d = 0; d < tempDays.Count; d++)
97 {
98 for (int h = 0; h < tempHHMMs.Count; h++)
99 {
100 string[] hhmm = Regex.Split(tempHHMMs[h], ":|:");
101 if (int.TryParse(hhmm[0], out hour) && int.TryParse(hhmm[1], out minute))
102 {
103 DateTime actionTime = new DateTime(tempYears[y], tempMonths[m], tempDays[d], hour, minute, second);
104 if (actionTime > date)
105 {
106 if (VerifyConfigTimeStr(actionTime, item))
107 {
108 Console.WriteLine(actionTime.ToString("yyyy-MM-dd HH:mm:ss"));
109 TimeSpan ts = (actionTime - date);
110 ret = ts.Days * 24 * 60 * 60 + ts.Hours * 60 * 60 + ts.Minutes * 60 + ts.Seconds;
111 ret *= 1000;
112 ret += ts.Milliseconds;
113 goto Lab_Exit;
114 }
115 }
116 }
117 }
118 }
119 }
120 }
121 }
122 Lab_Exit:
123 return ret;
124 }
125 #endregion
驗證活動配置時間
[2016][2][*][*][10:00-11:59/14:00-16:59]

接下來我們在測試一下性能問題,

大家都懂的,在控制台輸出打印是比較耗時的,這種情況下2000次也才1秒;效率是不必是說的。
全部完整代碼。。

好了謝謝大家的收看。。。我搬磚去了。。。
忘了告訴大家,"-"表示間隔,"/"表示包含的意思 支持多個時間配置器哦;
[2015][7][20-31][*][10:00-11:59/14:00-16:59];[2015][8][1-5][*][10:00-11:59/14:00-16:59]
這樣配置表示2015年的7月20號到8月5號的每天兩檔活動~!
本想翻譯java的,,,結果我太懶了。。。。