切换时区进行计算

时间:2013-11-07 11:13:53

标签: java datetime timezone jodatime

我们的应用程序以UTC时区存储所有日期。然而,我们的主要业务部门位于“欧洲/柏林”时区(+ 2,+ 1取决于夏令时)。因此,当我们确定某个Timespan应该等于什么“月”时,我们想要使用THAT Timezone。

即。开始Thursday, 31 October 2013, 23:00:0 UTC和结束Friday, 29 November 2013, 23:00:00 UTC给出的时间应该全球称为Nov 13,对于我们的主要业务部门,时间将是Friday, 1 November 2013, 00:00:00到{{1} }

服务器本身以UTC格式运行,因此我们必须在计算句点名时切换时区。我们在后端使用Joda Datetime,我总是可以这样做:

Friday, 30 November 2013, 00:00:00

然而,有很多计算正在进行,我想知道是否有更好的方法,在某个时区内进行所有计算?

如果它是一个独立的应用程序,可以使用类似的东西:

DateTime now = new DateTime();
now.withZone(DateTimeZone.forID("Europe/Berlin"));

但是,由于它是服务器环境,修改默认时区可能会导致其他线程上发生的其他计算出错。

所以,我想知道,如果没有像java中的c#using指令那么?除了错误的语法,我正在寻找这样的东西:

DateTimeZone old = DateTimeZone.getDefault();
DateTimeZone.setDefault(DateTimeZone.forID("Europe/Berlin"));

//do all work

DateTimeZone.setDefault(old);

编辑:一些小测试显示问题:即使在2个线程上运行,也会在两个线程中使用“默认”TimeZone。因此,无论设置什么时区,LAST都将用于两个线程。 (当然这就是“默认”时区的用途。)

using(DateTimeZone.forID("Europe/Berlin")){
   //do all work, where JUST all DateTime usings inside this using
   //Statement are affected
}

Beeing能够在不同的线程上使用不同的默认值也会有所帮助。

另一个想法是扩展JodaDateTime并覆盖to string()方法及其所有重载:

@Test
    public final void testTimeZoneThreaded() {

        Thread EuropeThread = new Thread(new Runnable() {
            @Override
            public void run() {
                DateTimeZone.setDefault(DateTimeZone.forID("Europe/Berlin"));

                int i = 0;
                while (i++ < 10) {
                    DateTime now = new DateTime();
                    System.out.println("It is now " + now + " in TimeZone " + DateTimeZone.getDefault().toString());

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        });

        Thread UTCThread = new Thread(new Runnable() {
            @Override
            public void run() {
                DateTimeZone.setDefault(DateTimeZone.forID("UTC"));

                int i = 0;
                while (i++ < 10) {
                    DateTime now = new DateTime();
                    System.out.println("It is now " + now + " in TimeZone " + DateTimeZone.getDefault().toString());

                    try {
                        Thread.sleep(800);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        });

        EuropeThread.start();
        UTCThread.start();

        while (UTCThread.isAlive()) {
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {

            }
        }

    }
  • DateTime是“final”......: - (

所以,目前我总是需要手动处理它,生成句点名称(年,季,月,周......)

class MyDateTime extends DateTime{
  @Override
  public String toString(){
    return super().withZone(DateTimeZone.for("Europe/Berlin")).toString();
  }

  @Override
  public String toString(String format){
    return super().withZone(DateTimeZone.for("Europe/Berlin")).toString(format);
  }
}

1 个答案:

答案 0 :(得分:1)

我可能不会设置默认值,因为那样你就会在代码中丢失任何冗长的内容,以帮助你了解真正发生的事情。

这是一个非常简单的建议,但也许你应该只使用一个局部变量。

...
DateTimeZone tz = DateTimeZone.forID("Europe/Berlin");
DateTime firstOfMonth = this.getPeriodStart().withZone(tz).dayOfMonth().withMinimumValue().millisOfDay().withMinimumValue();
DateTime lastOfMonth = this.getPeriodEnd().withZone(tz).dayOfMonth().withMaximumValue().millisOfDay().withMaximumValue();
... etc ...

看看你的代码,我看到很多冗余,其他一些简单的局部变量会更好地清理它们。