遊客:  註冊 | 登錄 | 幫助





標題: [分享] Java TimeZone
mickeyGoUp     Rank: 7Rank: 7Rank: 7
版主
性別 男
UID 5

精華 0
帖子 35511
積分 5235   詳情

閱讀權限 150
註冊 2006-3-24
來自 美國滴滴尼
狀態 離線

 
 
 
 
發表於 2008-4-14 08:35 PM  資料  個人空間  短訊  加為好友 
Java TimeZone

Problem: The web server is in New York.  The users can be anywhere in the country.  The users get to select the current location that they are working for (not necessariliy be their current physical location).  For example, they can physically be in Texas, but they want to select California as their current location.  And the system must display current California time to them.

I wrote a method to calculate the local datetime based on a given GMT offset.  Since the users will select their current location, we know the GMT offset.  For example, if they selected California, we know the GMT offset is -8.  The codes are as follow:

        private void setCurrentGmtDatetime(String idfGmtOffsetStr) {
                int idfGmtOffset = 0;
                long newDatetimeInMillis = new Date().getTime();
                long gmtDatetimeInMillis = (new Date().getTime()) -
                                                     (TimeZone.getDefault().getOffset(new Date().getTime()));
                Date newDatetime = null;
               
                try {
                        idfGmtOffset = Integer.parseInt(idfGmtOffsetStr);
                        newDatetimeInMillis = gmtDatetimeInMillis + (idfGmtOffset * 3600000);
                        newDatetime = new Date(newDatetimeInMillis);
                       
                } catch (NumberFormatException nfex) {
                        nfex.printStackTrace();
                        System.err.println("Invalid offset string.  Use Current Date");
                        newDatetime = new Date();
                }

                // a bunch of setters here...
        }

Everything works until Daylight Saving Time came into the picture.  Therefore, I modified the line to adjust the time according to the Daylight Saving Time:

        long gmtDatetimeInMillis = (new Date().getTime()) -
                                ((TimeZone.getDefault().getOffset(new Date().getTime())) -
                                   TimeZone.getDefault().getDSTSavings());

Do you guys think this is good enough?  I know the answer already, but I think this is an interesting topic to talk about.  So, I think of sharing this with you all.  



最後編輯: mickeyGoUp : 2008-4-14 08:36 PM
頂部

ah_cho     Rank: 5Rank: 5Rank: 5
風中藍 (天藍看更)
性別 女
UID 5699

精華 1
帖子 19196
積分 6063   詳情

閱讀權限 60
註冊 2006-8-11
來自 住0係楓葉國既日本漢奸 ... ... ...
狀態 離線

 
 
 
 
發表於 2008-4-15 02:49 AM  資料  個人空間  主頁 短訊  加為好友 
外星文?我幫你唔到呀
支持下你仲可以既!
加油!

mickeyGoUp :
多謝捧場!!





頂部



  小神     Rank: 4Rank: 4
水中藍
性別 保密
UID 11831

精華 0
帖子 2634
積分 1386   詳情

閱讀權限 50
註冊 2006-9-12
來自 天堂
狀態 離線

 
 
 
 
發表於 2008-4-15 08:02 AM  資料  個人空間  短訊  加為好友 
用Calendar 都有得set zone_offset and dst_offset...
不過我未用過..
但係會唔會簡單D ar?

mickeyGoUp :
Calendar 果個唔知點寫呢? 如果可以 get 到個 GMT offset,應該都可以計返個 GMT Time 之後再計個 user 既 local time。

頂部

1022292057     Rank: 4Rank: 4
水中藍
性別 男
UID 17104

精華 0
帖子 165
積分 798   詳情

閱讀權限 50
註冊 2006-12-9
來自 Canada
狀態 離線

 
 
 
 
發表於 2008-4-15 01:10 PM  資料  個人空間  主頁 短訊  加為好友 
The location the user chose can have daylight saving too, i think u still need to code that so u use (idfGmtOffset + 1) if daylight saving unless u assumed that idfGmtOffsetStr is passed in after daylight saving is already adjusted
and i believe TimeZone.getDefault().getOffset(new Date().getTime()) already included the daylight saving as getTime() gets the time that is DST adjusted, so ur modification to include daylight saving is actually incorrect

In ur code, there're some unnecessary memory usage, and look kinda confusing too
for example,  
repeated "new Date().getTime() " should be replaced with newDatetimeInMillis, since "new" will allocate memory space, which in this case is not neccessary, and getTime() takes a big amount of time and memory when executing in terms of small program, should avoid calling more than once
in ur function, u converted to GMT first, but that can basically be eliminated, there's really no point of doing that when u can just differ up the offset on both location to get what u want
u have 2 variables related to GMT, which wasted memory and size again
dealing with those millisec is confusing too
also the 3600000 in ur code is call "magic number", should avoid that


I would do it this way instead (to optimize memory, speed and organization):

// pass in TimeZone ID instead of idfGmtOffsetStr, it's more relevant
private void setCurrentGmtDatetime(String LocationID) {

     TimeZone local = TimeZone.getDefault();
     TimeZone result = TimeZone.getTimeZone(locationID);

     // total offset = result offset with DST adjusted minus local offset with DST adjusted  
     int offset = ( (result.getRawOffset() + result.getDSTSavings()) - (local.getRawOffset() + local.getDSTSavings()) );

     // do conversion
     // don't even have to give variable to local time, just inline here to avioid extra memory usage
     Date newDatetime = new Date(new Date().getTime() + offset);
}


what do u think?



最後編輯: 1022292057 : 2008-4-15 03:15 PM
頂部

mickeyGoUp     Rank: 7Rank: 7Rank: 7
版主
性別 男
UID 5

精華 0
帖子 35511
積分 5235   詳情

