使用openjdk的时区未设置,引发了线上系统的诡异问题
2022-07-14 本文已影响0人
天草二十六_简村人
一、使用openjdk作为docker 镜像
- 建议在环境变量中指定时区
apk add tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
apk del tzdata && \
- 也可以在java -jar命令行指定时区
java -jar -Duser.timezone=Asia/Shanghai app.jar
二、详解openjdk的获取时区
3.1、java程序中获取默认时间
import java.util.TimeZone;
public class Test {
public static void main(String[] args) {
System.out.println(TimeZone.getDefault());
}
}
>javac Test.java
>java Test
sun.util.calendar.ZoneInfo[id="GMT",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
如果是oracle jdk,打印的时区详情是:sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=29,lastRule=null]
3.2、openjdk的源码跟踪
类TimeZone
package java.util;
// defaultTimeZone 使用关键词volatile修饰
private static volatile TimeZone defaultTimeZone;
// 默认的时区就是GMT
static final String GMT_ID = "GMT";
public static TimeZone getDefault() {
return (TimeZone) getDefaultRef().clone();
}
static TimeZone getDefaultRef() {
TimeZone defaultZone = defaultTimeZone;
if (defaultZone == null) {
// Need to initialize the default time zone.
defaultZone = setDefaultZone();
assert defaultZone != null;
}
// Don't clone here.
return defaultZone;
}
jar命令行参数-Duser.timezone=GMT+8
private static synchronized TimeZone setDefaultZone() {
TimeZone tz;
// get the time zone ID from the system properties
String zoneID = AccessController.doPrivileged(
new GetPropertyAction("user.timezone"));
// if the time zone ID is not set (yet), perform the
// platform to Java time zone ID mapping.
if (zoneID == null || zoneID.isEmpty()) {
String javaHome = AccessController.doPrivileged(
new GetPropertyAction("java.home"));
try {
zoneID = getSystemTimeZoneID(javaHome);
if (zoneID == null) {
zoneID = GMT_ID;
}
} catch (NullPointerException e) {
zoneID = GMT_ID;
}
}
// Get the time zone for zoneID. But not fall back to
// "GMT" here.
tz = getTimeZone(zoneID, false);
if (tz == null) {
// If the given zone ID is unknown in Java, try to
// get the GMT-offset-based time zone ID,
// a.k.a. custom time zone ID (e.g., "GMT-08:00").
String gmtOffsetID = getSystemGMTOffsetID();
if (gmtOffsetID != null) {
zoneID = gmtOffsetID;
}
tz = getTimeZone(zoneID, true);
}
assert tz != null;
final String id = zoneID;
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
System.setProperty("user.timezone", id);
return null;
}
});
defaultTimeZone = tz;
return tz;
}
public static void setDefault(TimeZone zone)
{
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new PropertyPermission
("user.timezone", "write"));
}
defaultTimeZone = zone;
}
3.3、TimeZone.c类中,会读取系统的时区
/*
* Gets the platform defined TimeZone ID
*/
JNIEXPORT jstring JNICALL
Java_java_util_TimeZone_getSystemTimeZoneID(JNIEnv *env, jclass ign,
jstring java_home, jstring country)
{
const char *cname;
const char *java_home_dir;
char *javaTZ;
if (java_home == NULL)
return NULL;
java_home_dir = JNU_GetStringPlatformChars(env, java_home, 0);
if (java_home_dir == NULL)
return NULL;
if (country != NULL) {
cname = JNU_GetStringPlatformChars(env, country, 0);
/* ignore error cases for cname */
} else {
cname = NULL;
}
/*
* Invoke platform dependent mapping function
*/
javaTZ = findJavaTZ_md(java_home_dir, cname);
free((void *)java_home_dir);
if (cname != NULL) {
free((void *)cname);
}
if (javaTZ != NULL) {
jstring jstrJavaTZ = JNU_NewStringPlatform(env, javaTZ);
free((void *)javaTZ);
return jstrJavaTZ;
}
return NULL;
}
3.4、findJavaTZ_md(java_home_dir, cname);的不同操作系统实现
- unix操作系统
-
windows操作系统
solaris系统和windows系统.png