Joda-Time হলো Java-তে তারিখ এবং সময় নিয়ে কাজ করার জন্য একটি লাইব্রেরি, যা Stephen Colebourne জটিল java.util.Date এবং java.util.Calendar-এর বিকল্প হিসেবে তৈরি করেছিলেন। Java 8 প্রকাশের আগে, এই লাইব্রেরিটি শিল্প বিকাশে, Android অ্যাপ্লিকেশন সহ, তারিখ পরিচালনার জন্য ডি ফ্যাক্টো স্ট্যান্ডার্ড ছিল। Oracle Java Magazine (2023) অনুসারে, Android API 26 প্রকাশের দুই বছরের মধ্যে 60% এর বেশি প্রকল্প Joda-Time থেকে java.time-এমাইগ্রেশন করেছে।
মূল বিষয়
Joda-Time একটি ওপেন-সোর্স লাইব্রেরি (Apache 2.0) যা Java ভাষায় java.util.Date এবং java.util.Calendar ক্লাসের জন্য একটি গুণগত প্রতিস্থাপন প্রদান করে। প্রকল্পটি Stephen Colebourne 2004 সালে স্ট্যান্ডার্ড তারিখ এবং সময় API-র অসংখ্য সমস্যার প্রতিক্রিয়ায় প্রতিষ্ঠা করেছিলেন, যার মধ্যে পরিবর্তনশীলতা, ফর্ম্যাটিং জটিলতা এবং সীমিত টাইমজোন সমর্থন অন্তর্ভুক্ত ছিল। লাইব্রেরিটি Java সম্প্রদায়ে ব্যাপকভাবে গৃহীত হয়েছিল এবং হাজার হাজার প্রকল্প দ্বারা ব্যবহৃত হয়েছিল, যার মধ্যে বড় এন্টারপ্রাইজ সিস্টেম এবং Android অ্যাপ্লিকেশন অন্তর্ভুক্ত ছিল, যেখানে অন্তর্নির্মিত তারিখ পরিচালনার সরঞ্জামগুলি বিশেষভাবে অসুবিধাজনক ছিল। 2014 সালে Java 8 প্রকাশ এবং java.time প্যাকেজ (JSR-310) প্রবর্তনের পর থেকে, লাইব্রেরিটি রক্ষণাবেক্ষণ মোডে রাখা হয়েছে — নতুন বৈশিষ্ট্য যোগ করা হচ্ছে না, এবং বিদ্যমান কার্যকারিতা নতুন API দ্বারা সম্পূর্ণরূপে আচ্ছাদিত।
Joda-Time অপরিবর্তনীয়তার নীতির উপর নির্মিত: তৈরি করার পরে প্রতিটি তারিখ বা সময় অবজেক্ট পরিবর্তন করা যায় না। যেকোনো অপারেশন — একটি দিন যোগ করা, মাস পরিবর্তন করা, টাইমজোন সেট করা — একটি নতুন অবজেক্ট ফেরত দেয়, আসলটি অপরিবর্তিত রেখে। এই পদ্ধতি অবজেক্টের অনিচ্ছাকৃত পরিবর্তনের সাথে যুক্ত ত্রুটির শ্রেণীকে সম্পূর্ণরূপে দূর করে যা পরিবর্তনশীল java.util.Date এবং java.util.Calendar-এর বৈশিষ্ট্য ছিল। অপরিবর্তনীয় ডিজাইন অতিরিক্ত সিঙ্ক্রোনাইজেশন ছাড়াই লাইব্রেরিটিকে থ্রেড-নিরাপদ করে তোলে।
লাইব্রেরি বিভিন্ন পরিস্থিতির জন্য বেশ কয়েকটি প্রধান ক্লাস প্রদান করে: DateTime — টাইমজোন সহ সম্পূর্ণ তারিখ এবং সময়, LocalDate — সময় ছাড়া শুধুমাত্র তারিখ, LocalTime — তারিখ ছাড়া শুধুমাত্র সময়, LocalDateTime — টাইমজোন বাঁধাই ছাড়া তারিখ এবং সময়। অতিরিক্তভাবে, ব্যবধান (Interval), সময়কাল (Period) এবং সময়সীমা (Duration) নিয়ে কাজ করার জন্য ক্লাস অন্তর্ভুক্ত করা হয়েছে, যা আপনাকে পরিমাপের বিভিন্ন এককে সময়ের দুটি বিন্দুর মধ্যে পার্থক্য গণনা করতে দেয়। প্রতিটি ক্লাস অভিন্ন হ্যান্ডলিংয়ের জন্য ReadableInstant বা ReadablePartial ইন্টারফেস প্রয়োগ করে।
Java-তে স্ট্যান্ডার্ড তারিখ API-র সমস্যা প্ল্যাটফর্মের শুরু থেকেই জানা ছিল। java.util.Date এবং java.util.Calendar ক্লাসের মৌলিক ত্রুটি ছিল: মাস 0 থেকে সংখ্যায়িত হত, Date একসঙ্গে তারিখ এবং সময় উভয়ই উপস্থাপন করত, Calendar পরিবর্তনশীল ছিল এবং জটিল কনফিগারেশনের প্রয়োজন হত। SimpleDateFormat-এর মাধ্যমে ফর্ম্যাটিং থ্রেড-নিরাপদ ছিল না — মাল্টিথ্রেডেড অ্যাপ্লিকেশনে এটি ভুল তারিখ পার্সিংয়ের দিকে নিয়ে যেত। Stephen Colebourne, তারিখের নিবিড় ব্যবহার সহ প্রকল্পগুলিতে কাজ করে, একটি বিকল্প তৈরি করার সিদ্ধান্ত নেন যা এই সমস্ত সমস্যা সমাধান করবে।
InfoQ (2014) এ একটি সাক্ষাৎকার অনুসারে, Colebourne প্রথম পাবলিক রিলিজের আগে এক বছরেরও বেশি সময় ধরে উত্পাদন প্রকল্পে Joda-Time পরীক্ষা করেছিলেন। প্রথম সংস্করণটি 2004 সালে প্রকাশিত হয়েছিল এবং অবিলম্বে সম্প্রদায়ের দৃষ্টি আকর্ষণ করেছিল। 2010 সালের মধ্যে, লাইব্রেরিটি Spring এবং Hibernate-এর মতো ফ্রেমওয়ার্ক সহ বেশিরভাগ Java প্রকল্পে একটি স্ট্যান্ডার্ড নির্ভরতা হয়ে উঠেছিল। Joda-Time-এর সাফল্য সরাসরি JSR-310 স্পেসিফিকেশন (Date and Time API) কে প্রভাবিত করেছিল, যা Java 8-এ অন্তর্ভুক্ত হয়েছিল — একই Stephen Colebourne স্পেসিফিকেশন লিড হিসাবে।
Joda-Time শুধু তারিখের সমস্যা সমাধান করেনি — এটি Java-তে API ডিজাইনের পদ্ধতি পরিবর্তন করেছে। অপরিবর্তনীয় মান অবজেক্টের ধারণা, যা লাইব্রেরি দ্বারা প্রদর্শিত হয়েছিল, Java 8-এ সমস্ত নতুন API-র জন্য একটি মান হিসাবে গৃহীত হয়েছিল। তাছাড়া, Joda-Time-এর জনপ্রিয়তা Oracle-কে দেখিয়েছিল যে সম্প্রদায় নিম্ন-মানের স্ট্যান্ডার্ড লাইব্রেরি সহ্য করতে প্রস্তুত নয় — Joda-Time-এর পরে, Java-তে ফাইল হ্যান্ডলিং (NIO.2), সময় (java.time) এবং ঐচ্ছিক মান (Optional) এর জন্য API পুনরায় ডিজাইন করা হয়েছিল।
Joda-Time বৈশিষ্ট্যগুলির একটি সেট প্রদান করে যা Java 8-এর আগে স্ট্যান্ডার্ড লাইব্রেরিতে অনুপলব্ধ ছিল। প্রধান সুবিধার মধ্যে রয়েছে স্বয়ংক্রিয় ডেলাইট সেভিং টাইম হ্যান্ডলিং সহ 200+ টাইমজোনের জন্য সমর্থন, প্যাটার্ন এবং লোকেল সহ একটি সমৃদ্ধ ফর্ম্যাটিং API, পাশাপাশি বিভিন্ন এককে — বছর, মাস, দিন, ঘন্টা — তারিখের মধ্যে সময়কাল গণনা। বিশেষ উল্লেখের দাবি রাখে ব্যবধান সিস্টেম: Interval (দুটি মুহূর্তের মধ্যে একটি ব্যবধান), Period (ক্যালেন্ডার এককে পার্থক্য) এবং Duration (মিলিসেকেন্ডে সঠিক দৈর্ঘ্য)।
Joda-Time-এ DateTimeFormatter ক্লাস থ্রেড-নিরাপদ তারিখ ফর্ম্যাটিং প্রদান করে — java.text.SimpleDateFormat-এর বিপরীতে। ফর্ম্যাটার প্যাটার্নের মাধ্যমে (যেমন, “yyyy-MM-dd HH:mm:ss”) বা স্থানীয় আউটপুটের জন্য শৈলীর মাধ্যমে (SHORT, MEDIUM, LONG, FULL) তৈরি করা যেতে পারে। লাইব্রেরি ফর্ম্যাটার ক্যাশিংও সমর্থন করে, যা উচ্চ-লোড অ্যাপ্লিকেশনে কর্মক্ষমতা গতি বাড়ায়। স্ট্রিং থেকে তারিখ পার্সিং কঠোরতা নিয়ন্ত্রণের সাথে সঞ্চালিত হয় — আপনি অসম্পূর্ণ বা ভুল তারিখ অনুমতি বা অস্বীকার করতে পারেন।
Joda-Time-এর শক্তিশালী দিকগুলির মধ্যে একটি হলো সময়ের ব্যবধান নিয়ে কাজ করা। Interval ক্লাস দুটি মুহূর্তের মধ্যে একটি সঠিক সময়ের ব্যবধান উপস্থাপন করে এবং ছেদ, মিলন এবং ধারণ পরীক্ষার অপারেশন সমর্থন করে। Period, Interval-এর বিপরীতে, ক্যালেন্ডার এককে কাজ করে — উদাহরণস্বরূপ, 1 মার্চ এবং 1 এপ্রিলের মধ্যে পার্থক্য ঠিক 1 মাস, যদিও সময়কালে এটি 28–31 দিন হতে পারে। Duration, অন্যদিকে, ক্যালেন্ডার বাঁধাই ছাড়া মিলিসেকেন্ডে সঠিক দৈর্ঘ্য উপস্থাপন করে এবং অপারেশন নির্বাহের সময় পরিমাপের জন্য উপযুক্ত।
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); // সত্য
java.time প্যাকেজ (JSR-310) একই লেখক — Stephen Colebourne — দ্বারা তৈরি করা হয়েছিল এবং দশ বছরের অপারেশনাল অভিজ্ঞতার সাথে Joda-Time-এর সেরা ধারণাগুলিকে অন্তর্ভুক্ত করেছিল। উভয় API অপরিবর্তনীয় ক্লাস ব্যবহার করে, টাইমজোন সমর্থন করে এবং অপারেশনের একটি সমৃদ্ধ সেট প্রদান করে। তবে, java.time Java স্ট্যান্ডার্ড লাইব্রেরিতে সম্পূর্ণরূপে সংহত, কোনো বাহ্যিক নির্ভরতার প্রয়োজন হয় না এবং আরও ধারাবাহিক নামকরণ পদ্ধতি ব্যবহার করে: ReadableInstant-এর পরিবর্তে Instant, LocalDate-এর পরিবর্তে LocalDate (নাম সংরক্ষিত), DateTime-এর পরিবর্তে ZonedDateTime।
| বৈশিষ্ট্য | Joda-Time | java.time |
|---|---|---|
| প্রকাশের বছর | 2004 | 2014 (Java 8) |
| অবস্থা | রক্ষণাবেক্ষণ | সক্রিয় বিকাশ |
| বেস তারিখ/সময় | DateTime | ZonedDateTime |
| শুধুমাত্র তারিখ | LocalDate | LocalDate |
| অপরিবর্তনীয়তা | হ্যাঁ | হ্যাঁ |
| ফর্ম্যাটিং | DateTimeFormatter | DateTimeFormatter |
| তারিখের পার্থক্য | Period / Duration | Period / Duration |
java.time Joda-Time-এর বেশ কয়েকটি আর্কিটেকচারাল সিদ্ধান্ত সংশোধন করে। প্রথমত, java.time null ফেরত দেওয়া পদ্ধতি এবং অনুপস্থিত মানগুলির মধ্যে বিভ্রান্তি দূর করে — পরিবর্তে Optional ব্যবহার করে। দ্বিতীয়ত, Chronology ইন্টারফেসের মাধ্যমে বিকল্প ক্যালেন্ডার সিস্টেম (জাপানি, থাই, ইসলামিক) এর জন্য সমর্থন যুক্ত করা হয়েছে। তৃতীয়ত, java.time-এ ক্যালেন্ডার বাঁধাই ছাড়া UTC সময়ের মুহূর্ত নিয়ে কাজ করার জন্য Instant ক্লাস অন্তর্ভুক্ত রয়েছে — এটি নেটওয়ার্ক প্রোটোকল এবং ডেটাবেসের সাথে সংহতকরণকে সরল করে। Android-এর জন্য, API 26 (Android 8.0) থেকে শুরু করে java.time ব্যবহার করার সুপারিশ করা হয় বা পুরানো সংস্করণের জন্য desugaring-এর মাধ্যমে।
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 প্রকল্প নির্ভরতা থেকে সম্পূর্ণরূপে সরানো হয়।
// 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 দ্বারা) org.openrewrite.java.migrate.JodaTimeToJavaTime রেসিপির মাধ্যমে স্বয়ংক্রিয়মাইগ্রেশন সমর্থন করে — এটি প্রোগ্রাম লজিক সংরক্ষণ করে ক্লাস, পদ্ধতি এবং ইমপোর্ট প্রতিস্থাপন করে। Gradle প্রকল্পের জন্য, de.fayard.refreshVersions প্লাগইনেওমাইগ্রেশন নিয়ম অন্তর্ভুক্ত রয়েছে। ম্যানুয়ালি, IDEA-এর সাথেমাইগ্রেশন করা সবচেয়ে সহজ: Java Time Migration Assistant প্লাগইন Joda-Time কল হাইলাইট করে এবং java.time-এ সংশ্লিষ্ট প্রতিস্থাপনের পরামর্শ দেয়, যা ম্যানুয়াল প্রতিস্থাপনের তুলনায় প্রক্রিয়াটি 2–3 গুণ গতি বাড়ায়।
Android অ্যাপ্লিকেশনে Joda-Time-এর সাথে কাজ করার ব্যবহারিক উদাহরণ দেখি। লাইব্রেরিটি স্থানীয় মান অনুযায়ী তারিখ ফর্ম্যাট করা, ব্যবহারকারীর বয়স গণনা করা, ইভেন্টের সময়কাল নির্ধারণ এবং দুটি তারিখের মধ্যে ব্যবধান গণনার জন্য বিশেষভাবে উপযোগী। সমস্ত উদাহরণ অপরিবর্তনীয় অবজেক্ট ব্যবহার করে — প্রতিটি কল একটি নতুন ইনস্ট্যান্স ফেরত দেয়, যখন আসল অবজেক্ট অপরিবর্তিত থাকে।
// ব্যবহারকারীর বয়স গণনা করুন
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 দুটি মুহূর্তের মধ্যে দৈর্ঘ্য মিলিসেকেন্ড নির্ভুলতার সাথে পরিমাপ করতে ব্যবহৃত হয়।
// ব্যবধান ওভারল্যাপ পরীক্ষা করুন
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); // শূন্য (কোনো ফাঁক নেই)
প্রায়শই জিজ্ঞাসিত প্রশ্ন
Joda-Time Java-তে তারিখ এবং সময় নিয়ে কাজ করার জন্য একটি লাইব্রেরি, যা Java 8 প্রকাশের আগে তৈরি করা হয়েছিল। এটি java.util.Date এবং java.util.Calendar-এর ত্রুটিগুলি সংশোধন করেছে: পরিবর্তনশীলতা, 0 থেকে মাস সংখ্যা, সম্পূর্ণ টাইমজোন সমর্থনের অভাব এবং নন-থ্রেড-নিরাপদ ফর্ম্যাটিং।
Java.time (JSR-310) Joda-Time-এর উত্তরসূরি, একই লেখক দ্বারা বিকশিত। প্রধান পার্থক্য: java.time Java 8+ স্ট্যান্ডার্ড লাইব্রেরিতে অন্তর্নির্মিত, আরও ধারাবাহিক নামকরণ পদ্ধতি ব্যবহার করে, বিকল্প ক্যালেন্ডার সিস্টেম সমর্থন করে এবং UTC সময় নিয়ে কাজ করার জন্য Instant ক্লাস অন্তর্ভুক্ত করে।
না, নতুন প্রকল্পের জন্য java.time ব্যবহার করার সুপারিশ করা হয়। Joda-Time 2014 সাল থেকে রক্ষণাবেক্ষণ মোডে রয়েছে এবং আর নতুন বৈশিষ্ট্য পায় না। Android API 26+ এর জন্য, java.time নেটিভলি উপলব্ধ, এবং পুরানো সংস্করণের জন্য desugaring ব্যবহার করা হয় — একটি প্রক্রিয়া যা API 19+ ডিভাইসে java.time ব্যবহার করার অনুমতি দেয়।
মাইগ্রেশন ধাপে ধাপে করা হয়: Joda-Time-কে অ্যাবস্ট্রাকশনে আলাদা করুন, প্রথমে LocalDate এবং LocalTime প্রতিস্থাপন করুন, তারপর DateTime → ZonedDateTime, এবং শেষে Period, Duration এবং Interval। OpenRewrite সরঞ্জাম JodaTimeToJavaTime রেসিপির মাধ্যমে স্বয়ংক্রিয়মাইগ্রেশন সমর্থন করে, যা প্রক্রিয়াটি 2–3 গুণ গতি বাড়ায়।
DateTime → ZonedDateTime, LocalDate → LocalDate (মেলে), LocalTime → LocalTime, LocalDateTime → LocalDateTime, DateTimeZone → ZoneId, Interval → কোনো সরাসরি সমতুল্য নেই (Instant + Duration-এর সংমিশ্রণ ব্যবহার করা হয়), Period → Period, Duration → Duration। পদ্ধতির নামও একই রকম: plusDays, minusMonths, withZone উভয় লাইব্রেরিতে উপলব্ধ।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন