Joda-Time: คืออะไร ไลบรารีวันที่ และการแทนที่ด้วย Java 8

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-07-14 เวลาอ่าน: 10 นาที

Joda-Time — ไลบรารีสำหรับการทำงานกับวันที่และเวลาใน Java สร้างโดย Stephen Colebourne เพื่อเป็นทางเลือกแทน java.util.Date และ java.util.Calendar ที่ไม่สะดวก ก่อนที่ Java 8 จะออก ไลบรารีนี้เป็นมาตรฐานโดยพฤตินัยสำหรับการทำงานกับวันที่ในการพัฒนาระดับอุตสาหกรรม รวมถึงแอปพลิเคชัน Android ตามข้อมูลจาก Oracle Java Magazine (2023) โปรเจกต์มากกว่า 60% ได้ย้ายจาก Joda-Time ไปยัง java.time ภายในสองปีหลังจาก Android API 26 เปิดตัว

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

  • Joda-Time — ไลบรารีสำหรับทำงานกับวันที่และเวลา ซึ่งเป็นบรรพบุรุษของ java.time ใน Java 8
  • คลาส Immutable — DateTime, LocalDate, LocalTime, LocalDateTime ทำให้มั่นใจในความปลอดภัยของเธรด
  • การรองรับเขตเวลา — ฐานข้อมูลเขตเวลาในตัวพร้อมการอัปเดตอัตโนมัติ
  • การย้าย — java.time (JSR-310) แทนที่ Joda-Time อย่างสมบูรณ์ ผู้เขียนไลบรารีแนะนำให้ย้าย
  • Android — Joda-Time ทำงานตั้งแต่ API 1 แต่สำหรับ Android 8+ (API 26) ควรใช้ java.time มากกว่า

Joda-Time คืออะไร

Joda-Time — เป็นไลบรารีโอเพนซอร์ส (Apache 2.0) ที่ให้การทดแทนคุณภาพสูงสำหรับคลาส java.util.Date และ java.util.Calendar ในภาษา Java โปรเจกต์นี้ก่อตั้งโดย Stephen Colebourne ในปี 2004 เพื่อตอบสนองต่อปัญหามากมายของ API วันที่มาตรฐาน รวมถึงความไม่แน่นอน (mutability) ความซับซ้อนของการจัดรูปแบบ และการรองรับเขตเวลาที่จำกัด ไลบรารีนี้แพร่หลายในชุมชน Java และถูกใช้โดยโปรเจกต์นับพัน รวมถึงระบบองค์กรขนาดใหญ่และแอปพลิเคชัน Android ซึ่งเครื่องมือจัดการวันที่ในตัวนั้นไม่สะดวกเป็นพิเศษ หลังจาก Java 8 เปิดตัวในปี 2014 และแพ็คเกจ java.time (JSR-310) ปรากฏขึ้น ไลบรารีถูกเปลี่ยนเป็นโหมดบำรุงรักษา — ไม่มีการเพิ่มฟีเจอร์ใหม่ และฟังก์ชันที่มีอยู่ทั้งหมดครอบคลุมโดย API ใหม่

สถาปัตยกรรมของไลบรารี

Joda-Time สร้างขึ้นบนหลักการของ immutability: ออบเจกต์วันที่หรือเวลาทุกตัวหลังจากสร้างแล้วไม่สามารถเปลี่ยนแปลงได้ การดำเนินการใด ๆ — การเพิ่มวัน การเปลี่ยนเดือน การกำหนดเขตเวลา — จะคืนค่าออบเจกต์ใหม่ โดยปล่อยให้ออบเจกต์เดิมไม่เปลี่ยนแปลง วิธีการนี้ช่วยขจัดข้อผิดพลาดประเภทที่เกี่ยวข้องกับการแก้ไขออบเจกต์โดยไม่ตั้งใจ ซึ่งเป็นลักษณะเฉพาะของ java.util.Date และ java.util.Calendar ที่ไม่แน่นอน การออกแบบแบบ immutable ยังทำให้ไลบรารีปลอดภัยต่อเธรดโดยไม่ต้องมีการซิงโครไนซ์เพิ่มเติม

