Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม

การจัดรูปแบบวันที่ Master Java:SimpleDateFormat &DateFormat อธิบาย

บทนำ

02 รูปแบบและแยกวิเคราะห์ 15 ค่าโดยใช้สตริงรูปแบบที่กำหนดเองและ 25 จัดเตรียม API ฐานนามธรรมสำหรับการจัดรูปแบบวันที่และเวลาแบบรับรู้สถานที่ ใช้ API เหล่านี้เมื่อคุณรักษาโค้ด Java เดิมที่ยังคงขึ้นอยู่กับ 39; สำหรับรหัสใหม่ แนะนำให้ใช้ 43 จาก API วันที่/เวลา Java 8+ เนื่องจาก 58 ไม่ปลอดภัยต่อเธรด

บทช่วยสอนนี้แสดงวิธีใช้ 69 และ 78 สำหรับการจัดรูปแบบ การแยกวิเคราะห์ การแปลงเขตเวลา และเอาต์พุตเฉพาะสถานที่ นอกจากนี้ยังครอบคลุมถึงการตรวจสอบอย่างเข้มงวดด้วย 81 วิธีแก้ปัญหาความปลอดภัยของเธรด และเส้นทางการโยกย้ายที่ใช้งานได้จริงไปยัง 91 .

ประเด็นสำคัญ

  • 104 คือ API การจัดรูปแบบนามธรรม และ 118 คือการดำเนินการอย่างเป็นรูปธรรมสำหรับการจัดรูปแบบและการแยกวิเคราะห์ตามรูปแบบ
  • 129 รองรับโทเค็นรูปแบบที่หลากหลายสำหรับปี เดือน วัน ฟิลด์เวลา และเอาต์พุตเขตเวลา
  • ที่ใช้ร่วมกัน 130 อินสแตนซ์ไม่ปลอดภัยในโค้ดแบบมัลติเธรด เนื่องจากสถานะภายในไม่แน่นอน
  • 142 แยกอินสแตนซ์ของฟอร์แมตเตอร์ต่อเธรดเมื่อไม่สามารถย้ายรหัสเดิมได้ทันที
  • 151 ไม่เปลี่ยนรูปและปลอดภัยสำหรับเธรด ดังนั้นจึงเป็นการดีกว่าที่จะแทนที่โค้ด Java ใหม่
  • 167 สามารถโยน 170 ได้ ดังนั้นการแยกวิเคราะห์โค้ดควรใช้ try-catch และข้อความแสดงข้อผิดพลาดที่เป็นประโยชน์
  • 184 ป้องกันวันที่ที่ไม่ถูกต้องที่ปรับโดยไม่ต้องแจ้งให้ทราบ เช่น 197
  • ส่ง 201 ที่ชัดเจนเสมอ เพื่อหลีกเลี่ยงเอาต์พุตที่ขึ้นอยู่กับสภาพแวดล้อมในการปรับใช้เซิร์ฟเวอร์

SimpleDateFormat ใน Java คืออะไร

210 คือ 228 คลาสย่อยที่ให้คุณกำหนดรูปแบบวันที่/เวลาที่ชัดเจนสำหรับการจัดรูปแบบและการแยกวิเคราะห์ใน Java

ใช้ 234 เมื่อคุณต้องการเอาต์พุตตามสไตล์และทราบสถานที่ผ่านวิธีการจากโรงงาน และใช้ 246 เมื่อคุณต้องการการควบคุมรูปแบบที่แน่นอน เช่น 256 หรือ 266 . 277 ค่าคงที่สไตล์ (284 , 292 , 304 , 310 ) สร้างเอาต์พุตที่เหมาะสมกับสถานที่โดยไม่จำเป็นต้องให้คุณทราบลำดับวันที่ตามภูมิภาคที่แน่นอน ซึ่งมีประโยชน์สำหรับสตริงการแสดงผลที่ผู้ใช้เห็นซึ่งรูปแบบควรเป็นไปตามแบบแผนสถานที่ของผู้ใช้ ใช้ 322 เมื่อรูปแบบเอาต์พุตได้รับการแก้ไขโดยข้อกำหนดภายนอก เช่น สัญญา API รูปแบบบันทึก หรือรูปแบบการตั้งชื่อไฟล์ เนื่องจากกรณีเหล่านั้นจำเป็นต้องมีรูปแบบที่แน่นอนโดยไม่คำนึงถึงภาษา

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
Locale locale = Locale.US;
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
String styleBased = dateFormat.format(new Date());
SimpleDateFormat patternBased = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss", locale);
String patternOutput = patternBased.format(new Date());
System.out.println(styleBased);
System.out.println(patternOutput);
Jan 5, 2026
05-01-2026 14:30:22

