Switch Timezone for calculation

浪尽此生 提交于 2019-12-23 13:53:32

问题


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.

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

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.

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
}

Edit: 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) {

            }
        }

    }

Beeing able to use different defaults on different threads would help, also.

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 is "final" ... :-(

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 + ")";
        }
    }

回答1:


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.



来源:https://stackoverflow.com/questions/19834468/switch-timezone-for-calculation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!