คลาสพื้นฐานของ Joda-Time

ไลบรารีมีคลาสหลักหลายคลาสสำหรับสถานการณ์ต่าง ๆ: DateTime — วันที่และเวลาเต็มพร้อมเขตเวลา, LocalDate — เฉพาะวันที่โดยไม่มีเวลา, LocalTime — เฉพาะเวลาโดยไม่มีวันที่, LocalDateTime — วันที่และเวลาโดยไม่ผูกกับเขตเวลา นอกจากนี้ยังมีคลาสสำหรับทำงานกับช่วงเวลา (Interval) ระยะเวลา (Period) และความยาวเวลา (Duration) ซึ่งช่วยให้คำนวณความแตกต่างระหว่างสองจุดเวลาในหน่วยต่าง ๆ ได้ แต่ละคลาสใช้อินเทอร์เฟซ ReadableInstant หรือ ReadablePartial เพื่อการประมวลผลที่สอดคล้องกัน

ประวัติความเป็นมาของ Joda-Time

ปัญหาเกี่ยวกับ API วันที่มาตรฐานใน Java เป็นที่รู้จักกันตั้งแต่เริ่มต้นของแพลตฟอร์ม คลาส java.util.Date และ java.util.Calendar มีข้อบกพร่องพื้นฐาน: เดือนเริ่มนับจาก 0, Date แทนทั้งวันที่และเวลาพร้อมกัน, Calendar ไม่แน่นอนและต้องมีการตั้งค่าที่ซับซ้อน การจัดรูปแบบผ่าน SimpleDateFormat ไม่ปลอดภัยต่อเธรด — ในแอปพลิเคชันแบบหลายเธรด สิ่งนี้นำไปสู่การแยกวิเคราะห์วันที่ที่ไม่ถูกต้อง Stephen Colebourne ขณะทำงานในโปรเจกต์ที่ใช้วันที่จำนวนมาก ตัดสินใจสร้างทางเลือกที่จะแก้ไขปัญหาทั้งหมดนี้

ตามบทสัมภาษณ์บน InfoQ (2014) Colebourne ทดสอบ Joda-Time ในโปรเจกต์อุตสาหกรรมนานกว่าหนึ่งปีก่อนการเผยแพร่สาธารณะครั้งแรก เวอร์ชันแรกออกในปี 2004 และดึงดูดความสนใจของชุมชนได้ทันที ภายในปี 2010 ไลบรารีกลายเป็นการพึ่งพามาตรฐานในโปรเจกต์ Java ส่วนใหญ่ รวมถึงเฟรมเวิร์กอย่าง Spring และ Hibernate ความสำเร็จของ Joda-Time ส่งผลโดยตรงต่อข้อกำหนด JSR-310 (Date and Time API) ซึ่งรวมอยู่ใน Java 8 — โดยที่ผู้เขียนข้อกำหนดคือ Stephen Colebourne คนเดียวกัน

ผลกระทบต่อระบบนิเวศ Java

Joda-Time ไม่เพียงแต่แก้ปัญหาวันที่ — มันเปลี่ยนวิธีการออกแบบ API ใน Java แนวคิดของ immutable value-objects ที่ไลบรารีแสดงให้เห็น ถูกนำมาใช้เป็นมาตรฐานใน Java 8 สำหรับ API ใหม่ทั้งหมด ยิ่งไปกว่านั้น ความนิยมของ Joda-Time แสดงให้ Oracle เห็นว่าชุมชนไม่พร้อมที่จะยอมรับไลบรารีมาตรฐานที่มีคุณภาพต่ำ — หลังจาก Joda-Time API ใน Java สำหรับการทำงานกับไฟล์ (NIO.2) เวลา (java.time) และค่าที่เป็นทางเลือก (Optional) ได้ถูกปรับปรุงใหม่

คุณสมบัติหลักของไลบรารี Joda-Time

