看板 java 關於我們 聯絡資訊
有圖(?)有連結的網頁版: 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