332 เลิกใช้แล้วตั้งแต่ Java 19 ใช้ 345 แทน.

Locale locale = new Locale.Builder()
 .setLanguage("en")
 .setRegion("US")
 .build();

หากต้องการจัดรูปแบบเวลาแทนวันที่ ให้ใช้ 356 ด้วยพารามิเตอร์สถานที่และสไตล์เดียวกัน

Locale locale = Locale.US;
DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale);
System.out.println(timeFormat.format(new Date()));
Output depends on the current time and timezone, for example:
2:30:45 PM

สำหรับภาพรวมที่กว้างขึ้นของ API วันที่/เวลา Java สมัยใหม่ โปรดดูคุณลักษณะ Java 8 Date, LocalDate, LocalDateTime, Instant และ Java 8 พร้อมตัวอย่าง

การอ้างอิงไวยากรณ์รูปแบบ SimpleDateFormat

366 ตัวอักษรรูปแบบแมปโดยตรงกับส่วนประกอบวันที่/เวลา และการเลือกรูปแบบที่ถูกต้องจะควบคุมทั้งรูปแบบเอาต์พุตและพฤติกรรมการแยกวิเคราะห์

สัญลักษณ์ ความหมาย รูปแบบตัวอย่าง ผลลัพธ์ตัวอย่าง 375 ผู้กำหนดยุค389 392 401 ปี418 424 435 เดือนในปี449 455 466 สัปดาห์ในปี479 481 495 สัปดาห์ในเดือน507 515 522 วันในปี537 542 551 วันในเดือน567 573 587 วันในสัปดาห์ในเดือน594 605 610 ชื่อวันในสัปดาห์625 637 646 หมายเลขวันในสัปดาห์ (659 )669 673 687 เครื่องหมาย AM/PM692 700 710 ชั่วโมงต่อวัน (722 )735 748 752 ชั่วโมงต่อวัน (760 )772 786 795 ชั่วโมงเป็นช่วงเช้า/บ่าย (801 )811 827 831 ชั่วโมงเป็นช่วงเช้า/บ่าย (842 )854 862 878 นาทีในชั่วโมง880 890 900 วินาทีในนาที910 925 936 มิลลิวินาที948 953 966 เขตเวลาทั่วไป976 989 990 ออฟเซ็ตเขตเวลา RFC 8221000 1019 1023 ชดเชยเขตเวลา ISO 86011036 1045

การทำซ้ำรูปแบบและความกว้างเอาต์พุต

ตัวอักษรที่มีรูปแบบซ้ำๆ จะเปลี่ยนความกว้าง การเติมตัวเลข หรือรูปแบบข้อความ

สนาม รูปแบบ ผลลัพธ์ตัวอย่าง เดือน1,052 1068 เดือน1,079 1083 เดือน1098 1109 เดือน1112 1121 วันของเดือน1138 1140 วันของเดือน1155 1165 ชั่วโมง (1171 )1182 1195 ชั่วโมง (1200 )1214 1220 ปี1234 1248 ปี1253 1268

ตัวอย่างรูปแบบทั่วไปพร้อมผลลัพธ์ที่คาดหวัง

รูปแบบทั่วไปเหล่านี้มีประโยชน์สำหรับบันทึก, API และวันที่ที่ผู้ใช้พบ

รูปแบบ ผลลัพธ์ตัวอย่าง 1270 1289 1292 1309 1314 1320 1332 1344 1353 1365

วิธีการจัดรูปแบบวันที่โดยใช้ SimpleDateFormat

หากต้องการจัดรูปแบบ 1378 ให้สร้าง 1381 มีรูปแบบและโทร 1393 .

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
Date now = new Date();
SimpleDateFormat basic = new SimpleDateFormat("MM-dd-yyyy", Locale.US);
SimpleDateFormat withTime = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss", Locale.US);
SimpleDateFormat isoLike = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
System.out.println(basic.format(now));
System.out.println(withTime.format(now));
System.out.println(isoLike.format(now));
01-05-2026
05-01-2026 14:30:45
2026-01-05T14:30:45+0000