Joda-Time มีชุดความสามารถที่ไม่สามารถใช้ได้ในไลบรารีมาตรฐานก่อน Java 8 ข้อดีหลักรวมถึง การรองรับเขตเวลามากกว่า 200 เขต พร้อมการจัดการเวลาออมแสงอัตโนมัติ API การจัดรูปแบบที่หลากหลายพร้อมรูปแบบและตำแหน่งที่ตั้ง รวมถึงการคำนวณระยะเวลาระหว่างวันที่ในหน่วยต่าง ๆ — ปี เดือน วัน ชั่วโมง ระบบช่วงเวลาสมควรได้รับความสนใจเป็นพิเศษ: Interval (ช่วงระหว่างสองจุด), Period (ความแตกต่างในหน่วยปฏิทิน) และ Duration (ระยะเวลาที่แน่นอนในหน่วยมิลลิวินาที)

การจัดรูปแบบและการแยกวิเคราะห์

คลาส DateTimeFormatter ใน Joda-Time ให้การจัดรูปแบบวันที่ที่ปลอดภัยต่อเธรด — แตกต่างจาก java.text.SimpleDateFormat สามารถสร้างตัวจัดรูปแบบผ่านรูปแบบ (เช่น “yyyy-MM-dd HH:mm:ss”) หรือผ่านสไตล์ (SHORT, MEDIUM, LONG, FULL) สำหรับเอาต์พุตที่ปรับตามท้องถิ่น ไลบรารียังรองรับการแคชตัวจัดรูปแบบ ซึ่งช่วยเร่งการทำงานในแอปพลิเคชันที่มีโหลดสูง การแยกวิเคราะห์วันที่จากสตริงทำได้ด้วยการควบคุมความเข้มงวด — สามารถอนุญาตหรือปฏิเสธวันที่ที่ไม่สมบูรณ์หรือไม่ถูกต้อง

ช่วงเวลาและการคำนวณ

จุดแข็งประการหนึ่งของ Joda-Time คือการทำงานกับช่วงเวลา คลาส Interval แทนช่วงเวลาที่แน่นอนระหว่างสองจุด (Instant) และรองรับการดำเนินการตัดกัน การรวม และการตรวจสอบการเป็นสมาชิก Period แตกต่างจาก Interval ตรงที่ทำงานกับหน่วยปฏิทิน — ตัวอย่างเช่น ความแตกต่างระหว่างวันที่ 1 มีนาคมถึง 1 เมษายนคือ 1 เดือนพอดี แม้ว่าตามระยะเวลาอาจเป็น 28–31 วัน ส่วน Duration แทนระยะเวลาที่แน่นอนในหน่วยมิลลิวินาทีโดยไม่ผูกกับปฏิทิน และเหมาะสำหรับการวัดเวลาดำเนินการ

java
import org.joda.time.*;
import org.joda.time.format.*;

DateTime now = new DateTime();
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
String formatted = fmt.print(now);

DateTime nextWeek = now.plusWeeks(1);
Period period = new Period(now, nextWeek);
int days = period.getDays(); // วัน = 7

Interval interval = new Interval(now, nextWeek);
boolean contains = interval.contains(now); // จริง

การเปรียบเทียบ Joda-Time และ java.time

แพ็คเกจ java.time (JSR-310) ได้รับการพัฒนาโดยผู้เขียนคนเดียวกัน — Stephen Colebourne — และรวบรวมแนวคิดที่ดีที่สุดของ Joda-Time โดยคำนึงถึงประสบการณ์การใช้งานสิบปี API ทั้งสองใช้คลาส immutable รองรับเขตเวลา และมีชุดการดำเนินการที่หลากหลาย อย่างไรก็ตาม java.time ถูกรวมเข้ากับไลบรารีมาตรฐานของ Java อย่างสมบูรณ์ ไม่ต้องการการพึ่งพาภายนอก และใช้ระบบการตั้งชื่อที่สอดคล้องมากขึ้น: Instant แทน ReadableInstant, LocalDate แทน LocalDate (ชื่อคงเดิม), ZonedDateTime แทน DateTime

