網(wǎng)上有很多關(guān)于pos機時(shí)間不對,改變JVM默認時(shí)區是否影響log4j打印日志中的日期時(shí)間的知識,也有很多人為大家解答關(guān)于pos機時(shí)間不對的問(wèn)題,今天pos機之家(m.xjcwpx.cn)為大家整理了關(guān)于這方面的知識,讓我們一起來(lái)看下吧!
本文目錄一覽:
pos機時(shí)間不對
引言在【JVM & MySQL時(shí)區配置問(wèn)題-兩行代碼讓我們一幫子人熬了一個(gè)通宵】描述了由于代碼BUG導致存儲到數據庫的時(shí)間比正常時(shí)間少八小時(shí)的案例。當時(shí)分析的時(shí)候發(fā)現log4j打印的日志文件中日期時(shí)間都是正確的,下面對這個(gè)問(wèn)題進(jìn)行下驗證和分析。
測試環(huán)境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默認時(shí)區:東八區 LOGGER.info("Hello World!"); // 模擬應用問(wèn)題場(chǎng)景:改變JVM默認時(shí)區 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>分析過(guò)程FixedDateFormat
一路跟蹤代碼,最終格式化日期時(shí)間的類(lèi)是: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(); // 默認時(shí)區為東八區 FixedDateFormat fixedDateFormat = FixedDateFormat.createIfSupported(null); String str = fixedDateFormat.format(time); System.out.println(str); // 改變默認時(shí)區為零時(shí)區 TimeZone.setDefault(TimeZone.getTimeZone("GMT")); fixedDateFormat = FixedDateFormat.createIfSupported(null); str = fixedDateFormat.format(time); System.out.println(str); }}初始化
創(chuàng )建FixedDateFormat實(shí)例
FixedDateFormat在初始化的時(shí)候配置了時(shí)區信息。
FixedFormat枚舉類(lèi)型,定義了日期時(shí)間的各種樣式。下面以FixedFormat.ISO8601為例解釋下各個(gè)字段的含義:
ISO8601("yyyy-MM-dd'T'HH:mm:ss,SSS", "yyyy-MM-dd'T'", 2, ':', 1, ',', 1, 3, null)
字段
字段示例
說(shuō)明
pattern
yyyy-MM-dd’T’HH:mm:ss,SSS
日期時(shí)間格式
datePattern
yyyy-MM-dd’T’
日期格式
escapeCount
2
pattern中T兩邊單引號的個(gè)數
timeSeparator
:
小時(shí)與分鐘、分鐘與秒之間的分隔符
timeSepLength
1
timeSeparator字符長(cháng)度
millisSeparator
,
秒與毫秒之間的分隔符
millisSepLength
1
millisSeparator字符長(cháng)度
secondFractionDigits
3
millisSeparator后面時(shí)間字符的長(cháng)度
timeZoneFormat
null,其他示例:+08、+0800、+08:00
日期時(shí)間格式中是否顯示時(shí)區信息,類(lèi)型為FixedTimeZoneFormat,三種樣式:HH、HHMM、HHCMM
format格式化日期流程
1.初始化char數組// double size for locales with lengthy DateFormatSymbolsfinal char[] result = new char[length << 1];
char數組用于存放格式化后的pattern數據。
2.計算從當天午夜開(kāi)始的毫秒數midnightToday:當天午夜時(shí)間戳,默認值為0;midnightTomorrow:明天午夜時(shí)間戳,默認值為0;這里是個(gè)緩存的邏輯:如果待格式化的時(shí)間戳在midnightToday和midnightTomorrow之間,則直接返回:【待格式化時(shí)間戳】減去【midnightToday】;否則執行下面計算并緩存相應的值:
2.2.1格式化日期并緩存對于一個(gè)時(shí)間戳來(lái)說(shuō)從零點(diǎn)到24點(diǎn)之間,日期部分是不變的,所以解析并緩存起來(lái)。
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計算當前午夜時(shí)間戳
midnightToday = calcMidnightMillis(now, 0);
計算午夜時(shí)間戳
2.2.3計算明天午夜時(shí)間戳與2.2.2不同的是addDays是1。
midnightTomorrow = calcMidnightMillis(now, 1);2.3時(shí)間戳【減】當前午夜時(shí)間戳
return currentTime - midnightToday;3.將緩存的日期寫(xiě)入字符數組
private void writeDate(final char[] buffer, final int startPos) { if (cachedDate != null) { System.arraycopy(cachedDate, 0, buffer, startPos, dateLength); }}4.將【午夜開(kāi)始的毫秒數】轉換為時(shí)、分、秒… …
計算時(shí)分秒及毫秒
小結FixedDateFormat在初始化的時(shí)候對時(shí)區進(jìn)行了配置,當系統默認時(shí)區變化的時(shí)候,并不會(huì )影響到FixedDateFormat中的時(shí)區配置。
Benchmark在日常開(kāi)發(fā)中,少不了日期時(shí)間格式化,通常的使用方式:
SimpleDateFormat,非線(xiàn)程安全DateTimeFormatter,線(xiàn)程安全log4j中FixedDateFormat、FastDateFormat不同格式化類(lèi)的性能測試
一起討論假設現在有一套系統部署在東八區,由于業(yè)務(wù)需求,需要在零時(shí)區也部署一套,涉及到時(shí)區方面如何考慮?
國際化
以上就是關(guān)于pos機時(shí)間不對,改變JVM默認時(shí)區是否影響log4j打印日志中的日期時(shí)間的知識,后面我們會(huì )繼續為大家整理關(guān)于pos機時(shí)間不對的知識,希望能夠幫助到大家!