1403 ใช้กฎเขตเวลาและสถานที่จากอินสแตนซ์ตัวจัดรูปแบบ ดังนั้นให้ตั้งค่าเหล่านั้นอย่างชัดเจนเมื่อเอาต์พุตต้องสอดคล้องกัน

วิธีแยกสตริงเป็นวันที่โดยใช้ SimpleDateFormat

หากต้องการแยกสตริงเป็น 1415 สร้างฟอร์แมตเตอร์ด้วยรูปแบบอินพุตที่แน่นอนแล้วเรียก 1429 .

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
try {
 SimpleDateFormat dateParser = new SimpleDateFormat("dd-MM-yyyy", Locale.US);
 Date parsedDate = dateParser.parse("05-01-2026");
 System.out.println(parsedDate);
 SimpleDateFormat timeParser = new SimpleDateFormat("HH:mm:ss", Locale.US);
 Date parsedTime = timeParser.parse("22:15:09");
 System.out.println(parsedTime);
} catch (ParseException e) {
 e.printStackTrace();
}
Mon Jan 05 00:00:00 UTC 2026
Thu Jan 01 22:15:09 UTC 1970

หากมีการระบุเวลาเท่านั้น Java จะใช้วันที่ยุคเป็นส่วนวันที่

การจัดการ ParseException อย่างถูกต้อง

1438 พ่น 1444 เมื่ออินพุตไม่ตรงกับรูปแบบที่กำหนดค่าไว้ ดังนั้นโค้ดการผลิตควรตรวจจับและบันทึกทั้งอินพุตดิบและรูปแบบที่คาดหวัง

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
String input = "31/01/2026";
String pattern = "dd-MM-yyyy";
SimpleDateFormat parser = new SimpleDateFormat(pattern, Locale.US);
try {
 parser.parse(input);
 System.out.println("Parsed successfully");
} catch (ParseException e) {
 // Include both the input value and pattern for easier debugging.
 System.err.println("Failed to parse date string: " + input);
 System.err.println("Expected pattern: " + pattern);
 System.err.println("Parser error: " + e.getMessage());
}
Failed to parse date string: 31/01/2026
Expected pattern: dd-MM-yyyy
Parser error: Unparseable date: "31/01/2026"

สำหรับรูปแบบการจัดการข้อยกเว้นที่คุณสามารถนำมาใช้ซ้ำในบริการต่างๆ โปรดดูการจัดการข้อยกเว้นใน Java และ Java 8 Date, LocalDate, LocalDateTime, Instant

ตรวจสอบสตริงวันที่ก่อนแยกวิเคราะห์

1454 มีการผ่อนปรนตามค่าเริ่มต้น ดังนั้นค่าที่ไม่ถูกต้องจึงสามารถทบกลับได้แทนที่จะล้มเหลว โทร 1461 เพื่อบังคับใช้การตรวจสอบอย่างเข้มงวด

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
String invalid = "2024-13-45";
SimpleDateFormat lenientParser = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
SimpleDateFormat strictParser = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
strictParser.setLenient(false);
System.out.println("Lenient parse result:");
try {
 // Lenient mode silently rolls over invalid values instead of throwing.
 System.out.println(lenientParser.parse(invalid));
} catch (ParseException e) {
 System.out.println("ParseException: " + e.getMessage());
}
System.out.println("Strict parse result:");
try {
 System.out.println(strictParser.parse(invalid));
} catch (ParseException e) {
 System.out.println("ParseException: " + e.getMessage());
}
Lenient parse result:
Fri Feb 14 00:00:00 UTC 2025
Strict parse result:
ParseException: Unparseable date: "2024-13-45"

การจัดการเขตเวลาใน SimpleDateFormat

