Java Date在tomcat运行的不同时区生成

Java Date generate in different timezone that tomcat is running

本问题已经有最佳答案,请猛点这里访问。

我有一个日期存储在mysql中没有时区,如2001-01-10 00:00:00。
我有tomcat在时区+10:00运行。
我需要生成一个Date(),该对象没有偏移量。

如果我这样做:

1
2
3
4
5
6
7
 Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
 cal.setTime( new Date(/*from 2001-01-10 00:00:00*/) );
 cal.set(Calendar.HOUR_OF_DAY, 0);
 cal.set(Calendar.MINUTE, 0);
 cal.set(Calendar.SECOND, 0);
 cal.set(Calendar.MILLISECOND, 0);
 Date newDate = cal.getTime();

结果Date对象仍然将zoneinfo和zoneoffset报告给服务器时区,而不是UTC。

我需要生成一个具有ZERO TIME的Date()对象,但是保留存储在mysql中的日期,与tomcat时区无关。
换句话说,我希望独立于服务器时区生成零小时/分钟/秒的日期。

1
2
3
The date generated shows 2001-01-01T00:00:00.000+1400
the time is zero but offset is +14:00.
I want to generate 2001-01-01T00:00:00.000+0000

mysql数据时间是DATETIME


Date对象不保留时区信息,将其想象为只具有long属性的类,该属性存储从1970年开始经过的毫秒数。

SimpleDateFormat类或其他库(如JODA)负责在将日期转换为字符串时跟踪时区。


好吧,我可以获得所需结果的唯一方法是调整Java Date,我得到Tomcat的当前偏移量并从Date添加/删除他,follow函数使得rest返回的日期总是一样的,独立于tomcat时区。我使用JODA DateTime。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    public Date adjustDateTimeZoneToUTC( Date date )
{
    Date utcDate = null;
    if( date != null )
    {
        int curOffset = TimeZone.getDefault().getRawOffset();

        DateTime dt = new DateTime(date).withZoneRetainFields(DateTimeZone.UTC);
        // Se o offset for NEGATIVO(-12:00), deve-se somar esse tempo
        // Se o offset for POSITIVO(+12:00), deve-se subtrair esse tempo
        if( curOffset >= 0 ) {
            dt.minusMillis(curOffset);
        } else {
            curOffset *= -1;
            dt.plusMillis(curOffset);
        }
        utcDate = dt.toDate();
    }
    return utcDate;
}

在客户端,使用角度datepicker或其他javascript日历,你需要在javascript上做同样的方式,因为你的日期可以在不同的时区保持一致。像样品一样:

1
2
3
4
5
6
7
8
9
10
$dateParser.timezoneOffsetAdjust = function (date, timezone, undo) {
if (!date) {
    return null;
}
// Right now, only 'UTC' is supported.
if (timezone && timezone === 'UTC') {
    date = new Date(date.getTime());
    date.setMinutes(date.getMinutes() + (undo ? -1 : 1) * date.getTimezoneOffset());
}
return date;

};


日期本身没有任何时区。它的toString()方法使用当前的默认时区来返回表示此日期的String,如本文所述。但是,您可以在格式化期间精确定位目标时区,以获得所需的结果:

1
2
3
4
5
6
7
8
9
10
11
12
// 2001-01-01T00:00:00.000+00:00
long timestamp = 978307200_000L;
Date newDate = new Date(timestamp);

SimpleDateFormat u = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
u.setTimeZone(TimeZone.getTimeZone("UTC"));

SimpleDateFormat k = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
k.setTimeZone(TimeZone.getTimeZone("Pacific/Kiritimati"));

assertEquals("2001-01-01T00:00:00.000+0000", u.format(newDate));
assertEquals("2001-01-01T14:00:00.000+1400", k.format(newDate));