คุณลักษณะJoda-Timejava.time
ปีที่เปิดตัว20042014 (Java 8)
สถานะบำรุงรักษากำลังพัฒนาอย่างแข็งขัน
วันที่/เวลาหลักDateTimeZonedDateTime
เฉพาะวันที่LocalDateLocalDate
ความไม่เปลี่ยนแปลงใช่ใช่
การจัดรูปแบบDateTimeFormatterDateTimeFormatter
ความแตกต่างของวันที่Period / DurationPeriod / Duration

ความแตกต่างหลัก

java.time แก้ไขการตัดสินใจทางสถาปัตยกรรมหลายอย่างของ Joda-Time ประการแรก ใน java.time ความสับสนระหว่างวิธีการที่คืนค่า null และค่าที่ไม่มีอยู่ถูกกำจัด — แทนที่จะใช้ Optional ประการที่สอง เพิ่มการรองรับระบบปฏิทินทางเลือก (ญี่ปุ่น ไทย อิสลาม) ผ่านอินเทอร์เฟซ Chronology ประการที่สาม java.time มีคลาส Instant สำหรับการทำงานกับจุดเวลาใน UTC โดยไม่ผูกกับปฏิทิน — ซึ่งช่วยลดความซับซ้อนในการรวมกับโปรโตคอลเครือข่ายและฐานข้อมูล สำหรับ Android แนะนำให้ใช้ java.time ตั้งแต่ API 26 (Android 8.0) หรือผ่าน desugaring สำหรับเวอร์ชันที่เก่ากว่า

การย้ายจาก Joda-Time ไปยัง java.time

การย้ายจาก Joda-Time ไปยัง java.time — เป็นกระบวนการที่ผู้เขียนไลบรารีพยายามทำให้ปลอดภัยและคาดเดาได้มากที่สุด คลาสส่วนใหญ่มีสิ่งที่เทียบเท่าโดยตรง: DateTime → ZonedDateTime, LocalDate → LocalDate (ชื่อตรงกัน), LocalTime → LocalTime, DateTimeZone → ZoneId, Period → Period, Duration → Duration การเปลี่ยนแปลงหลักเกี่ยวข้องกับวิธีการสร้างออบเจกต์และชื่อของเมธอด — ตัวอย่างเช่น แทนที่ `now.toDate()` ใช้ `Date.from(instant)` และ `DateTime.now()` ถูกแทนที่ด้วย `ZonedDateTime.now()`

กลยุทธ์การย้ายทีละขั้นตอน

แนะนำให้เริ่มการย้ายโดยแยก Joda-Time ออกเป็นชั้นนามธรรมแบบบาง — ซึ่งจะช่วยให้สามารถเปลี่ยนไลบรารีเป็นระยะ ๆ โดยไม่กระทบต่อฐานโค้ดทั้งหมด ขั้นตอนแรกมักจะเปลี่ยนการทำงานกับ LocalDate และ LocalTime — คลาสเหล่านี้มีความแตกต่างน้อยที่สุดระหว่างไลบรารี ขั้นตอนที่สองย้าย DateTime (เป็น ZonedDateTime) และเขตเวลา ขั้นตอนที่สามเปลี่ยน Interval, Period และ Duration — ที่นี่ต้องตรวจสอบพฤติกรรมอย่างระมัดระวังโดยคำนึงถึงเวลาออมแสง หลังจากเสร็จสิ้นการย้าย Joda-Time จะถูกลบออกจากการพึ่งพาของโปรเจกต์อย่างสมบูรณ์

kotlin
// Joda-Time (ก่อนการย้าย)
val dateTime = DateTime.now(DateTimeZone.forID("Europe/Moscow"))
val formatted = dateTime.toString("dd.MM.yyyy")
val plusDay = dateTime.plusDays(1)

// java.time (หลังการย้าย)
val zonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Moscow"))
val formatted2 = zonedDateTime.format(
    DateTimeFormatter.ofPattern("dd.MM.yyyy")
)
val plusDay2 = zonedDateTime.plusDays(1)

เครื่องมือสำหรับการย้าย