1472 สามารถแสดงผล 1486 เดียวกันได้ ในเขตเวลาที่ต่างกันโดยการตั้งค่าเขตเวลาบนฟอร์แมตเตอร์ก่อนเอาต์พุต 1497 อ็อบเจ็กต์เก็บเฉพาะจำนวนมิลลิวินาที UTC และไม่มีเขตเวลาของตัวเอง เขตเวลาเป็นปัญหาเกี่ยวกับการจัดรูปแบบ ไม่ใช่ข้อกังวลเรื่องพื้นที่จัดเก็บข้อมูล 1505 เดียวกัน ค่าจะสร้างเอาต์พุตที่มนุษย์อ่านได้ที่แตกต่างกัน ขึ้นอยู่กับเขตเวลาที่ตัวจัดรูปแบบใช้ ซึ่งหมายความว่า 1511 ต้องถูกเรียกบนฟอร์แมตเตอร์ก่อน 1520 เรียกว่า; การตั้งค่าในภายหลังจะไม่ส่งผลต่อเอาต์พุตที่ผลิตไปแล้ว

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
Date timestamp = new Date(1700000000000L); // Fixed instant for repeatable output
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.US);
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("UTC: " + formatter.format(timestamp));
formatter.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println("New York: " + formatter.format(timestamp));
formatter.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
System.out.println("Kolkata: " + formatter.format(timestamp));
UTC: 2023-11-14 22:13:20 +0000
New York: 2023-11-14 17:13:20 -0500
Kolkata: 2023-11-15 03:43:20 +0530

ดูวิธีแปลงวันที่ Java เป็นรูปแบบเขตเวลาเฉพาะเพื่อดูรูปแบบการแปลงเขตเวลาที่ลึกยิ่งขึ้น

ข้อผิดพลาดเกี่ยวกับเขตเวลาที่พบบ่อยและวิธีหลีกเลี่ยง

ข้อบกพร่องของเขตเวลามักมาจากการสร้างความสับสนให้กับ Instant ที่จัดเก็บไว้ตามเวลาท้องถิ่นที่แสดงผล

  • 1530 เก็บ UTC มิลลิวินาที และเขตเวลาจะใช้เฉพาะเมื่อจัดรูปแบบ
  • กำลังโทร 1540 บนอินสแตนซ์ฟอร์แมตเตอร์ที่ใช้ร่วมกันในสภาพแวดล้อมแบบมัลติเธรดสามารถเปลี่ยนโซนเวลากลางการดำเนินการสำหรับการเรียกใช้เธรด Sin-Flight อื่น ทำให้เกิดเอาต์พุตในเขตเวลาที่ไม่ถูกต้องโดยไม่มีข้อยกเว้นเกิดขึ้น
  • การนำ 1551 เดียวมาใช้ซ้ำ อินสแตนซ์ข้ามคำขอ HTTP ใน aservlet หรือ Spring controller อาจทำให้เกิดคำขอ 1568 ของคำขอเดียว การเรียก toaffect ผลลัพธ์ของคำขออื่น สร้างอินสแตนซ์ใหม่ตามคำขอหรือใช้1579 เพื่อแยกรัฐ
  • 1581 ย้อนกลับไปที่ GMT โดยไม่แจ้งให้ทราบ เนื่องจากสัญญาวิธีการระบุ GMT เป็นค่าเริ่มต้นสำหรับ ID ที่ไม่รู้จักแทนที่จะส่งข้อยกเว้น
  • ตรวจสอบรหัสโซนด้วย 1594 จาก 1609 ก่อนที่จะส่งต่อไปที่ 1619; 1622 พ่น 1630 บน ID ที่ไม่ถูกต้อง ซึ่งทำให้ปัญหาชัดเจน

การจัดรูปแบบวันที่ที่รับรู้สถานที่

หากต้องการสร้างเอาต์พุตวันที่เฉพาะสถานที่ เช่น ชื่อเดือนภาษาฝรั่งเศสหรือชื่อวันในเยอรมัน ให้ส่ง 1641 ไปที่ 1659 ตัวสร้าง ใช้ค่าคงที่ในตัว 1664 , 1679 , 1685 , 1695 สำหรับภูมิภาคทั่วไป หรือสร้างภาษาที่กำหนดเองด้วย 1701 เมื่อคุณต้องการขอบเขตที่ไม่ครอบคลุมโดยค่าคงที่ 1719 ควบคุมภาษาที่จะใช้สำหรับช่องข้อความ เช่น ชื่อเดือน ชื่อวัน และเครื่องหมาย AM/PM

การระบุสถานที่ในตัวสร้าง SimpleDateFormat

