一个进程里两处日志时间时区不一样的问题

    最近发现一个进程里打出来的日志里时区不一样,一个是UTC时间,2018-09-12 10:48:12.278,一个是北京时间2018-09-12 18:48:15.453。北京时间的是log4j输出的,UTC时间的是我们自己输出的,我们自己的时间字符串来源是大概如下两行代码:

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String dateString = dateFormat.format(new Date());

Log4j的时间是怎么来的呢?
以log4j1为例,有如下调用关系 
RollingFileAppender.subAppend()->WriterAppender.subAppend()-> PatternLayout.format() -> BridgePatternConverter.format() -> FormattingInfo.format() -> DatePatternConverter.format() -> CachedDateFormat.format()
那CachedDateFormat是怎么初始化的呢? DatePatternConverter 构造方法中可以看到

    if ((options != null) && (options.length > 1)) {
      TimeZone tz = TimeZone.getTimeZone((String) options[1]);
      simpleFormat.setTimeZone(tz);
    } else {
      simpleFormat = new DefaultZoneDateFormat(simpleFormat);
    }
    df = new CachedDateFormat(simpleFormat, maximumCacheValidity);


可以在log4j.xml中指定时区(比如"%d{ISO8601}{GMT-4}  %m%n"),如果不指定则是使用操作系统默认时区

log4j2中则是
RollingFileAppender.append() -> AbstractOutputStreamAppender.append() -> AbstractOutputStreamAppender.tryAppend() -> AbstractOutputStreamAppender.writeByteArrayToManager() -> AbstractStringLayout.toByteArray() -> PatternLayout.toSerializable() -> PatternLayout.PatternSerializer.toSerializable()->PatternLayout.PatternSerializer.toSerializable() -> PatternFormatter.format() —> DatePatternConverter.format()—> DatePatternConverter.formatWithoutAllocation()
在DatePatternConverter 类的 createNonFixedFormatter 可以看到

        TimeZone tz = null;
        if (options.length > 1 && options[1] != null) {
            tz = TimeZone.getTimeZone(options[1]);
        }

        try {
            final FastDateFormat tempFormat = FastDateFormat.getInstance(pattern, tz);
            return new PatternFormatter(tempFormat);

在不设置tz的情况下 timeZone = TimeZone.getDefault();
FormatCache 来cache每种类型;
不论log4j1还是log4j2,可以确定如下几点:
1.如果不配置时区,都是使用默认时区
2.时区初始化好了就不会变化
3.一个Appender对象一种格式化对象(log4j2是FastDateFormat对象;log4j1是DefaultZoneDateFormat)

 

回到问题,我们自己的和logj对时间的时区处理都是基于TimeZone.getDefault()来的,为什么会一个是UTC一个是CST呢?
后来定位到是因为我们自己自己懒加载的bean里有静态块
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
那么问题就清楚了,log4j的LOGGER和Appender对象初始化时先读取了操作系统的CST时间,然后对象一直没变;然后我们代码修改了时区,导致我们代码打出来的时间为UTC。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值