網上有很多關于pos機時間不對,改變JVM默認時區是否影響log4j打印日志中的日期時間的知識,也有很多人為大家解答關于pos機時間不對的問題,今天pos機之家(www.bangarufamily.com)為大家整理了關于這方面的知識,讓我們一起來看下吧!
本文目錄一覽:
1、pos機時間不對
pos機時間不對
引言在【JVM & MySQL時區配置問題-兩行代碼讓我們一幫子人熬了一個通宵】描述了由于代碼BUG導致存儲到數據庫的時間比正常時間少八小時的案例。當時分析的時候發現log4j打印的日志文件中日期時間都是正確的,下面對這個問題進行下驗證和分析。
測試環境Java versionjava version "1.8.0_341"Java(TM) SE Runtime Environment (build 1.8.0_341-b10)Java HotSpot(TM) Client VM (build 25.341-b10, mixed mode, sharing)pom
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.19.0</version></dependency><dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.19.0</version></dependency>測試代碼&配置
import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import java.util.TimeZone;public class Log4jTimezoneTest { private static Logger LOGGER = LogManager.getLogger(); public static void main(String[] args){ // JVM默認時區:東八區 LOGGER.info("Hello World!"); // 模擬應用問題場景:改變JVM默認時區 TimeZone.setDefault(TimeZone.getTimeZone("GMT")); LOGGER.info("Hello World!"); }}
<?xml version="1.0" encoding="UTF-8"?><Configuration> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <patternLayout pattern="%d [%t] %-5level %c:%M(%L) - %msg%n"/> </Console> </Appenders> <Loggers> <Root level="DEBUG"> <AppenderRef ref="Console"/> </Root> </Loggers></Configuration>分析過程FixedDateFormat
一路跟蹤代碼,最終格式化日期時間的類是:org.apache.logging.log4j.core.util.datetime.FixedDateFormat。
基本使用import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;import java.util.TimeZone;public class TimeZoneTest { public static void main(String[] args){ long time = System.currentTimeMillis(); // 默認時區為東八區 FixedDateFormat fixedDateFormat = FixedDateFormat.createIfSupported(null); String str = fixedDateFormat.format(time); System.out.println(str); // 改變默認時區為零時區 TimeZone.setDefault(TimeZone.getTimeZone("GMT")); fixedDateFormat = FixedDateFormat.createIfSupported(null); str = fixedDateFormat.format(time); System.out.println(str); }}初始化
創建FixedDateFormat實例
FixedDateFormat在初始化的時候配置了時區信息。
FixedFormat枚舉類型,定義了日期時間的各種樣式。下面以FixedFormat.ISO8601為例解釋下各個字段的含義:
ISO8601("yyyy-MM-dd'T'HH:mm:ss,SSS", "yyyy-MM-dd'T'", 2, ':', 1, ',', 1, 3, null)
字段
字段示例
說明
pattern
yyyy-MM-dd’T’HH:mm:ss,SSS
日期時間格式
datePattern
yyyy-MM-dd’T’
日期格式
escapeCount
2
pattern中T兩邊單引號的個數
timeSeparator
:
小時與分鐘、分鐘與秒之間的分隔符
timeSepLength
1
timeSeparator字符長度
millisSeparator
,
秒與毫秒之間的分隔符
millisSepLength
1
millisSeparator字符長度
secondFractionDigits
3
millisSeparator后面時間字符的長度
timeZoneFormat
null,其他示例:+08、+0800、+08:00
日期時間格式中是否顯示時區信息,類型為FixedTimeZoneFormat,三種樣式:HH、HHMM、HHCMM
format格式化日期流程
1.初始化char數組// double size for locales with lengthy DateFormatSymbolsfinal char[] result = new char[length << 1];
char數組用于存放格式化后的pattern數據。
2.計算從當天午夜開始的毫秒數midnightToday:當天午夜時間戳,默認值為0;midnightTomorrow:明天午夜時間戳,默認值為0;這里是個緩存的邏輯:如果待格式化的時間戳在midnightToday和midnightTomorrow之間,則直接返回:【待格式化時間戳】減去【midnightToday】;否則執行下面計算并緩存相應的值:
2.2.1格式化日期并緩存對于一個時間戳來說從零點到24點之間,日期部分是不變的,所以解析并緩存起來。
private void updateCachedDate(final long now) { if (fastDateFormat != null) { final StringBuilder result = fastDateFormat.format(now, new StringBuilder()); cachedDate = result.toString().toCharArray(); dateLength = result.length(); }}2.2.2計算當前午夜時間戳
midnightToday = calcMidnightMillis(now, 0);
計算午夜時間戳
2.2.3計算明天午夜時間戳與2.2.2不同的是addDays是1。
midnightTomorrow = calcMidnightMillis(now, 1);2.3時間戳【減】當前午夜時間戳
return currentTime - midnightToday;3.將緩存的日期寫入字符數組
private void writeDate(final char[] buffer, final int startPos) { if (cachedDate != null) { System.arraycopy(cachedDate, 0, buffer, startPos, dateLength); }}4.將【午夜開始的毫秒數】轉換為時、分、秒… …
計算時分秒及毫秒
小結FixedDateFormat在初始化的時候對時區進行了配置,當系統默認時區變化的時候,并不會影響到FixedDateFormat中的時區配置。
Benchmark在日常開發中,少不了日期時間格式化,通常的使用方式:
SimpleDateFormat,非線程安全DateTimeFormatter,線程安全log4j中FixedDateFormat、FastDateFormat不同格式化類的性能測試
一起討論假設現在有一套系統部署在東八區,由于業務需求,需要在零時區也部署一套,涉及到時區方面如何考慮?
國際化
以上就是關于pos機時間不對,改變JVM默認時區是否影響log4j打印日志中的日期時間的知識,后面我們會繼續為大家整理關于pos機時間不對的知識,希望能夠幫助到大家!