ส่ง 1723 เป็นอาร์กิวเมนต์ตัวสร้างที่สอง หากคุณละเว้น 1731 โทร 1740 ภายใน ซึ่งจะผูกฟอร์แมตเตอร์เข้ากับภาษารันไทม์ของ JVM ซึ่งเป็นค่าที่แตกต่างกันระหว่างเครื่องของนักพัฒนา สภาพแวดล้อม CI และเซิร์ฟเวอร์ที่ใช้งานจริงที่ทำงานภายใต้การกำหนดค่าภาษา OS ที่แตกต่างกัน

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
Date sample = new Date(1700000000000L);
String pattern = "EEEE, dd MMMM yyyy";
SimpleDateFormat usFormatter = new SimpleDateFormat(pattern, Locale.US);
SimpleDateFormat frFormatter = new SimpleDateFormat(pattern, Locale.FRENCH);
String usDate = usFormatter.format(sample);
String frDate = frFormatter.format(sample);
System.out.println("US: " + usDate);
System.out.println("French: " + frDate);
US: Tuesday, 14 November 2023
French: mardi, 14 novembre 2023

การจัดรูปแบบชื่อเดือนและวันตามภูมิภาค

รูปแบบเดียวกันทำให้ข้อความออกมาต่างกันตามสถานที่

สถานที่ รูปแบบ เอาท์พุท 1752 1764 1771 1781 1798 1808 1814 1825 1838

อาศัย 1843 ใน JVM ที่ทำงานในสภาพแวดล้อมเซิร์ฟเวอร์สามารถสร้างเอาต์พุตที่ไม่สอดคล้องกันได้เนื่องจากการตั้งค่าโลแคล OS แตกต่างกันในแต่ละโฮสต์ ส่ง 1857 ที่ชัดเจนเสมอ .

ปัญหาความปลอดภัยของเธรดด้วย SimpleDateFormat

เหตุใด SimpleDateFormat จึงไม่ปลอดภัยสำหรับเธรด

1863 กลายพันธุ์ภายใน 1878 และ 1881 ระบุสถานะระหว่างการดำเนินการแยกวิเคราะห์/จัดรูปแบบ หากหลายเธรดใช้อินสแตนซ์เดียว ฟิลด์ที่ไม่แน่นอนเหล่านี้สามารถถูกเขียนทับระหว่างการดำเนินการได้ ซึ่งทำให้เกิดสภาวะการแข่งขันและเอาต์พุตที่คาดเดาไม่ได้ ในทางปฏิบัติสิ่งนี้จะแสดงเป็นวันที่จากเธรดหนึ่งที่ปรากฏในผลลัพธ์ของเธรดอื่น 1893 ส่งกลับวันที่ผิดโดยสิ้นเชิงโดยไม่มีข้อยกเว้นหรือ 1901 โยนจากภายในฟอร์แมตเตอร์เอง ความล้มเหลวเหล่านี้เกิดขึ้นเป็นระยะๆ และขึ้นอยู่กับโหลด ซึ่งทำให้ยากต่อการจำลองในสภาพแวดล้อมการทดสอบแบบเธรดเดียว

เมื่อคุณต้องการการจัดรูปแบบที่ปลอดภัยพร้อมกันในโค้ดเดิม ให้แยกอินสแตนซ์ตามเธรดหรือขอบเขตคำขอ สำหรับความเป็นมาเกี่ยวกับลักษณะการทำงานของเธรด Java โปรดดูตัวอย่างเธรด Java

การใช้ ThreadLocal เพื่อแยกอินสแตนซ์ SimpleDateFormat

1911 ให้แต่ละเธรดอินสแตนซ์ตัวจัดรูปแบบของตัวเองและหลีกเลี่ยงสถานะที่ไม่แน่นอนที่ใช้ร่วมกัน ในสภาพแวดล้อมเธรดพูล เช่น คอนเทนเนอร์เซิร์ฟเล็ตและแอปพลิเคชัน Spring เธรดจะถูกนำมาใช้ซ้ำในคำขอและจะไม่ถูกยกเลิก ซึ่งหมายความว่า 1929 ค่าจะไม่ถูกลบออกโดยอัตโนมัติ โทร 1933 ทุกครั้ง หลังจากการดำเนินการเสร็จสิ้น หรืออินสแตนซ์ตัวจัดรูปแบบจะคงอยู่ตลอดอายุการใช้งานของเธรด และสะสมเป็นหน่วยความจำรั่วภายใต้โหลดที่ยั่งยืน

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class ThreadSafeLegacyFormatter {
 // Each thread gets one dedicated formatter instance.
 private static final ThreadLocal<SimpleDateFormat> FORMATTER =
 ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US));
 public static String format(Date date) {
 try {
 // No cross-thread mutation because each thread reads its own formatter.
 return FORMATTER.get().format(date);
 } finally {
 // Remove the instance after use to prevent memory leaks in thread pools.
 FORMATTER.remove();
 }
 }
}

