私たちのアプリケーションは、すべての日付を UTC タイムゾーンで保存しています。ただし、当社の主要ビジネス ユニットは「ヨーロッパ/ベルリン」のタイムゾーン (夏時間に応じて +2、+1) にあります。したがって、特定の Timespan が等しい「月」を決定するときは、その 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
。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 つのスレッドで実行している場合でも、両方のスレッドで「デフォルト」の TimeZone が使用されます。したがって、タイムゾーンが LAST に設定されていても、両方のスレッドに使用されます。(もちろん、それが「デフォルトの」タイムゾーンの目的です。)
@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) {
}
}
}
異なるスレッドで異なるデフォルトを使用できることも役立ちます。
もう 1 つの考えは、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);
}
}
- DateTime は「最終」です ... :-(
したがって、今のところ、期間名 (年、四半期、月、週など) を生成するときは、常に手動で処理する必要があります。
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 + ")";
}
}