从GAE服务器发送日期和时区到GWT客户端

6

大家好,我已经困扰了两周左右的问题,尝试了我能想到的一切方法并查看了很多答案,但似乎没有人能够解决我的问题。虽然这里有许多半成品答案,但都不能满足我的需求。请原谅我的问题非常长,但重要的是要正确提出问题,以便得到正确的答案!:D

如果您不考虑我的数据存储/服务器是Google App Engine(GAE),我的客户端是用Google Web Toolkit(GWT)编写的,并且所有内容都是用Java编写的,那么请不要再继续阅读。

最后,如果有人知道一个更好的地方来解决这样的问题,请告诉我,因为我总是遇到这样的问题,除了在这里找到解决方案,或花费数小时在谷歌上搜索其他人已经成功解决的问题外,我不知道如何找到解决方案。我也不理解如何从JavaDocs中找到任何东西-抱歉,但除非有人向我解释,否则我就无法理解。

我在服务器上存储了一个日期时间(显然是UTC时间),我还将每个业主的时区作为字符串存储在服务器上(例如"America/New_York")。通过在服务器上使用java.util.TimeZone.getAvailableIDs()获取此字符串,并要求业主选择其业务相关时区(如果他们没有选择任何内容,则默认为"Europe/London" - 不需要过多关注该部分)。我需要将任何日期时间传回客户端PC,忽略其PC上的本地时区,因为日期时间需要按照业主的时区显示。

例如,业主是伦敦的理发店,他们有一个在线预约日程表,任何潜在客户都可以查看。其中一位客户(也在伦敦)想要预约,看到了9月3日星期一上午9点BST的空闲时间并预订了它。

然后,这将作为UTC时间存储在数据存储中(实际上是0800,因为BST是UTC + 1),当然业主已经选择了"Europe/London"作为他们的时区。到目前为止一切都好。

现在,在将来的某个时候,客户在纽约参加商务会议,意识到下周要在伦敦理发,他们想将预约推迟一周,因此他们尝试查看预约(理发店的预约本),但他们不想以纽约时间4点的形式查看预约,而是想以英国时间9点的形式查看。

我的问题是,当客户在9月3日点击“查看预约”时,服务器可以发送一个UTC时间为0800和一个java.util.TimeZone ID字符串为"Europe/London"

但因为在客户端上,我只能使用

com.google.gwt.i18n.client.TimeZone

它不允许我使用这个函数。

TimeZone bizTimeZone=TimeZone.getTimeZone("Europe/London")
(which works for `java.util.TimeZone`)

由于它引起了错误

"The method getTimeZone(String) is undefined for the type TimeZone"

建议将其更改为

com.google.gwt.i18n.client.TimeZone.createTimeZone("Europe/London")

但是这个版本期望一个GWT com.google.gwt.i18n.client.TimeZoneConstants "对象"(示例在此消息末尾显示),而不是java.util.TimeZone.createTimeZone()将接受的简单字符串。

我可以通过使用以下方法创建它:

final TimeZoneConstants constTz = GWT.create(TimeZoneConstants.class);
final TimeZone timeZoneCali = TimeZone.createTimeZone(constTz.europeLondon());

但是当我从"Europe/London"开始,或者我不知道如何将此对象存储到App Engine数据库中以便以后检索时,我就不知道该怎么做了。

顺便说一句,在注释文本中,我还尝试使用了以下几行:

//Calendar tmad = new GregorianCalendar(TimeZone.getTimeZone("Europe/London"));
//Calendar cal = Calendar.getInstance(someTimeZone);
//DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//df1.setTimeZone(TimeZone.getTimeZone("Europe/London"));
//final TimeZone timeZoneClient = TimeZone.createTimeZone("Europe/London");
//dtf.format(date,timeZoneClient)

肯定有一种标准的方法可以解决这个问题,我真的不可能是第一个需要解决这个问题的人!

constTz.europeLondon()={"transitions": [19394, 60, 24770, 0, 28130, 60, 33506, 0, 36866, 60, 42242, 0, 45602, 60, 50978, 0, 54506, 60, 59714, 0, 63242, 60, 68450, 0, 71978, 60, 77354, 0, 80714, 60, 86090, 0, 89450, 60, 94826, 0, 98521, 60, 103561, 0, 107257, 60, 112297, 0, 115993, 60, 121033, 0, 124729, 60, 129937, 0, 133633, 60, 138673, 0, 142369, 60, 147409, 0, 151105, 60, 156145, 0, 159841, 60, 164881, 0, 168577, 60, 173785, 0, 177313, 60, 182521, 0, 186217, 60, 191257, 0, 194953, 60, 199993, 0, 203689, 60, 208729, 0, 212425, 60, 217465, 0, 221161, 60, 226201, 0, 230065, 60, 235105, 0, 238801, 60, 243841, 0, 247537, 60, 252577, 0, 256273, 60, 261481, 0, 265009, 60, 270217, 0, 273745, 60, 278953, 0, 282649, 60, 287689, 0, 291385, 60, 296425, 0, 300121, 60, 305329, 0, 308857, 60, 314065, 0, 317593, 60, 322801, 0, 326329, 60, 331537, 0, 335233, 60, 340273, 0, 343969, 60, 349009, 0, 352705, 60, 357913, 0, 361441, 60, 366649, 0, 370177, 60, 375385, 0, 379081, 60, 384121, 0, 387817, 60, 392857, 0, 396553, 60, 401593, 0, 405289, 60, 410497, 0, 414025, 60, 419233, 0, 422761, 60, 427969, 0, 431665, 60, 436705, 0, 440401, 60, 445441, 0, 449137, 60, 454345, 0, 457873, 60, 463081, 0, 466609, 60, 471817, 0, 475513, 60, 480553, 0, 484249, 60, 489289, 0, 492985, 60, 498025, 0, 501721, 60, 506929, 0, 510457, 60, 515665, 0, 519193, 60, 524401, 0, 528097, 60, 533137, 0, 536833, 60, 541873, 0, 545569, 60, 550777, 0, 554305, 60, 559513, 0, 563041, 60, 568249, 0, 571777, 60, 576985, 0, 580681, 60, 585721, 0, 589417, 60, 594457, 0], "names": ["GMT", "格林威治标准时间", "BST", "英国夏令时"], "id": "欧洲/伦

我可能漏掉了什么,但是你不能只是在服务器端使用java.util.TimeZone转换日期并将转换后的日期发送到客户端吗? - jrochette
没问题,我目前正在测试这个作为至少是临时解决方案!但仍然惊讶于没有更好的解决方案.... - johnvdenley
通过查看文档,我看到的另一个解决方案是使用 com.google.gwt.i18n.client 包中的 TimeZone 和 TimeZoneConstants。也许可以像 TimeZone.createTimeZone(timeZoneConstants.europeLondno()) 这样做? - jrochette
是的,我尝试过了,但我不知道如何确立我应该使用timeZoneConstants.europeLondon()而不是例如timeZoneConstants.americaLosAngeles()。但你之前的建议实际上起作用了(或者至少目前看起来是这样)。当然,还需要进行更多的测试! - johnvdenley
太好了。如果它能正常工作,我会将这些评论作为答案写入问题中。 - jrochette
显示剩余2条评论
3个回答

2

我在使用2.4版本时遇到了类似的问题。

我认为Riley Lark是正确的。

TimeZone.createTimeZone("Asia/Tokyo")在GWT 2.4中无法工作。

但是,我发现可以通过使用浏览器的默认设置来获取东京时区:

Date d = new Date();
TimeZone timezone = TimeZone.createTimeZone(d.getTimezoneOffset());

这是Riley Lark为您建议的实现方式,因为europeLondon的"std_offset"为0。

TimeZone(时区)timezone = TimeZone.createTimeZone(0);


偏移量会根据日期而改变。结果可能会得到错误的时区。 - Andrei Volgin

0

我曾经遇到过类似的问题,需要在客户端保留服务器时区。这有点具有挑战性,因为GWT不允许序列化来自最近Java库(例如java.time.ZonedDateTime)的对象。以下是我使用的技巧,可以创建一个具有所选时区的java.util.Date对象。

/*
    * This method forces a java.util.Date object to use a hard coded timezone.
    * The method first discards any local timezone from the Date object,
    * then adds a given timezone with the time. The purpose is to keep the 
    * original timestamp unchanged to avoid server-clinet timezone mismatch and use the 
    * server side timestamp. 
    */
    public java.util.Date updateZonedUtil(java.util.Date aDate)
    {
        // hard coding timezone with server timezone.
        String timezone = "America/Toronto";
        
        java.util.Date utilDate = new java.util.Date(aDate.getTime());
        SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
        String strDate = formatter.format(utilDate);        
   
        DateTimeFormatter localFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
        LocalDateTime localdt = LocalDateTime.parse(strDate, localFormatter);

        ZonedDateTime zdt = localdt.atZone(ZoneId.of(timezone));
                
        return Date.from(zdt.toInstant());
    }

0

你尝试过使用TimeZone.createTimeZone("Europe/London");这个方法吗?至少在较新版本的GWT中,该方法接受许多名称,显然是从CLDR和Olson时区数据库准备的。文档明确引用了您的用例:通过json传输时区。

请参见属性文件 - 它似乎包含所有标准时区的名称。

如果这对你不起作用,你可以传输时区偏移量(以分钟为单位),然后使用TimeZone.createTimeZone(offsetInMinutes)创建你的时区。


我尝试了TimeZone.createTimeZone("Europe/London");,但在我的当前版本GWT 2.2上无法工作,但我注意到v2.4可供升级,所以我可以尝试一下... - johnvdenley
是的,我不知道它在哪个版本中可用。也许值得一试~ - Riley Lark
我现在已经升级到GWT 2.4(最新版本),但是com.google.gwt.i18n.client.TimeZone.createTimeZone("Europe/London")这行代码仍然会导致我的GWT客户端崩溃,而且文档中写道: com.google.gwt.i18n.client.TimeZone.createTimeZone(String tzJSON)此工厂方法从包含所需时区的时区信息的JSON字符串创建时区实例。应用程序可以从TimeZoneConstants类获取这样的字符串。 - johnvdenley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接