การเปลี่ยนไปใช้ DateTimeFormatter เป็นทางเลือกที่ปลอดภัยสำหรับเธรด

1942 ไม่เปลี่ยนรูปและปลอดภัยสำหรับเธรด ดังนั้นอินสแตนซ์แบบคงที่ที่ใช้ร่วมกันหนึ่งอินสแตนซ์จึงปลอดภัย

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
// Not thread-safe when shared across threads
SimpleDateFormat unsafe = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
System.out.println(unsafe.format(new Date()));
// Thread-safe: DateTimeFormatter is immutable and can be stored as a static field
DateTimeFormatter safe = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.US);
System.out.println(safe.format(LocalDateTime.now()));
2026-01-05 14:30:22
2026-01-05 14:30:22

การย้ายจาก SimpleDateFormat ไปเป็น DateTimeFormatter

การย้ายข้อมูลเป็น 1957 ขจัดความเสี่ยงด้านความปลอดภัยของเธรด กำจัด 1964 วิธีแก้ปัญหาชั่วคราว และผสานรวมกับ 1976 อย่างสมบูรณ์ ประเภท สำหรับโค้ดเบสส่วนใหญ่ การโยกย้ายเป็นไปตามกลไก:ไวยากรณ์ของรูปแบบเกือบจะเหมือนกัน โดย API ทั้งสองสามารถอยู่ร่วมกันได้ในระหว่างการเปิดตัวส่วนเพิ่ม และคุณไม่จำเป็นต้องแปลงทุกอย่างพร้อมกัน ความเสี่ยงหลักคือ 1987 สัญลักษณ์ ซึ่งหมายถึงวันในสัปดาห์ใน 1996 และปีใน 2008; รูปแบบที่คัดลอกโดยตรงระหว่าง API โดยไม่ตรวจสอบจะทำให้เกิดเอาต์พุตที่ไม่ถูกต้อง

การเปรียบเทียบโค้ดแบบเคียงข้างกัน

ตัวอย่างข้อมูลแบบเคียงข้างกันนี้แสดงการจัดรูปแบบที่เทียบเท่าและพฤติกรรมการแยกวิเคราะห์ใน API เดิมและสมัยใหม่

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;
String pattern = "yyyy-MM-dd";
String input = "2026-01-05";
// SimpleDateFormat (legacy java.util.Date API)
SimpleDateFormat legacyFormatter = new SimpleDateFormat(pattern, Locale.US);
Date legacyParsed = legacyFormatter.parse(input);
String legacyFormatted = legacyFormatter.format(new Date());
// DateTimeFormatter (modern java.time API)
DateTimeFormatter modernFormatter = DateTimeFormatter.ofPattern(pattern, Locale.US);
LocalDate modernParsed = LocalDate.parse(input, modernFormatter);
String modernFormatted = modernFormatter.format(LocalDate.now());
System.out.println(legacyParsed);
System.out.println(legacyFormatted);
System.out.println(modernParsed);
System.out.println(modernFormatted);
Mon Jan 05 00:00:00 UTC 2026
2026-01-05
2026-01-05
2026-01-05

ความแตกต่างทางไวยากรณ์ของรูปแบบระหว่าง API ทั้งสอง

ตัวอักษรรูปแบบส่วนใหญ่จะคล้ายกัน แต่สัญลักษณ์บางตัวแตกต่างกันและอาจหยุดการย้ายข้อมูลได้หากคัดลอกโดยตรง