มียูทิลิตี้หลายอย่างที่ช่วยให้การเปลี่ยนจาก Joda-Time ไปยัง java.time ง่ายขึ้น OpenRewrite (โดย Moderne) รองรับการย้ายอัตโนมัติผ่าน recipe org.openrewrite.java.migrate.JodaTimeToJavaTime — ซึ่งเปลี่ยนคลาส เมธอด และ imports โดยคงตรรกะของโปรแกรมไว้ สำหรับโปรเจกต์ Gradle ปลั๊กอิน de.fayard.refreshVersions ก็รวมกฎการย้ายไว้ด้วย การย้ายด้วยตนเองทำได้ง่ายที่สุดด้วย IDEA: ปลั๊กอิน Java Time Migration Assistant จะเน้นการเรียก Joda-Time และเสนอการแทนที่ที่สอดคล้องกันใน java.time ซึ่งทำให้กระบวนการเร็วขึ้น 2–3 เท่าเมื่อเทียบกับการแทนที่ด้วยตนเอง

ตัวอย่างโค้ดของ Joda-Time

มาดูตัวอย่างการทำงานจริงกับ Joda-Time ในแอปพลิเคชัน Android กัน ไลบรารีมีประโยชน์อย่างยิ่งสำหรับงานจัดรูปแบบวันที่ตามมาตรฐานท้องถิ่น การคำนวณอายุผู้ใช้ การกำหนดระยะเวลาของกิจกรรม และการคำนวณช่วงระหว่างวันที่สองวัน ตัวอย่างทั้งหมดใช้ออบเจกต์ immutable — การเรียกแต่ละครั้งจะคืนค่าอินสแตนซ์ใหม่ ในขณะที่ออบเจกต์ดั้งเดิมยังคงไม่เปลี่ยนแปลง

kotlin
// คำนวณอายุผู้ใช้
val birthDate = LocalDate.parse("1990-05-15")
val today = LocalDate.now()
val age = Years.yearsBetween(birthDate, today).getYears()
// อายุ == 36

// จัดรูปแบบตามตำแหน่งที่ตั้งของผู้ใช้
val dateTime = DateTime.now()
val formatter = DateTimeFormat.forStyle("MM").withLocale(Locale.getDefault())
val localized = formatter.print(dateTime)

การทำงานกับช่วงเวลา

ช่วงเวลาใน Joda-Time ช่วยแก้ปัญหาการตรวจสอบการทับซ้อนของช่วงเวลา การคำนวณการซ้อนทับ และการค้นหาเหตุการณ์ที่ใกล้ที่สุดได้อย่างมีประสิทธิภาพ ตัวอย่างเช่น เมื่อพัฒนาแอปพลิเคชันปฏิทิน สามารถตรวจสอบได้ว่าเหตุการณ์ใหม่ทับซ้อนกับเหตุการณ์ที่มีอยู่แล้วหรือไม่ คลาส Interval รองรับการดำเนินการ contains, overlaps, gap และ abuts — อย่างสุดท้ายแสดงว่าช่วงเวลาสัมผัสกันที่ขอบเขตหรือไม่ สำหรับการวัดระยะเวลาระหว่างสองจุด จะใช้ Duration ด้วยความแม่นยำถึงมิลลิวินาที

java
// ตรวจสอบการทับซ้อนของช่วงเวลา
Interval meeting1 = new Interval(
    new DateTime(2026, 7, 21, 10, 0),
    new DateTime(2026, 7, 21, 11, 0)
);
Interval meeting2 = new Interval(
    new DateTime(2026, 7, 21, 10, 30),
    new DateTime(2026, 7, 21, 11, 30)
);

boolean overlaps = meeting1.overlaps(meeting2); // จริง
Duration gap = meeting1.gap(meeting2); // null (ไม่มีช่องว่าง)

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

Joda-Time คืออะไรและจำเป็นอย่างไร

Joda-Time — ไลบรารีสำหรับทำงานกับวันที่และเวลาใน Java สร้างขึ้นก่อน Java 8 จะออก มันแก้ไขข้อบกพร่องของ java.util.Date และ java.util.Calendar: ความไม่แน่นอน (mutability) การนับเดือนจาก 0 การขาดการรองรับเขตเวลาอย่างสมบูรณ์ และการจัดรูปแบบที่ไม่ปลอดภัยต่อเธรด

Joda-Time แตกต่างจาก java.time อย่างไร

java.time (JSR-310) — ผู้สืบทอดของ Joda-Time พัฒนาโดยผู้เขียนคนเดียวกัน ความแตกต่างหลัก: java.time ถูกรวมอยู่ใน ไลบรารีมาตรฐานของ Java 8+ ใช้ระบบการตั้งชื่อที่สอดคล้องมากขึ้น รองรับระบบปฏิทินทางเลือก และรวมคลาส Instant สำหรับการทำงานกับเวลา UTC

ควรใช้ Joda-Time ในโปรเจกต์ใหม่หรือไม่

ไม่ สำหรับโปรเจกต์ใหม่แนะนำให้ใช้ java.time Joda-Time อยู่ในโหมดบำรุงรักษาตั้งแต่ปี 2014 และไม่ได้รับฟีเจอร์ใหม่อีกต่อไป สำหรับ Android ที่ API 26+ java.time พร้อมใช้งานโดยตรง และสำหรับเวอร์ชันที่เก่ากว่าจะใช้ desugaring — กลไกที่ช่วยให้ใช้ java.time บนอุปกรณ์ที่ใช้ API 19+

จะย้ายโค้ดจาก Joda-Time ไปยัง java.time ได้อย่างไร

การย้ายทำเป็นขั้นตอน: แยก Joda-Time ออกเป็น abstraction layer, เปลี่ยน LocalDate และ LocalTime ก่อน, จากนั้น DateTime → ZonedDateTime, และขั้นตอนสุดท้ายคือ Period, Duration และ Interval เครื่องมือ OpenRewrite รองรับการย้ายอัตโนมัติผ่าน recipe JodaTimeToJavaTime ซึ่งทำให้กระบวนการเร็วขึ้น 2–3 เท่า

คลาสใดของ Joda-Time ที่สอดคล้องกับ java.time

DateTime → ZonedDateTime, LocalDate → LocalDate (ตรงกัน), LocalTime → LocalTime, LocalDateTime → LocalDateTime, DateTimeZone → ZoneId, Interval — ไม่มีสิ่งที่เทียบเท่าโดยตรง (ใช้การรวมกันของ Instant + Duration), Period → Period, Duration → Duration ชื่อเมธอดก็ใกล้เคียงกัน: plusDays, minusMonths, withZone พร้อมใช้งานในทั้งสองไลบรารี

สรุป

  • Joda-Time — ไลบรารีวันที่และเวลาสำหรับ Java ที่กลายเป็นมาตรฐานก่อน Java 8 และมีผลโดยตรงต่อข้อกำหนด JSR-310
  • การออกแบบ Immutable — คลาสทั้งหมดของ Joda-Time ไม่สามารถเปลี่ยนแปลงได้ ซึ่งรับประกันความปลอดภัยของเธรดและป้องกันการเปลี่ยนแปลงออบเจกต์โดยไม่ตั้งใจ
  • คลาสหลัก — DateTime, LocalDate, LocalTime, LocalDateTime, Period, Duration และ Interval ครอบคลุมทุกสถานการณ์การทำงานกับวันที่และเวลา
  • การรองรับเขตเวลา — ฐานข้อมูลในตัวของ 200+ โซน พร้อมการจัดการเวลาออมแสงอัตโนมัติและการอัปเดต
  • การย้ายไปยัง java.time — แนะนำสำหรับทุกโปรเจกต์; ทำเป็นขั้นตอน โดยใช้เครื่องมือ OpenRewrite และเครื่องมือในตัวของ IDE
  • ความเข้ากันได้กับ Android — Joda-Time ทำงานตั้งแต่ API 1 แต่สำหรับ API 26+ ควรใช้ java.time ซึ่งพร้อมใช้งานผ่าน desugaring ในเวอร์ชันที่เก่ากว่า
  • ความสำคัญทางประวัติศาสตร์ — Joda-Time เปลี่ยนวิธีการออกแบบ API ใน Java และแสดงให้ชุมชนเห็นถึงข้อดีของ immutable value-objects

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม