切换时区进行计算 [英] Switch Timezone for calculation
问题描述
我们的应用程序将所有日期存储在UTC时区中。但是,我们的主要业务部门位于欧洲/柏林时区(+ 2,+ 1,具体取决于夏令时)。因此,当我们确定某个时间跨度应等于月时,我们要使用那个时区。
Our application is storing all dates in UTC Timezone. Our Major-Business Unit however is in "Europe/Berlin" Timezone (+2, +1 depending on daylight saving). Therefore, when we determine what "month" a certain Timespan should equal, we want to use THAT Timezone.
即开始时间为 2013年10月31日,星期四23:00:0 UTC
,结束日期为,2013年11月29日,星期五,23:00:00 UTC
应该在全球范围内被称为 Nov 13
,至于我们的主要业务部门,《泰晤士报》将是 11月1日,星期五2013,00:00:00
到 2013年11月30日,星期五,00:00:00
I.e. The period given by the start Thursday, 31 October 2013, 23:00:0 UTC
and end Friday, 29 November 2013, 23:00:00 UTC
should bee globaly known as Nov 13
, as for our Major Business Unit, the Times would be Friday, 1 November 2013, 00:00:00
to Friday, 30 November 2013, 00:00:00
服务器本身以UTC运行,因此在计算期间名称时,我们必须切换时区。我们在后端使用Joda Datetime,我总是可以做类似的事情:
The Server itself is running in UTC, so we have to switch the timezone, while calculating periodnames. We are using Joda Datetime on the backend, and I always can do something like:
DateTime now = new DateTime();
now.withZone(DateTimeZone.forID("Europe/Berlin"));
然而,正在进行大量计算,我想知道是否有更好的方法
However there are a lot of calculations going on, and i wonder if there is a better way, to do ALL calculations within a certain timezone?
如果它是一个独立的应用程序,则可以使用类似的东西:
If it would be a stand alone application, one could use something like that:
DateTimeZone old = DateTimeZone.getDefault();
DateTimeZone.setDefault(DateTimeZone.forID("Europe/Berlin"));
//do all work
DateTimeZone.setDefault(old);
但是,由于它是服务器环境,因此修改默认时区可能会导致其他计算结果错误在其他线程上。
However since it is a server environment, modifying the default Timezone may lead to wrong results on other calculations happening on other threads.
所以,我想知道在Java中是否没有像c#using指令这样的东西?除了错误的语法外,我还在寻找类似的东西:
so, I wonder, if there is nothing like the c# using directive in java? Beside the wrong syntax i'm looking for something like this:
using(DateTimeZone.forID("Europe/Berlin")){
//do all work, where JUST all DateTime usings inside this using
//Statement are affected
}
编辑:一些小的测试显示了问题:即使在2个线程上运行时,两个线程都使用默认 TimeZone。因此,无论设置了哪个时区,LAST都将用于两个线程。 (当然,这就是默认时区的含义。)
Some Little Test shows the problem: Even when running on 2 Threads, the "Default" TimeZone is used in both threads. So, whatever timezone is set LAST will be used for both threads. (Of course that's what "default" Timezone is for.)
@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) {
}
}
}
能够在不同线程上使用不同默认值的Bee也将有所帮助。
Beeing able to use different defaults on different threads would help, also.
另一种想法是扩展JodaDateTime和用其所有重载覆盖to string()方法:
Another thought was to extend the JodaDateTime and override the to string() method with all of its overloads:
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);
}
}
- DateTime是最终 ...:-(
因此,就目前而言,在生成期间名称(任一年份, ,quartals,months,weeks等)。
So, for the moment i always need to handle it manually, when generating period names (either years, quartals, months, weeks, ...)
public String getMonthPeriodName() {
DateTime firstOfMonth = this.getPeriodStart().withZone(DateTimeZone.forID("Europe/Berlin")).dayOfMonth().withMinimumValue().millisOfDay().withMinimumValue();
DateTime lastOfMonth = this.getPeriodEnd().withZone(DateTimeZone.forID("Europe/Berlin")).dayOfMonth().withMaximumValue().millisOfDay().withMaximumValue();
if (firstOfMonth.isEqual(getPeriodStart()) && lastOfMonth.isEqual(getPeriodEnd())) {
// full month.
return firstOfMonth.withZone(DateTimeZone.forID("Europe/Berlin")).toString("MMM yyyy", Locale.US);
} else {
// just partial month.
String Basename = firstOfMonth.withZone(DateTimeZone.forID("Europe/Berlin")).toString("MMM yyyy", Locale.US);
String f = getPeriodStart().withZone(DateTimeZone.forID("Europe/Berlin")).dayOfMonth().getAsShortText();
String t = getPeriodEnd().withZone(DateTimeZone.forID("Europe/Berlin")).dayOfMonth().getAsShortText();
return Basename + " (" + f + " to " + t + ")";
}
}
推荐答案
I可能不会考虑设置默认值,因为那样的话,您会松散代码中的详细信息,以帮助您了解实际情况。
I would probably not look to setting defaults, because then you loose any verbosity in your code that would help you know what was really going on.
这是一个非常简单的建议,但是也许您应该只使用局部变量。
This is a very simple recommendation, but perhaps you should just use a local variable.
...
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 ...
看着您的代码,我发现许多冗余之处其他一些简单的局部变量甚至可以更好地进行清理。
Looking at your code, I see many redundancies where some other simple local variables would clean things up even better.
这篇关于切换时区进行计算的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!