Java日期格式化如何避免YYYY引發(fā)的時間異常
在編程中,日期格式化是一個常見的任務(wù)。使用不同的格式化選項可能會導(dǎo)致一些意外的結(jié)果。最近遇到一個問題,就是使用YYYY格式化選項會導(dǎo)致時間異常。
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
String time = "2023-12-31 23:59:59";
System.out.printf("yyyy-MM-dd HH:mm:ss: %s\n",sdf.format(sdf.parse(time)));
System.out.printf("YYYY-MM-dd HH:mm:ss: %s\n",sdf2.format(sdf2.parse(time)));
System.out.println("======================================");
String time2 = "2023-11-31 23:59:59"; //11月沒有31號
System.out.printf("yyyy-MM-dd HH:mm:ss: %s\n",sdf.format(sdf.parse(time2)));
System.out.printf("YYYY-MM-dd HH:mm:ss: %s\n",sdf2.format(sdf2.parse(time2)));
System.out.println("======================================");
String time3 = "2023-10-31 23:59:59";
System.out.printf("yyyy-MM-dd HH:mm:ss: %s\n",sdf.format(sdf.parse(time3)));
System.out.printf("YYYY-MM-dd HH:mm:ss: %s\n",sdf2.format(sdf2.parse(time3)));
}輸出結(jié)果
yyyy-MM-dd HH:mm:ss: 2023-12-31 23:59:59
YYYY-MM-dd HH:mm:ss: 2023-01-01 23:59:59
======================================
yyyy-MM-dd HH:mm:ss: 2023-12-01 23:59:59
YYYY-MM-dd HH:mm:ss: 2023-01-01 23:59:59
======================================
yyyy-MM-dd HH:mm:ss: 2023-10-31 23:59:59
YYYY-MM-dd HH:mm:ss: 2023-01-01 23:59:59
網(wǎng)上查閱說大寫的YYYY表示一個基于周的年份,它是根據(jù)周計算的年份,而不是基于日歷的年份。通常情況下,兩者的結(jié)果是相同的,但在跨年的第一周或最后一周可能會有差異。但這里發(fā)現(xiàn)無論怎么調(diào)整時間,YYYY-MM-dd HH:mm:ss格式化后一直是2023-01-01 23:59:59,不僅僅是在跨年的時候出現(xiàn)問題,具體原因尚不清楚
如何避免
定義通用的格式類,所有使用日期格式的地方都引用這個類,這個類中就定義好yyyy-MM-dd格式即可,這樣就不會出現(xiàn)有人手誤給大家埋雷了。
public class LocalDateUtils {
/**
* 顯示年月日時分秒,例如 2023-10-31 09:51:53.
*/
public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
/**
* 僅顯示年月日,例如 2023-10-31.
*/
public static final String DATE_PATTERN = "yyyy-MM-dd";
private static final String YEAR = "year";
private static final String MONTH = "month";
private static final String WEEK = "week";
private static final String DAY = "day";
/**
* 將日期轉(zhuǎn)換為字符串,格式為:yyyy-MM-dd HH:mm:ss
*/
public static String getLocalDateTimeStr(LocalDateTime localDateTime) {
return format(localDateTime, DATETIME_PATTERN);
}
/**
* 將日期轉(zhuǎn)換為字符串,格式為:yyyy-MM-dd
*/
public static String getLocalDateStr(LocalDateTime localDateTime) {
return format(localDateTime, DATE_PATTERN);
}
/**
* 將字符串轉(zhuǎn)換為日期,格式為:yyyy-MM-dd HH:mm:ss
*/
public static LocalDateTime parseLocalDateTime(String localDateTimeStr) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATETIME_PATTERN);
return LocalDateTime.parse(localDateTimeStr, dateTimeFormatter);
}
/**
* 將字符串轉(zhuǎn)換為日期,格式為:yyyy-MM-dd
*/
public static LocalDate parseLocalDate(String localDateStr) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_PATTERN);
return LocalDate.parse(localDateStr, dateTimeFormatter);
}
/**
* 將字符串轉(zhuǎn)日期成Long類型的時間戳
*/
public static Long convertLocalDateTimeToLong(String time) {
LocalDateTime parse = parse(time, DATETIME_PATTERN);
return LocalDateTime.from(parse).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
/**
* 將字符串轉(zhuǎn)日期成Long類型的時間戳
*/
public static Long convertLocalDateToLong(String time) {
LocalDateTime parse = parse(time, DATE_PATTERN);
return LocalDateTime.from(parse).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
public static LocalDateTime parse(String time, String pattern) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
return LocalDateTime.parse(time, dateTimeFormatter);
}
/**
* 將Long類型的時間戳轉(zhuǎn)換成String 類型的時間格式
*/
public static String getLocalDateTimeStr(Long time) {
return format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()), DATETIME_PATTERN);
}
/**
* 將Long類型的時間戳轉(zhuǎn)換成String 類型的時間格式,時間格式為:yyyy-MM-dd
*/
public static String getLocalDateStr(Long time) {
return format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()), DATE_PATTERN);
}
/**
* 獲取日期時間字符串
*/
public static String format(TemporalAccessor temporal, String pattern) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
return dateTimeFormatter.format(temporal);
}
/**
* 取本月第一天
*/
public static LocalDate firstDayOfThisMonth() {
LocalDate today = LocalDate.now();
return today.with(TemporalAdjusters.firstDayOfMonth());
}
/**
* 取本月第N天
*/
public static LocalDate dayOfThisMonth(int n) {
LocalDate today = LocalDate.now();
return today.withDayOfMonth(n);
}
/**
* 取本月最后一天
*/
public static LocalDate lastDayOfThisMonth() {
LocalDate today = LocalDate.now();
return today.with(TemporalAdjusters.lastDayOfMonth());
}
/**
* 獲取指定日期時間加上指定數(shù)量日期時間單位之后的日期時間.
*/
public static LocalDateTime plus(LocalDateTime localDateTime, int num, ChronoUnit chronoUnit) {
return localDateTime.plus(num, chronoUnit);
}
/**
* 獲取指定日期時間減去指定數(shù)量日期時間單位之后的日期時間.
*/
public static LocalDateTime minus(LocalDateTime localDateTime, int num, ChronoUnit chronoUnit) {
return localDateTime.minus(num, chronoUnit);
}
/**
* 根據(jù)ChronoUnit計算兩個日期時間之間相隔日期時間
*/
public static long getChronoUnitBetween(LocalDateTime start, LocalDateTime end, ChronoUnit chronoUnit) {
return Math.abs(start.until(end, chronoUnit));
}
/**
* 根據(jù)ChronoUnit計算兩個日期之間相隔年數(shù)或月數(shù)或天數(shù)
*/
public static long getChronoUnitBetween(LocalDate start, LocalDate end, ChronoUnit chronoUnit) {
return Math.abs(start.until(end, chronoUnit));
}
/**
* 切割日期。按照周期切割成小段日期段。例如: <br>
*
* @param startDate 開始日期(yyyy-MM-dd)
* @param endDate 結(jié)束日期(yyyy-MM-dd)
* @param period 周期(天,周,月,年)
* @return 切割之后的日期集合
* <li>startDate="2023-10-27",endDate="2023-10-31",period="day"</li>
* <li>結(jié)果為:[2023-10-27, 2023-10-28, 2023-10-29, 2023-10-03,2023-10-31]</li><br>
* <li>startDate="2023-10-27",endDate="2023-10-31",period="week"</li>
* <li>結(jié)果為:[2023-10-27,2023-10-31]</li><br>
* <li>startDate="2023-10-27",endDate="2023-10-31",period="month"</li>
* <li>結(jié)果為:[2023-10-27,2023-10-31]</li><br>
* <li>startDate="2023-10-27",endDate="2023-10-31",period="year"</li>
* <li>結(jié)果為:[2023-10-27,2023-10-31]</li><br>
*/
public static List<String> listDateStrs(String startDate, String endDate, String period) {
List<String> result = new ArrayList<>();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_PATTERN);
LocalDate end = LocalDate.parse(endDate, dateTimeFormatter);
LocalDate start = LocalDate.parse(startDate, dateTimeFormatter);
LocalDate tmp = start;
switch (period) {
case DAY:
while (start.isBefore(end) || start.isEqual(end)) {
result.add(start.toString());
start = start.plusDays(1);
}
break;
case WEEK:
while (tmp.isBefore(end) || tmp.isEqual(end)) {
if (tmp.plusDays(6).isAfter(end)) {
result.add(tmp.toString() + "," + end);
} else {
result.add(tmp.toString() + "," + tmp.plusDays(6));
}
tmp = tmp.plusDays(7);
}
break;
case MONTH:
while (tmp.isBefore(end) || tmp.isEqual(end)) {
LocalDate lastDayOfMonth = tmp.with(TemporalAdjusters.lastDayOfMonth());
if (lastDayOfMonth.isAfter(end)) {
result.add(tmp.toString() + "," + end);
} else {
result.add(tmp.toString() + "," + lastDayOfMonth);
}
tmp = lastDayOfMonth.plusDays(1);
}
break;
case YEAR:
while (tmp.isBefore(end) || tmp.isEqual(end)) {
LocalDate lastDayOfYear = tmp.with(TemporalAdjusters.lastDayOfYear());
if (lastDayOfYear.isAfter(end)) {
result.add(tmp.toString() + "," + end);
} else {
result.add(tmp.toString() + "," + lastDayOfYear);
}
tmp = lastDayOfYear.plusDays(1);
}
break;
default:
break;
}
return result;
}
}
以上就是Java日期格式化如何避免YYYY引發(fā)的時間異常的詳細內(nèi)容,更多關(guān)于Java日期格式化的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot使用TraceId日志鏈路追蹤的代碼實現(xiàn)
有時候一個業(yè)務(wù)調(diào)用鏈場景,很長,調(diào)了各種各樣的方法,看日志的時候,各個接口的日志穿插,確實讓人頭大,為了解決這個痛點,就使用了TraceId,根據(jù)TraceId關(guān)鍵字進入服務(wù)器查詢?nèi)罩局惺欠裼羞@個TraceId, 本文給大家介紹了SpringBoot使用TraceId日志鏈路追蹤的方法2025-07-07
淺談springMVC接收前端json數(shù)據(jù)的總結(jié)
下面小編就為大家分享一篇淺談springMVC接收前端json數(shù)據(jù)的總結(jié),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03
Java中的讀寫鎖ReentrantReadWriteLock源碼分析
這篇文章主要介紹了Java中的讀寫鎖ReentrantReadWriteLock源碼分析,ReentrantReadWriteLock 分為讀鎖和寫鎖兩個實例,讀鎖是共享鎖,可被多個線程同時使用,寫鎖是獨占鎖,持有寫鎖的線程可以繼續(xù)獲取讀鎖,反之不行,需要的朋友可以參考下2023-12-12
SpringBoot中實現(xiàn)訂單30分鐘自動取消的項目實踐
現(xiàn)在電子商務(wù)平臺上訂單創(chuàng)建成功,等待支付,一般會給30分鐘的時間,本文主要介紹了SpringBoot中實現(xiàn)訂單30分鐘自動取消的項目實踐,具有一定的參考價值,感興趣的可以了解一下2023-10-10
mybatis之調(diào)用帶輸出參數(shù)的存儲過程(Oracle)
這篇文章主要介紹了mybatis調(diào)用帶輸出參數(shù)的存儲過程(Oracle),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
Java實現(xiàn)將彩色PDF轉(zhuǎn)為灰度PDF的示例代碼
本文以Java代碼為例介紹如何實現(xiàn)將彩色PDF文件轉(zhuǎn)為灰度(黑白)的PDF文件,文中的示例代碼講解詳細,感興趣的小伙伴快跟隨小編一起學(xué)習(xí)一下吧2022-03-03

