LocalDate, LocalTime এবং LocalDateTime হল java.time প্যাকেজের প্রধান ক্লাস যা সময় অঞ্চলের বাঁধন ছাড়াই তারিখ এবং সময় নিয়ে কাজ প্রদান করে। Oracle ডকুমেন্টেশন (Java 17, 2024) অনুসারে, এই টাইপগুলি immutable এবং thread-safe হিসেবে ডিজাইন করা হয়েছে, যা এগুলিকে মাল্টিথ্রেডেড অ্যাপ্লিকেশনের জন্য নিরাপদ করে তোলে। এগুলি Android-এ API 26 থেকে desugaring-এর মাধ্যমে এবং পুরানো সংস্করণগুলির জন্য — ThreeTenABP লাইব্রেরির মাধ্যমে উপলব্ধ হয়েছে।
মূল পয়েন্ট
LocalDate — একটি ক্লাস যা সময় এবং সময় অঞ্চলের তথ্য ছাড়াই বছর-মাস-দিন ফর্ম্যাটে তারিখ উপস্থাপন করে। এটি জন্মদিন, ইভেন্টের তারিখ বা মেয়াদ শেষ হওয়ার তারিখের মতো ডেটা সংরক্ষণ করতে ব্যবহৃত হয়।
LocalDate -999999999 থেকে +999999999 পর্যন্ত পরিসরে বছর, 1 থেকে 12 পর্যন্ত মাস এবং লিপ ইয়ার বিবেচনা করে মাসের দিন সংরক্ষণ করে। ক্লাসটি সম্পূর্ণ immutable — যেকোনো অপারেশন একটি নতুন অবজেক্ট ফেরত দেয়।
LocalTime দিনের সময় উপস্থাপন করে: ঘন্টা, মিনিট, সেকেন্ড এবং ন্যানোসেকেন্ড। সর্বোচ্চ নির্ভুলতা একটি ন্যানোসেকেন্ড পর্যন্ত। LocalTime-এ তারিখ বা সময় অঞ্চলের কোনো তথ্য নেই, যা এটিকে দোকান খোলার সময় বা প্রক্রিয়া সময় সংরক্ষণের জন্য সুবিধাজনক করে তোলে।
LocalDateTime LocalDate এবং LocalTime-কে একটি অবজেক্টে একত্রিত করে। এটি সবচেয়ে বেশি ব্যবহৃত টাইপ যখন আপনার তারিখ এবং সময় উভয়ই সংরক্ষণের প্রয়োজন হয়, কিন্তু সময় অঞ্চলের বাঁধনের প্রয়োজন নেই। উদাহরণস্বরূপ, স্থানীয় ফর্ম্যাটে একটি কনসার্টের তারিখ এবং সময়।
Oracle Java ডকুমেন্টেশন (2024) অনুসারে, তিনটি ক্লাসই Joda-Time লাইব্রেরির ধারণার উপর ভিত্তি করে ডিজাইন করা হয়েছে, কিন্তু উন্নত আর্কিটেকচার এবং স্ট্যান্ডার্ড লাইব্রেরিতে সম্পূর্ণ একীকরণ সহ।
java.time প্যাকেজ Java 8-এ পুরানো Date, Calendar এবং SimpleDateFormat ক্লাসের প্রতিস্থাপন হিসেবে আবির্ভূত হয়েছে। এর আর্কিটেকচার immutable অবজেক্ট এবং fluent-ইন্টারফেসের নীতির উপর নির্মিত।
মূল বৈশিষ্ট্য — সমস্ত প্রধান ক্লাস value-based। এর মানে হল তাদের ইনস্ট্যান্স মান অনুসারে তুলনা করা হয়, রেফারেন্স অনুসারে নয়, এবং সেগুলি ইনহেরিট করা যায় না। দুটি অবজেক্ট তুলনা করতে == অপারেটর নয়, equals মেথড ব্যবহার করুন।
প্যাকেজটি বেশ কয়েকটি বিভাগে বিভক্ত। সময় অঞ্চল ছাড়া টাইপ — LocalDate, LocalTime, LocalDateTime — স্থানীয় তারিখ এবং সময়ের জন্য ব্যবহৃত হয়। সময় অঞ্চল সহ টাইপ — ZonedDateTime, OffsetDateTime, OffsetTime — অফসেট বা অঞ্চলের তথ্য যোগ করে। ইনস্ট্যান্ট টাইপ — Instant — UTC-তে সময়রেখায় একটি বিন্দু উপস্থাপন করে।
এই বিভাজন পুরানো API-তে অন্তর্নিহিত সমস্যার সমাধান করে: ডেভেলপার কখনই জানত না যে Date অবজেক্টে সময় অঞ্চলের তথ্য আছে কি না। java.time-এ, প্রতিটি টাইপ স্পষ্টভাবে তার শব্দার্থ ঘোষণা করে।
LocalDate ক্লাস তারিখ তৈরি, পড়া এবং পরিবর্তনের জন্য অনেক মেথড প্রদান করে। বর্তমান তারিখ স্ট্যাটিক মেথড now() এর মাধ্যমে পাওয়া যায়। একটি নির্দিষ্ট তারিখ — of(int year, int month, int dayOfMonth) মেথডের মাধ্যমে।
তারিখের উপাদান পড়তে গেটার ব্যবহার করা হয়: getYear(), getMonthValue(), getDayOfMonth(), getDayOfWeek(), getDayOfYear()। getMonth() মেথড Month এনাম ফেরত দেয়, এবং getDayOfWeek() DayOfWeek এনাম ফেরত দেয়।
LocalDate তারিখ পরীক্ষা সমর্থন করে। isBefore(), isAfter() এবং isEqual() মেথডগুলি তারিখ তুলনা করার অনুমতি দেয়। isLeapYear() মেথড পরীক্ষা করে বছর লিপ ইয়ার কিনা। lengthOfMonth() মেথড মাসে দিনের সংখ্যা ফেরত দেয়, এবং lengthOfYear() বছরে দিনের সংখ্যা ফেরত দেয়।
পরিবর্তনের জন্য withYear(), withMonth(), withDayOfMonth() মেথড ব্যবহার করা হয়, যা পরিবর্তিত উপাদান সহ একটি নতুন অবজেক্ট ফেরত দেয়। plusDays(), minusMonths() এবং অনুরূপ মেথডগুলি তারিখ পাটিগণিত সম্পাদন করে।
LocalTime ন্যানোসেকেন্ড নির্ভুলতার সাথে দিনের সময় উপস্থাপন করে। স্ট্যান্ডার্ড ফর্ম্যাট ISO-8601 (HH:mm:ss.nnnnnnnnn)। ন্যূনতম মান 00:00, সর্বোচ্চ 23:59:59.999999999।
LocalTime অবজেক্ট now() দিয়ে বর্তমান সময়ের জন্য, of(int hour, int minute), of(int hour, int minute, int second) অথবা of(int hour, int minute, int second, int nanoOfSecond) দিয়ে তৈরি করা যায়। parse(CharSequence text) মেথড ISO-8601 ফর্ম্যাটে স্ট্রিং পার্স করে।
গেটারগুলির মধ্যে রয়েছে getHour(), getMinute(), getSecond(), getNano()। toSecondOfDay() মেথড দিনের শুরু থেকে সেকেন্ডের সংখ্যা ফেরত দেয়, এবং toNanoOfDay() ন্যানোসেকেন্ড ফেরত দেয়। এটি একটি দিনের মধ্যে সময়কাল গণনার জন্য সুবিধাজনক।
LocalTime LocalDate-এর মতো একই তুলনা এবং পরিবর্তন অপারেশন সমর্থন করে: plusHours(), minusMinutes(), withHour(), withMinute()। isBefore() এবং isAfter() মেথডগুলি বিবেচনা করে কাজ করে যে সময় একটি দিনের মধ্যে চক্রাকার।
LocalDateTime একটি ক্লাসে LocalDate এবং LocalTime-এর ক্ষমতা একত্রিত করে। এটি তারিখ এবং সময় উভয়ই সংরক্ষণ করে, কিন্তু সময় অঞ্চল ছাড়া। এটি সবচেয়ে নমনীয় স্থানীয় টাইপ, কিন্তু বিতরিত সিস্টেমে ব্যবহার করার সময় সতর্কতা প্রয়োজন।
LocalDateTime স্ট্যাটিক মেথড now(), of(LocalDate date, LocalTime time), of(int year, Month month, int dayOfMonth, int hour, int minute) এবং তাদের ওভারলোডের মাধ্যমে তৈরি করা যায়। LocalDate এবং LocalTime atTime() মেথডের মাধ্যমেও একত্রিত করা যায়।
LocalDateTime সংশ্লিষ্ট গেটারের মাধ্যমে সমস্ত তারিখ এবং সময় ফিল্ডে অ্যাক্সেস প্রদান করে: toLocalDate() এবং toLocalTime() পৃথক উপাদান ফেরত দেয়। truncatedTo(TemporalUnit unit) মেথড সময়কে নির্দিষ্ট নির্ভুলতায় গোল করতে দেয় — উদাহরণস্বরূপ, মিনিট পর্যন্ত।
সময় অঞ্চলে রূপান্তরের জন্য atZone(ZoneId zone) মেথড ব্যবহার করা হয়, যা ZonedDateTime ফেরত দেয়। LocalDateTime-এ সময় অঞ্চল যোগ করার এটাই একমাত্র উপায়।
তিনটি ক্লাসই স্ট্যাটিক ফ্যাক্টরি মেথডের মাধ্যমে একীভূত সৃষ্টি প্যাটার্ন ব্যবহার করে। ক্লাস কনস্ট্রাক্টর private হিসেবে ঘোষিত — new ব্যবহার করে সরাসরি অবজেক্ট তৈরি করা যায় না।
প্রধান সৃষ্টি মেথড:
of মেথডের অনেক ওভারলোড রয়েছে। LocalDate-এর জন্য বছর, মাস এবং দিন প্রয়োজন। LocalTime-এর জন্য — ঘন্টা এবং মিনিট (ঐচ্ছিকভাবে সেকেন্ড এবং ন্যানোসেকেন্ড)। LocalDateTime-এর জন্য — বছর, মাস, দিন, ঘন্টা, মিনিট। মাস int (1-12) অথবা Month এনাম হিসেবে পাস করা যায়।
val today = LocalDate.now()
val specificDate = LocalDate.of(2026, Month.JULY, 21)
val parsedDate = LocalDate.parse("2026-07-21")
val currentTime = LocalTime.now()
val lunchTime = LocalTime.of(13, 30, 0)
val parsedTime = LocalTime.parse("13:30:00")
val now = LocalDateTime.now()
val meeting = LocalDateTime.of(2026, 7, 21, 15, 0)
java.time ক্লাসগুলি একে অপরের মধ্যে সুবিধাজনক রূপান্তরের জন্য ডিজাইন করা হয়েছে। LocalDate atTime(LocalTime) অথবা atStartOfDay() মেথডের মাধ্যমে LocalDateTime-এ রূপান্তরিত করা যায়। LocalTime — atDate(LocalDate) এর মাধ্যমে।
LocalDateTime toLocalDate() এর মাধ্যমে LocalDate-এ এবং toLocalTime() এর মাধ্যমে LocalTime-এ ফিরে রূপান্তরিত করা যায়। ZonedDateTime-এ রূপান্তরের জন্য atZone(ZoneId) মেথড ব্যবহার করা হয়।
java.util.Date-এ রূপান্তর (পুরানো কোডের সাথে সামঞ্জস্যের জন্য) Instant এবং সময় অঞ্চলের মাধ্যমে একটি মধ্যবর্তী ধাপ প্রয়োজন। Baeldung (2024) অনুসারে, এই অপারেশন Date.from(instant) এর মাধ্যমে সম্পাদিত হয়।
val date = LocalDate.of(2026, 7, 21)
val dateTime = date.atTime(LocalTime.of(10, 30))
val time = LocalTime.of(14, 0)
val dateTimeFromTime = time.atDate(date)
val extractedDate = dateTime.toLocalDate()
val extractedTime = dateTime.toLocalTime()
val zoned = dateTime.atZone(ZoneId.of("Europe/Moscow"))
ফর্ম্যাটিং এবং পার্সিংয়ের জন্য DateTimeFormatter ক্লাস ব্যবহার করা হয়। এটি ধ্রুবক (ISO_LOCAL_DATE, ISO_LOCAL_TIME, ISO_LOCAL_DATE_TIME) এর মাধ্যমে পূর্বনির্ধারিত ফর্ম্যাট এবং প্যাটার্ন স্ট্রিংয়ের মাধ্যমে কাস্টম ফর্ম্যাট তৈরি করার ক্ষমতা প্রদান করে।
ফর্ম্যাটিং প্যাটার্ন প্রতীক ব্যবহার করে: yyyy — বছর, MM — মাস (দুই অঙ্ক), dd — দিন, HH — ঘন্টা (0-23), mm — মিনিট, ss — সেকেন্ড। format() মেথড তারিখ-সময় অবজেক্টে বা DateTimeFormatter-এর মাধ্যমে কল করা হয়।
DateTimeFormatter স্ট্যাটিক মেথড ofLocalizedDate(FormatStyle), ofLocalizedTime(FormatStyle) এবং ofLocalizedDateTime(FormatStyle) এর মাধ্যমে স্থানীয়করণও সমর্থন করে। উপলব্ধ শৈলীগুলি হল SHORT, MEDIUM, LONG এবং FULL।
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
val formatted = LocalDateTime.now().format(formatter)
val parsed = LocalDate.parse(
"21.07.2026",
DateTimeFormatter.ofPattern("dd.MM.yyyy")
)
তিনটি ক্লাসই Comparable ইন্টারফেস বাস্তবায়ন করে, যা তাদের প্রাকৃতিকভাবে তুলনা করার অনুমতি দেয়। compareTo() মেথড ক্রম অনুসারে ঋণাত্মক সংখ্যা, শূন্য বা ধনাত্মক সংখ্যা ফেরত দেয়। isBefore(), isAfter() এবং isEqual() মেথডগুলি বুলিয়ান ফেরত দেয়।
LocalDate-এর জন্য, তুলনা কালানুক্রমিক — আগের তারিখ ছোট বিবেচিত হয়। LocalTime-এর জন্য — দিনের সময় অনুসারে। LocalDateTime-এর জন্য — প্রথমে তারিখ অনুসারে, তারপর সময় অনুসারে। সমস্ত তুলনা লিপ ইয়ার এবং মাসে দিনের সংখ্যা সঠিকভাবে বিবেচনা করে।
পুরানো API থেকে একটি গুরুত্বপূর্ণ পার্থক্য: LocalDate, LocalTime এবং LocalDateTime-এর জন্য equals() মান তুলনা করে, রেফারেন্স নয়। এর মানে একই ফিল্ডযুক্ত দুটি অবজেক্ট সমান হবে, এমনকি যদি সেগুলি ভিন্ন ইনস্ট্যান্স হয়।
val d1 = LocalDate.of(2026, 7, 21)
val d2 = LocalDate.of(2026, 12, 25)
if (d1.isBefore(d2)) {
Log.d("তারিখ", "d1, d2-এর আগে")
}
val sortedDates = listOf(d2, d1).sorted()
তিনটি ক্লাসই plus এবং minus মেথডের মাধ্যমে পাটিগণিত অপারেশন সমর্থন করে। LocalDate-এর জন্য plusDays(), plusWeeks(), plusMonths(), plusYears() এবং সংশ্লিষ্ট minus মেথড উপলব্ধ। LocalTime plusHours(), plusMinutes(), plusSeconds(), plusNanos() সমর্থন করে।
LocalDateTime উভয় টাইপ থেকে সমস্ত পাটিগণিত অপারেশন উত্তরাধিকার সূত্রে পায়। LocalDate-এর একটি উল্লেখযোগ্য বৈশিষ্ট্য: এক মাস যোগ করার সময়, ফলাফল বিভিন্ন মাসের দৈর্ঘ্য সঠিকভাবে পরিচালনা করে। উদাহরণস্বরূপ, 31 জানুয়ারি + 1 মাস = 28 (লিপ ইয়ারে 29) ফেব্রুয়ারি।
আরও জটিল অপারেশনের জন্য Period ক্লাস (তারিখের জন্য) এবং Duration ক্লাস (সময়ের জন্য) বিদ্যমান। plus(TemporalAmount) এবং minus(TemporalAmount) মেথডগুলি এই অবজেক্টগুলি গ্রহণ করে।
val today = LocalDate.now()
val nextWeek = today.plusDays(7)
val nextMonth = today.plusMonths(1)
val lastYear = today.minusYears(1)
val now = LocalTime.now()
val inTwoHours = now.plusHours(2)
val halfHourAgo = now.minusMinutes(30)
আসুন একটি ব্যবহারিক উদাহরণ দেখি: কাজের শিফট ট্র্যাকিং অ্যাপ্লিকেশন। আমাদের শিফটের সময়কাল গণনা করতে এবং নির্ধারণ করতে হবে যে এটি রাতের সময়ে পড়ে কিনা। আমরা শুরুর এবং শেষের সময়ের জন্য LocalTime, তারিখের জন্য LocalDate এবং মধ্যরাত পার হওয়া শিফট গণনার জন্য LocalDateTime ব্যবহার করি।
data class Shift(
val startTime: LocalTime,
val endTime: LocalTime,
val date: LocalDate
) {
fun isOvernight(): Boolean = endTime.isBefore(startTime)
fun durationInMinutes(): Long {
val start = LocalDateTime.of(date, startTime)
val end = LocalDateTime.of(
if (isOvernight()) date.plusDays(1) else date,
endTime
)
return Duration.between(start, end).toMinutes()
}
}
দ্বিতীয় উদাহরণ — ব্যবহারকারীর বয়স গণনা। আমরা জন্ম তারিখের জন্য LocalDate ব্যবহার করি এবং জন্মের দিন এবং মাস বিবেচনা করে বর্তমান তারিখের সাথে তুলনা করি।
fun calculateAge(birthDate: LocalDate): Int {
val today = LocalDate.now()
val period = Period.between(birthDate, today)
return period.years
}
তৃতীয় উদাহরণ — বিজ্ঞপ্তি নিয়ে কাজ। LocalDateTime অনুস্মারক নির্ধারণের জন্য ব্যবহৃত হয়। আমরা পরীক্ষা করি নির্ধারিত সময় এসেছে কিনা।
data class Reminder(
val id: Long,
val scheduledAt: LocalDateTime
) {
fun isDue(): Boolean =
LocalDateTime.now().isAfter(scheduledAt)
}
java.time-এর জন্য অন্তর্নির্মিত সমর্থন Android-এ API 26 (Android 8.0 Oreo) থেকে উপস্থিত হয়েছে। পুরানো Android সংস্করণের ডিভাইসগুলির জন্য, desugaring ব্যবহার করা প্রয়োজন — একটি প্রক্রিয়া যা প্রাথমিক সংস্করণগুলিতে নতুন Java API-র জন্য সমর্থন যোগ করে।
Android Gradle Plugin-এ Desugaring build.gradle-এ compileOptions এর মাধ্যমে কনফিগার করা হয়। শুধু isCoreLibraryDesugaringEnabled = true সেট করুন এবং desugar_jdk_libs লাইব্রেরি যোগ করুন। এর পরে, java.time 14 থেকে শুরু করে সমস্ত API স্তরের জন্য উপলব্ধ হয়।
যে প্রকল্পগুলি desugaring ব্যবহার করতে পারে না (যেমন, AGP 4.0-এর নিচে উত্তরাধিকার প্রকল্প), তাদের জন্য ThreeTenABP লাইব্রেরি বিদ্যমান — java.time-এর একটি ব্যাকপোর্ট। এটি একই ক্লাস (LocalDate, LocalTime, LocalDateTime) প্রদান করে, কিন্তু org.threeten.bp প্যাকেজে।
@Suppress("UnstableApiUsage")
android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
"coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}
প্রথম সাধারণ ভুল — সময় অঞ্চল বিবেচনা না করে বিতরিত সিস্টেমে LocalDateTime ব্যবহার করা। যদি সার্ভার Europe/Moscow-এ এবং ক্লায়েন্ট Asia/Tokyo-তে হয়, LocalDateTime ভিন্নভাবে ব্যাখ্যা করা হবে। সমাধান: বৈশ্বিক ডেটার জন্য Instant বা ZonedDateTime ব্যবহার করুন।
দ্বিতীয় ভুল — ভুল স্ট্রিং পার্সিং। ডিফল্টরূপে, LocalDate.parse() ISO-8601 ফর্ম্যাট (yyyy-MM-dd) আশা করে। যদি স্ট্রিং ভিন্ন ফর্ম্যাটে হয়, আপনাকে স্পষ্টভাবে DateTimeFormatter পাস করতে হবে। আপনার DateTimeParseExceptionও হ্যান্ডল করা উচিত যাতে অ্যাপ্লিকেশনটি ভুল ইনপুটে ক্র্যাশ না হয়।
তৃতীয় ভুল — null নিরাপত্তা উপেক্ষা করা। LocalDate, LocalTime এবং LocalDateTime হল অবজেক্ট যা null হতে পারে। Kotlin-এ, স্পষ্ট পরীক্ষা বা Elvis অপারেটর সহ nullable টাইপ ব্যবহার করার পরামর্শ দেওয়া হয়। Java-তে — মেথড কল করার আগে null পরীক্ষা করুন।
চতুর্থ ভুল — LocalDateTime এবং ZonedDateTime-এর মধ্যে বিভ্রান্তি। LocalDateTime-এ সময় অঞ্চলের কোনো তথ্য নেই। আপনার যদি সময়ে একটি পরম মুহূর্ত প্রেরণের প্রয়োজন হয় — জোনাল টাইপ ব্যবহার করুন। যদি স্থানীয় সময় যথেষ্ট হয় — স্থানীয় টাইপ ব্যবহার করুন।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
Date 1970-01-01 UTC থেকে মিলিসেকেন্ডের সংখ্যা সংরক্ষণ করে, যেখানে LocalDate সময় অঞ্চলের বাঁধন ছাড়াই বছর, মাস এবং দিন সংরক্ষণ করে। Date পরিবর্তনযোগ্য এবং thread-safe নয়, LocalDate অপরিবর্তনীয় এবং thread-safe। Date Java 8 থেকে অপ্রচলিত।
হ্যাঁ, LocalDateTime SQL টাইপ TIMESTAMP WITHOUT TIME ZONE-এ ভালভাবে ম্যাপ হয়। JPA এবং Room TypeConverter-এর মাধ্যমে এটি সমর্থন করে। TIMESTAMP WITH TIME ZONE-এর জন্য, ZonedDateTime বা OffsetDateTime ব্যবহার করুন।
ChronoUnit.DAYS.between(startDate, endDate) ব্যবহার করুন। এই মেথডটি long ফেরত দেয় — দিনের পার্থক্য। আরও বিস্তারিত গণনার জন্য Period.between() ব্যবহার করুন, যা বছর, মাস এবং দিন সহ Period ফেরত দেয়।
LocalTime ন্যানোসেকেন্ড নির্ভুলতা (9 দশমিক স্থান) সমর্থন করে। যদি মিলিসেকেন্ড নির্ভুলতা যথেষ্ট হয়, সংরক্ষণের আগে truncateTo(ChronoUnit.MILLIS) ব্যবহার করুন। এটি সিরিয়ালাইজেশনের সময় রাউন্ডিং সমস্যা প্রতিরোধ করে।
now() মেথড ডিভাইসের সিস্টেম ক্লক এবং ডিফল্ট সময় অঞ্চল ব্যবহার করে। যদি ডিভাইসগুলি ভিন্ন সময় অঞ্চলে থাকে, তারিখ ভিন্ন হতে পারে। একীভূত টাইমস্ট্যাম্পের জন্য Instant.now() ব্যবহার করুন, যা সবসময় UTC সময় ফেরত দেয়।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন