我们的应用程序将所有日期存储为 UTC 时区。然而,我们的主要业务部门位于“欧洲/柏林”时区(+2、+1,具体取决于夏令时)。因此,当我们确定某个时间跨度应等于哪个“月”时,我们希望使用该时区。
IE。开始时给出的时间段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
to Friday, 30 November 2013, 00:00:00
服务器本身以 UTC 运行,因此我们必须在计算周期名称时切换时区。我们在后端使用 Joda Datetime,我总是可以执行以下操作:
DateTime now = new DateTime();
now.withZone(DateTimeZone.forID("Europe/Berlin"));
然而,有很多计算正在进行,我想知道是否有更好的方法,在某个时区内进行所有计算?
如果它是一个独立的应用程序,可以使用类似的东西:
DateTimeZone old = DateTimeZone.getDefault();
DateTimeZone.setDefault(DateTimeZone.forID("Europe/Berlin"));
//do all work
DateTimeZone.setDefault(old);
然而,由于它是服务器环境,修改默认时区可能会导致其他线程上发生的其他计算出现错误结果。
所以,我想知道,java中是否有类似c#的using指令?除了错误的语法之外,我正在寻找这样的东西:
using(DateTimeZone.forID("Europe/Berlin")){
//do all work, where JUST all DateTime usings inside this using
//Statement are affected
}
编辑:一些小测试显示了问题:即使在 2 个线程上运行,两个线程中也会使用“默认”时区。因此,无论最后设置什么时区,都将用于两个线程。 (当然,这就是“默认”时区的用途。)
@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) {
}
}
}
能够在不同线程上使用不同的默认值也会有所帮助。
另一个想法是扩展 JodaDateTime 并使用其所有重载重写 to string() 方法:
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);
}
}
因此,目前在生成期间名称(年、夸脱、月、周……)时,我总是需要手动处理它
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 + ")";
}
}