2009年6月28日日曜日

全く前の話とは関係ない話

時差を計算する関数、というか時刻を正規化する関数がLSLにないので書いてみました。この程度なら、LSLの知識がほとんどなくても書けます。

   1: integer JST = 9;
2: integer PDT = -7;
3:
4: integer FORMAT0 = 0;
5: integer FORMAT1 = 1;
6: integer FORMAT2 = 2;
7:
8: integer YEAR = 0;
9: integer MONTH = 5;
10: integer DAY = 8;
11: integer HOUR = 11;
12: integer MIN = 14;
13: integer SEC = 17;
14:
15: integer getDateTimeElement(string dateTimeString, integer startPos, integer length)
16: {
17: return (integer) llGetSubString(dateTimeString,
18: startPos, startPos + length - 1);
19: }
20:
21: string getTimeString1(
22: integer year, integer month, integer day,
23: integer hour, integer min, integer sec,
24: string timeZone)
25: {
26: return getTimeString3(year, month, day, hour, min, sec, "") +
27: llGetSubString("0" + (string) sec, -2, -1) + ".000000" + timeZone;
28: }
29:
30: string getTimeString2(
31: integer year, integer month,
32: integer day, integer hour, integer min, integer sec,
33: string timeZone)
34: {
35: return getTimeString3(year, month, day, hour, min, sec, "") + ":" +
36: llGetSubString("0" + (string) sec, -2, -1) + timeZone;
37: }
38:
39: string getTimeString3(
40: integer year, integer month, integer day,
41: integer hour, integer min, integer sec,
42: string timeZone)
43: {
44: return (string) year + "-" +
45: llGetSubString("0" + (string) month, -2, -1) + "-" +
46: llGetSubString("0" + (string) day, -2, -1) + " " +
47: llGetSubString("0" + (string) hour, -2, -1) + ":" +
48: llGetSubString("0" + (string) min, -2, -1) + timeZone;
49: }
50:
51: integer isLeap(integer year)
52: {
53: return (year % 400) == 0 || ((year % 4) == 0 && (year % 100) != 0);
54: }
55:
56: integer getMaxDay(integer year, integer month)
57: {
58: integer result = 30;
59:
60: if (month == 1 || month == 3 || month == 5 || month == 7 ||
61: month == 8 || month == 10 || month == 12) {
62: result = 31;
63: } else if (month == 2) {
64: result = 28 + isLeap(year);
65: }
66: return result;
67: }
68:
69: integer isChangeMonth(integer year, integer month, integer day)
70: {
71: integer result = 0;
72:
73: if (day < 1) {
74: result = -1;
75: } else if (getMaxDay(year, month) < day) {
76: result = 1;
77: }
78: return result;
79: }
80:
81: string normalize(string dateTimeString, integer timeDifference,
82: integer flag, string timeZone)
83: {
84: string result;
85: integer correction = 0;
86: integer year = getDateTimeElement(dateTimeString, YEAR, 4);
87: integer month = getDateTimeElement(dateTimeString, MONTH, 2);
88: integer day = getDateTimeElement(dateTimeString, DAY, 2);
89: integer hour = getDateTimeElement(dateTimeString, HOUR, 2);
90: integer min = getDateTimeElement(dateTimeString, MIN, 2);
91: integer sec = getDateTimeElement(dateTimeString, SEC, 2);
92:
93: // 時刻の補正
94: hour += timeDifference;
95: correction = 0;
96: while (hour < 0 || 24 <= hour) {
97: if (hour < 0) {
98: hour += 24;
99: correction--;
100: } else {
101: hour -= 24;
102: correction++;
103: }
104: }
105:
106: // 年・月・日の補正
107: day += correction;
108: correction = isChangeMonth(year, month, day);
109: while (correction != 0) {
110: month += correction;
111: if (month < 1) {
112: year--;
113: month = 12;
114: day = 31;
115: } else if (12 < month) {
116: year++;
117: month = 1;
118: day = 1;
119: } else {
120: if (correction < 0) {
121: day = getMaxDay(year, month);
122: } else {
123: day = 1;
124: }
125: }
126: correction = isChangeMonth(year, month, day);
127: }
128:
129: if (flag == FORMAT0) {
130: result = getTimeString1(year, month, day, hour, min, sec, timeZone);
131: } else if (flag == FORMAT1) {
132: result = getTimeString2(year, month, day, hour, min, sec, timeZone);
133: } else {
134: result = getTimeString3(year, month, day, hour, min, sec, timeZone);
135: }
136: return result;
137: }

これ、年甲斐もなく、結構悩みました。ここを見てみると、とてもちぐはぐな感じが否めません。
システム内で、LSLで日時を扱う標準形式がなんなのかよく分からないのです。「integer llGetUnixTime( );」で求まる整数値(1970/01/01 00:00からの経過秒数)が一番シンプルなのですが、文字列形式と、この経過秒数の変換方法が全く提供されていません。で、考えることしばし。

結局、「string llGetTimestamp( );」で得られる、"YYYY-MM-DDThh:mm:ss.ff..fZ"形式を使ってしまいました。ちぐはぐというか、文字列を標準形式にするのとても気持ち悪いです。これW3Cで決まっているある程度権威のあるフォーマットなのですが、LSLの文字列処理機能の貧弱さ(この貧弱さというのは無視して下さい。筆者はC言語以外の言語で、文字列の取り扱いをするのが大嫌いなので)を考えると、いやだなぁと思ってしまいます。

ということで、この関数
string localTime = normalize(llGetTimestamp(), JST, FORMAT3, "");
なんて使うと、現在の日本時間が得られます。JST を PDT に変えればリンデン時間が得られます。
また、、"YYYY-MM-DDThh:mm:ss.ff..fZONE"形式で時刻をセットして JSTを JST - PDT にすれば、リンデン時間を日本時間に、逆に PDT - JST をセットすれば日本時間をリンデン時間にも変換できます。

なんでこんな物を作ったのかというと、公式ページなんかでイベントをリンデン時間で書いてあるのを日本時間に、頭の中で変換して読むのがめんどくさかったので、時刻変換時計を作りました。これは、その副産物です。
そうそう、リンデン時間は米国西岸時間なので、サマータイムの事も考えなきゃいけないんでしたが、それはそれ、これはこれということで。

0 件のコメント:

コメントを投稿