閱讀權限 150
註冊 2006-3-24
來自 美國滴滴尼
狀態 離線

 
 
 
 
發表於 2008-4-15 08:00 PM  資料  個人空間  短訊  加為好友 
回復 #4 1022292057 的帖子

Haha.. good job numbie!  My codes have not yet been optimized, I just threw everything together.  And as soon as I discovered what I wanted to share with you guys, I posted it.  So there are definitely rooms for improvement.   

Now, all we have is a "GMT offset" string for the result location.  The locationID you have in there is in "EST" or "GMT-5:00" format?  That means I'll have to do some formatting beforehand, correct?

頂部

mickeyGoUp     Rank: 7Rank: 7Rank: 7
版主
性別 男
UID 5

精華 0
帖子 35511
積分 5235   詳情

閱讀權限 150
註冊 2006-3-24
來自 美國滴滴尼
狀態 離線

 
 
 
 
發表於 2008-4-16 12:09 AM  資料  個人空間  短訊  加為好友 
回復 #4 1022292057 的帖子

For some reason, when I used "PST" as the locationID, the getDSTSavings() returns the right value (3600000); but when I used "GMT-8" or "GMT-8:00", it retuns 0.  But the getRawOffset() works properly.

Any thoughts?

頂部

1022292057     Rank: 4Rank: 4
水中藍
性別 男
UID 17104

精華 0
帖子 165
積分 798   詳情

閱讀權限 50
註冊 2006-12-9
來自 Canada
狀態 離線

 
 
 
 
發表於 2008-4-16 12:19 AM  資料  個人空間  主頁 短訊  加為好友 
回復 #5 mickeyGoUp 的帖子

you see, the problem here is that you can't just have "GMT offset" string for the result location
becoz two different location with same GMT offset may have different daylight saving time schedule
that's why you need locationID instead, unless what u ar passing in is not "GMT offset" but "an offset with DST adjusted"

locationID can be "GMT-5:00", but these are call custom ID, which has the same behaviour as the stuff i mention above, daylight saving schedule cannot be determined with these
you can call static String[] TimeZone.getAvailableIDs() to get all supporting IDs or static String[] TimeZone.getAvailableIDs(int rawOffset) to get all locationID with specific GMT offset
For example, "Hongkong" is one locationID, so TimeZone.getTimeZone("Hongkong") will give u the TimeZone of HK and be able to determine its daylight saving schedule

when user choose TimeZone, u should give all the unique locationID for them to choose, not just 25 choices from GMT-12 to GMT+12
if u open up ur Date&Time properties -> TimeZone in windows, u can see that there ar many different TimeZones for the same GMT offset
so by just providing a "GMT offset" is not enough, aliasing what user chose to a locationID is easy too as locationID is just really the location name



最後編輯: 1022292057 : 2008-4-16 12:21 AM
頂部

mickeyGoUp     Rank: 7Rank: 7Rank: 7
版主
性別 男
UID 5

精華 0
帖子 35511
積分 5235   詳情

閱讀權限 150
註冊 2006-3-24
來自 美國滴滴尼
狀態 離線

 
 
 
 
發表於 2008-4-16 01:52 AM  資料  個人空間  短訊  加為好友 
回復 #7 1022292057 的帖子

I like your suggestion.  Unfortunately, we do not have the correct TimeZone ID at this point.  I am developing on an existing application and currently when users selected their location, there is only GMT Offset provided.  Not sure how much control I will have in terms of adding the ID's to the location table in the database.  But I'll request for that.  

Now, let's assume that I have all the ID's, there is another challenge, and this is what I originally wanted to point out in my first post:

If I set the locationID to 'Asia/Hong_Kong', the "total offset" I got now is +13 hours.  My current time zone is EST, and it is supposed to be +12 hours behind HK.  See what is missing?  

頂部

1022292057     Rank: 4Rank: 4
水中藍
性別 男
UID 17104

精華 0
帖子 165
積分 798   詳情

閱讀權限 50
註冊 2006-12-9
來自 Canada
狀態 離線

 
 
 
 
發表於 2008-4-16 05:07 AM  資料  個人空間  主頁 短訊  加為好友 
回復 #8 mickeyGoUp 的帖子

u can never get correct timing if u only have GMT offset

y would u have +13 for total offset
total offset = (HKGMToffset + HKDST) - (ESTGMToffset + ESTDST)
total offset = (8 + 0) - (-5 + 1) = 8 + 4 = +12

I am EST too, i just tested my code, it gives me +12 for HK



最後編輯: 1022292057 : 2008-4-16 05:09 AM
頂部

mickeyGoUp     Rank: 7Rank: 7Rank: 7
版主
性別 男
UID 5

精華 0
帖子 35511
積分 5235   詳情

閱讀權限 150
註冊 2006-3-24
來自 美國滴滴尼
狀態 離線

 
 
 
 
發表於 2008-4-16 06:13 AM  資料  個人空間  短訊  加為好友 
回復 #9 1022292057 的帖子

Ooops!!  My bad!  I had made a mistake:

QUOTE:
int offset = ( (result.getRawOffset() + result.getDSTSavings()) - (local.getRawOffset() + result.getDSTSavings()) );

I corrected it, and I got +12 hours for the total offset.  Thanks!

Now let me changed my question.  It's just the other way around, but the same question:

If I set my server date-time to Feb 15, 2008, and I ran the same function again, I still got a total offset of +12 hours, but shouldn't it be +13 hours?

頂部

快速美言
           


當前時區 GMT+8, 現在時間是 2024-4-20 03:00 PM

    Powered by Discuz!  © 2001-2007 Comsenz Inc.   
Processed in 0.014536 second(s), 7 queries

清除 Cookies - 聯繫我們 - LIPS Corner 新天藍 - Archiver