งาน รูปแบบ SimpleDateFormat รูปแบบ DateTimeFormatter หมายเหตุ ปี2012 2022 หรือ 2036 ต้องการ 2046 ใน 2058 เพื่อความสอดคล้องกันของปี prolepticTimezone offset/name2063 , 2079 , 2085 2098 , 2104 , 2115 , 2129 2130 แยกแยะตัวแปรออฟเซ็ตเพิ่มเติม (2148 และ 2154 )ข้อความตัวอักษร2163 2174 API ทั้งสองใช้เครื่องหมายคำพูดเดี่ยวสำหรับตัวอักษร2183 symbolDay-of-week numberYearKnown gotcha:2194 เปลี่ยนความหมายระหว่าง API

รายการตรวจสอบการย้ายข้อมูลทีละขั้นตอน

ใช้รายการตรวจสอบนี้เพื่อแปลงฟอร์แมตเตอร์ทีละตัวในโค้ดเบสที่มีอยู่

  1. แทนที่ 2201 ด้วย 2210
  2. แทนที่ 2221 ด้วย 2237
  3. แทนที่ 2242 ด้วย 2259 หรือ 2263 ขึ้นอยู่กับความแม่นยำของอินพุต
  4. แทนที่ 2273 ด้วย 2284 หรือ 2292
  5. ลบ 2307 หากเป็นไปได้และใช้ 2313 หรือ 2329

2335 ใช้งานได้เฉพาะกับ 2345 ประเภท (2352 , 2366 , 2375 , 2383 ). ไม่ยอมรับ 2395 โดยตรง หากคุณมีโค้ดที่ยังคงสร้าง 2407 ค่า เช่น จากไดรเวอร์ ORM หรือ JDBC เดิม ให้แปลงก่อนด้วย 2414 ก่อนที่จะส่งต่อไปยัง 2424 . API ทั้งสองสามารถอยู่ร่วมกันในโค้ดเบสเดียวกันได้ในระหว่างการโยกย้ายส่วนเพิ่ม คุณไม่จำเป็นต้องแปลงทุกอย่างพร้อมกัน 2432 ยังแทนที่ 2449 ด้วย ด้วย 2454 ซึ่งเป็นข้อยกเว้นที่ไม่ได้ตรวจสอบ ดังนั้นบล็อก try-catch จึงกลายเป็นทางเลือก แต่ยังคงแนะนำให้ใช้ในโค้ดการแยกวิเคราะห์ที่ใช้งานจริง

สำหรับตัวเลือกบริบทและประเภทการย้าย โปรดดูที่ Java 8 Date, LocalDate, LocalDateTime, Instant

คำถามที่พบบ่อย

SimpleDateFormat และ DateFormat ใน Java แตกต่างกันอย่างไร?

2468 เป็นคลาสนามธรรมที่กำหนดสัญญาสำหรับการจัดรูปแบบวันที่/เวลา 2471 เป็นคลาสย่อยที่เป็นรูปธรรมที่ช่วยให้สามารถจัดรูปแบบตามรูปแบบที่กำหนดเองได้ คุณใช้ 2484 โดยตรงในรหัส คุณใช้ 2490 เป็นประเภทอ้างอิงเมื่อคุณต้องการยอมรับการใช้งานใดๆ

SimpleDateFormat thread ปลอดภัยหรือไม่?

เลขที่ 2503 อินสแตนซ์ไม่ปลอดภัยต่อเธรด การแชร์อินสแตนซ์เดียวข้ามเธรดที่ไม่มีการซิงโครไนซ์ทำให้เกิดผลลัพธ์ในการแยกวิเคราะห์และรูปแบบที่คาดเดาไม่ได้ ใช้ 2511 หรือแทนที่ด้วย 2522 ซึ่งไม่เปลี่ยนรูปและปลอดภัยต่อเธรด

ฉันจะแยกวิเคราะห์สตริงวันที่ในรูปแบบ dd-MM-yyyy โดยใช้ SimpleDateFormat ได้อย่างไร

สร้างอินสแตนซ์ 2537 ด้วยรูปแบบ 2544 จากนั้นโทร 2554 . ตัดสายในบล็อก try-catch สำหรับ 2563 . ตรวจสอบให้แน่ใจว่าสตริงอินพุตตรงกับรูปแบบทุกประการ รวมถึงอักขระตัวคั่นด้วย

ฉันจะแปลงวันที่เป็นเขตเวลาอื่นโดยใช้ SimpleDateFormat ได้อย่างไร

