บทนำ
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 รายการตรวจสอบการย้ายข้อมูลทีละขั้นตอน
ใช้รายการตรวจสอบนี้เพื่อแปลงฟอร์แมตเตอร์ทีละตัวในโค้ดเบสที่มีอยู่
- แทนที่
2201 ด้วย 2210
- แทนที่
2221 ด้วย 2237
- แทนที่
2242 ด้วย 2259 หรือ 2263รหัส> ขึ้นอยู่กับความแม่นยำของอินพุต
- แทนที่
2273 ด้วย 2284 หรือ 2292รหัส>
- ลบ
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
งานนี้ได้รับอนุญาตภายใต้ Creative Commons Attribution-NonCommercial- ShareAlike 4.0 International License
-
-
-
-