有圖(?)有連結的網頁版:
http://blog.dontcareabout.us/2012/02/gwtgae.html
========
開發環境:GWT 2.4.0、GAE 1.6.1、GPE 2.5.1、Objectify 3.0
正在作一個預約系統,很自然會有「取出某天所有預約」之類的需求,
所以將 class 設計成這樣,期望能節省一些麻煩:
class Booking{
Date date;
int hour; //時間間隔以「小時」為單位
//skip other field
}
由於 GAE 的 Datastore 理論上沒有提供在 query 時可以卡入日期函數,
所以如果不對日期作處理,下面這段「取得今天的預約」會完全取不到任何東西:
Objectify ofy = ObjectifyService.begin();
ofy.query(Booking.class).filter("date", new Date()).list(); //empty list
原因應該是在於 Datastore 作比對時是直接使用 equal()(個人猜測,沒有實際證據),
而 java.util.Date 的 equal() 是判斷 getTime()......
這取得到東西的或然率真的接近零了。
最直覺的反應是將日期中「小時」以下的單位全部歸零,
在 GWT 的 CalendarUtil 可以找到 resetTime() 的寫法:
@SuppressWarnings("deprecation") // GWT requires Date
private static void resetTime(Date date) {
long msec = date.getTime();
msec = (msec / 1000) * 1000;
date.setTime(msec);
// Daylight savings time occurs at midnight in some time zones, so we reset
// the time to noon instead.
date.setHours(12);
date.setMinutes(0);
date.setSeconds(0);
}
用這個方法,將 client 端傳上 server 的 date 都先「整理」過。
當然,媽媽說:「不要總是相信 client 端給的值」,
抱持著能省則省的白痴想法,所以忽略 deprecated 的訊息,
讓 server 也用同樣方法......
神奇的事情發生了,有時候會正確、有時候會失敗......
問題可以簡化成「client 端傳遞一個 reset 過的 date 給 server、
server 再 reset 一次回傳回來」,
把兩個 date 分別印出來,在 GPE 的 Development Mode 中,
有時候會得到這樣的結果:
Sat Feb 11 12:00:00 CST 2012
Sat Feb 11 20:00:00 CST 2012
整整差了八小時...... 是的,是時區的問題。
如果 server 端在 reset 之前先把 date 印出來,
會得到「Sat Feb 11 04:00:00 UTC 2012」。
server 用 UTC 時區,這很合情合理,
實際 deploy 上 AppEngine 也是同樣的結果,
完全就是自己不應該硬要用 deprecated 的東西。
但那「有時候會正確、有時候會失敗」的靈異事件又是怎樣?
事實的真相是:
在一開始啟動 Development Mode 的 server 時,
server 的時區是 UTC(所以會失敗);
但是在 reload web server 之後,
server 的時區就會變成本地時區(所以會成功)。
這大概是最近發現第三個 GPE 的不思議之謎
(第一個是「更改 gwt.xml 需 refresh 兩次才見效」、
第二個是「build project 進度會卡住,關掉網路就沒事」)
好了,就讓系統一個日期各自表述,
server 改用 Calendar 來設定日期,目前看起來運作正常...... [抖]
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT+800"));
c.setTime(new Date((date.getTime()/1000)*1000));
c.set(Calendar.HOUR_OF_DAY, 12);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
return c.getTime();
以下是延伸閱讀時間 XD:
→在 objectify-appengine 的 Google Group,Jeff Schnitzer 提到
用 java.sql.Date。雖然說 Objectify 2.2.2 版就可以處理 java.sql.Date
(GAE 只能儲存 java.util.Date)、GWT 也能使用 java.sql.Date,
不過不知道是我誤會意思還是?
實測的結果還是得先 reset 過才能符合需求——
而且 java.sql.Date 基本上不能設定時間...
→tkcn 提供的 reference(1、2)提到
可以用「Joda-Time」這個 library 來處理、以及一些其他資訊。
但是目前安逸於現在這個解法...... [毆飛]
→原始 G+ 討論串
結語:這是一篇看起來好像很複雜,實際上根本就是技術太弱才會搞出來的飛機......
--
錢鍾書: 說出來的話
http://www.psmonkey.org
比不上不說出來的話
Java 版 cookcomic 版
只影射著說不出來的話
and more......
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 114.25.29.97