โทร 2576 บน 2586 ของคุณ ตัวอย่างก่อนโทร 2590 . 2604 ที่ซ่อนอยู่ วัตถุเก็บ UTC มิลลิวินาที ฟอร์แมตเตอร์จะใช้ออฟเซ็ตเขตเวลาระหว่างเอาต์พุต

รูปแบบ “yyyy-MM-dd’T’HH:mm:ssZ” ก่อให้เกิดอะไร?

สร้างการประทับเวลาที่เข้ากันได้กับ ISO 8601 เช่น 2619 . 2620 เป็นอักขระตามตัวอักษรที่รวมอยู่ในเครื่องหมายคำพูดเดี่ยว 2639 แสดงถึงการชดเชยเขตเวลา RFC 822

ฉันจะย้ายจาก SimpleDateFormat ไปเป็น DateTimeFormatter ได้อย่างไร

แทนที่ 2641 ด้วย 2652 . แทนที่ 2665 โทรด้วย 2679 หรือ 2689 . แทนที่ 2691 โทรด้วย 2703 . โปรดทราบว่า 2712 ใช้ 2728 สำหรับปีในบางบริบทแทนที่จะเป็น 2731 .

เหตุใด SimpleDateFormat จึงแยกวิเคราะห์วันที่ที่ไม่ถูกต้องโดยไม่มีข้อยกเว้น

ตามค่าเริ่มต้น 2744 ใช้โหมดการแยกวิเคราะห์แบบผ่อนปรน ซึ่งจะปรับค่าที่อยู่นอกช่วงแทนที่จะปฏิเสธค่าเหล่านั้น โทร 2758 ก่อนที่จะแยกวิเคราะห์เพื่อบังคับใช้การตรวจสอบอย่างเข้มงวดและโยน 2762 เมื่ออินพุตไม่ถูกต้อง

ฉันจะจัดรูปแบบวันที่ด้วยสถานที่เฉพาะโดยใช้ SimpleDateFormat ได้อย่างไร

ผ่าน 2771 เป็นอาร์กิวเมนต์ที่สองของตัวสร้าง:2789 . ซึ่งจะทำให้ชื่อเดือนและวันเป็นภาษาที่ระบุ ซึ่งมีความสำคัญอย่างยิ่งต่อแอปพลิเคชันที่ให้บริการในหลายภูมิภาค

บทสรุป

คู่มือนี้ครอบคลุมถึง 2795 และ 2807 พื้นฐาน, ไวยากรณ์รูปแบบ, การจัดรูปแบบและการแยกวิเคราะห์เวิร์กโฟลว์, ลักษณะการทำงานของเขตเวลา, การแสดงผลแบบ Locale-aware, ปัญหาความปลอดภัยของเธรด และการโยกย้ายไปยัง 2817 .

ขณะนี้คุณสามารถเลือกตัวจัดรูปแบบที่เหมาะสมสำหรับโค้ดเดิมและโค้ดสมัยใหม่ แยกวิเคราะห์อินพุตเชิงป้องกันด้วยการตรวจสอบที่เข้มงวด หลีกเลี่ยงการเคลื่อนตัวของภาษาและเขตเวลาในสภาพแวดล้อมของเซิร์ฟเวอร์ และขจัดความเสี่ยงที่เกิดขึ้นพร้อมกันจากตัวจัดรูปแบบวันที่ที่ใช้ร่วมกัน

สำหรับขั้นตอนถัดไป ให้ตรวจสอบวันที่ของ Java 8, LocalDate, LocalDateTime, Instant, คุณสมบัติ Java 8 พร้อมตัวอย่าง, การจัดการข้อยกเว้นใน Java และวิธีแปลงวันที่ของ Java เป็นรูปแบบโซนเวลาเฉพาะ เพื่อดำเนินการปรับปรุงการจัดการวันที่/เวลาในแอปพลิเคชัน Java ให้ทันสมัยต่อไป

ข้อมูลอ้างอิง:

  • เอกสาร SimpleDateFormat API
  • เอกสาร DateFormat API
  • เอกสาร API ของ DateTimeFormatter API

การจัดรูปแบบวันที่ Master Java:SimpleDateFormat &DateFormat อธิบาย งานนี้ได้รับอนุญาตภายใต้ Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License