প্রস্তাবনা
SimpleDateFormat কাস্টম প্যাটার্ন স্ট্রিং ব্যবহার করে java.util.Date মান ফরম্যাট এবং পার্স করে, এবং DateFormat লোকেল-সচেতন ডেট ও টাইম ফরম্যাটিং-এর জন্য অ্যাবস্ট্রাক্ট বেস API প্রদান করে। এই APIগুলো ব্যবহার করুন যখন আপনি লিগেসি জাভা কোড রক্ষণাবেক্ষণ করছেন যা এখনো java.util.Date-এ নির্ভরশীল; নতুন কোডের জন্য, জাভা ৮+ ডেট/টাইম API থেকে DateTimeFormatter পছন্দ করুন কারণ SimpleDateFormat থ্রেড-সেফ নয়।
এই টিউটোরিয়ালটি দেখায় কীভাবে DateFormat এবং SimpleDateFormat ফরম্যাটিং, পার্সিং, টাইমজোন কনভারশন, এবং লোকেল-স্পেসিফিক আউটপুটের জন্য ব্যবহার করতে হয়। এছাড়া এতে স্ট্রিক্ট ভ্যালিডেশন (setLenient(false)), থ্রেড সেফটি ওয়ার্কঅরাউন্ড, এবং DateTimeFormatter-এ মাইগ্রেশন করার প্রয়োগিক পথও কভার করা হয়েছে।
মূল উপসংহার
DateFormatহলো অ্যাবস্ট্রাক্ট ফরম্যাটিং API, এবংSimpleDateFormatহলো প্যাটার্ন-ভিত্তিক ফরম্যাটিং এবং পার্সিং-এর জন্য কংক্রিট ইমপ্লিমেন্টেশনSimpleDateFormatরিচ প্যাটার্ন টোকেন সাপোর্ট করে বছর, মাস, দিন, টাইম ফিল্ড, এবং টাইমজোন আউটপুটের জন্য- একটি শেয়ার্ড
SimpleDateFormatইনস্ট্যান্স মাল্টিথ্রেডেড কোডে আনসেফ কারণ এর ইন্টারন্যাল স্টেট মিউটেবল ThreadLocal<SimpleDateFormat>ফরম্যাটার ইনস্ট্যান্সকে থ্রেড প্রতি আলাদা রাখে যখন লিগেসি কোড অবিলম্বে মাইগ্রেট করতে পারে নাDateTimeFormatterইমিউটেবল এবং থ্রেড-সেফ, তাই নতুন জাভা কোডের জন্য এটি পছন্দনীয় রিপ্লেসমেন্ট.parse()ParseExceptionথ্রো করতে পারে, তাই পার্সিং কোডে ট্রাই-ক্যাচ এবং উপযোগী এরর মেসেজ ব্যবহার করা উচিতsetLenient(false)সাইলেন্টলি অ্যাডজাস্ট হওয়া ইনভ্যালিড ডেটগুলি রোধ করে, যেমন2024-13-45- সার্ভার ডিপ্লয়মেন্টে এনভায়রনমেন্ট-ডিপেন্ডেন্ট আউটপুট এড়াতে সবসময় এক্সপ্লিসিট
Localeপাস করুন
জাভাতে SimpleDateFormat কী?
SimpleDateFormat হলো DateFormat সাবক্লাস যা আপনাকে জাভাতে ফরম্যাটিং এবং পার্সিং-এর জন্য এক্সপ্লিসিট ডেট/টাইম প্যাটার্ন ডিফাইন করতে দেয়।
DateFormat ব্যবহার করুন যখন আপনি স্টাইল-ভিত্তিক, লোকেল-সচেতন আউটপুট ফ্যাক্টরি মেথডের মাধ্যমে চান, এবং SimpleDateFormat ব্যবহার করুন যখন আপনাকে এক্সাক্ট প্যাটার্ন কন্ট্রোল প্রয়োজন যেমন "dd-MM-yyyy" বা "yyyy-MM-dd'T'HH:mm:ssZ"। DateFormat স্টাইল কনস্ট্যান্ট (SHORT, MEDIUM, LONG, FULL) লোকেল-অনুরূপ আউটপুট প্রডিউস করে যার জন্য আপনাকে এক্সাক্ট আঞ্চলিক ডেট অর্ডার জানার প্রয়োজন নেই, যা ইউজার-ফেসিং ডিসপ্লে স্ট্রিংসের জন্য উপযোগী যেখানে ফরম্যাটটি ইউজারের লোকেল কনভেনশন ফলো করা উচিত। SimpleDateFormat ব্যবহার করুন যখন আউটপুট ফরম্যাট একটি এক্সটার্নাল রিকোয়ারমেন্ট দ্বারা ফিক্সড থাকে যেমন একটি 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 new Locale(String, String) জাভা ১৯ থেকে ডিপ্রিকেটেড। বদলে Locale.Builder ব্যবহার করুন।
Locale locale = new Locale.Builder() .setLanguage("en") .setRegion("US") .build(); ডেটের বদলে টাইম ফরম্যাট করতে, একই লোকেল এবং স্টাইল প্যারামিটার সহ DateFormat.getTimeInstance() ব্যবহার করুন।
Locale locale = Locale.US; DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale); System.out.println(timeFormat.format(new Date())); আউটপুট বর্তমান সময় এবং টাইমজোনের ওপর নির্ভর করে, উদাহরণস্বরূপ: 2:30:45 PM আধুনিক জাভা ডেট/টাইম API-এর জন্য ব্রডার ওভারভিউতে, Java 8 Date, LocalDate, LocalDateTime, Instant এবং Java 8 Features with Examples দেখুন।
SimpleDateFormat প্যাটার্ন সিনট্যাক্স রেফারেন্স
SimpleDateFormat প্যাটার্ন লেটারগুলো সরাসরি ডেট/টাইম কম্পোনেন্টের সাথে ম্যাপ করে, এবং সঠিক প্যাটার্ন সিলেকশন আউটপুট ফরম্যাট এবং পার্স বিহেভিয়র দুটোই কন্ট্রোল করে।
| সিম্বল | অর্থ | উদাহরণ প্যাটার্ন | উদাহরণ আউটপুট |
|---|---|---|---|
G | ইরা ডেজিগনেটর | G | AD |
y | বছর | yyyy | 2026 |
M | বছরে মাস | MMMM | January |
w | বছরে সপ্তাহ | w | 3 |
W | মাসে সপ্তাহ | W | 1 |
D | বছরে দিন | D | 15 |
d | মাসে দিন | dd | 05 |
F | মাসে সপ্তাহের দিন | F | 1 |
E | সপ্তাহে দিনের নাম | EEE | Mon |
u | সপ্তাহে দিনের নম্বর (1 = Monday) | u | 1 |
a | AM/PM مارকার | a | PM |
H | দিনে ঘন্টা (0-23) | HH | 14 |
k | দিনে ঘন্টা (1-24) | k | 14 |
K | AM/PM-এ ঘন্টা (0-11) | K | 2 |
h | AM/PM-এ ঘন্টা (1-12) | hh | 02 |
m | ঘন্টায় মিনিট | mm | 30 |
s | মিনিটে সেকেন্ড | ss | 45 |
S | মিলিসেকেন্ড | SSS | 123 |
z | জেনারেল টাইমজোন | z | IST |
Z | RFC 822 টাইমজোন অফসেট | Z | +0530 |
X | ISO 8601 টাইমজোন অফসেট | XXX | +05:30 |
প্যাটার্ন রিপিটিশন এবং আউটপুট প্রস্থ
রিপিটেড প্যাটার্ন লেটার প্রস্থ, न्यুমেরিক প্যাডিং, বা টেক্সট স্টাইল পরিবর্তন করে।
| ফিল্ড | প্যাটার্ন | উদাহরণ আউটপুট |
|---|---|---|
| মাস | M | 1 |
| মাস | MM | 01 |
| মাস | MMM | Jan |
| মাস | MMMM | January |
| মাসের দিন | d | 5 |
| মাসের দিন | dd | 05 |
ঘন্টা (0-23) | H | 7 |
ঘন্টা (0-23) | HH | 07 |
| বছর | yy | 26 |
| বছর | yyyy | 2026 |
প্রচলিত প্যাটার্ন উদাহরণ প্রত্যাশিত আউটপুটসহ
এই সাধারণ প্যাটার্নগুলো লগ, API, এবং ইউজার-ফেসিং ডেটের জন্য উপযোগী।
| প্যাটার্ন | উদাহরণ আউটপুট |
|---|---|
MM/dd/yyyy | 01/05/2026 |
dd-M-yyyy hh:mm:ss | 05-1-2026 02:30:45 |
dd MMMM yyyy | 05 January 2026 |
dd MMMM yyyy zzzz | 05 January 2026 India Standard Time |
E, dd MMM yyyy HH:mm:ss z | Mon, 05 Jan 2026 14:30:45 IST |
SimpleDateFormat ব্যবহার করে ডেট ফরম্যাট করার পদ্ধতি
একটি Date ফরম্যাট করতে, একটি প্যাটার্ন সহ SimpleDateFormat তৈরি করুন এবং .format(date) কল করুন।
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 SimpleDateFormat ফরম্যাটার ইনস্ট্যান্স থেকে টাইমজোন এবং লোকেল রুল প্রয়োগ করে, তাই আউটপুট কনসিস্টেন্ট থাকতে হলে সেগুলো এক্সপ্লিসিটলি সেট করুন।
SimpleDateFormat ব্যবহার করে স্ট্রিংকে ডেটে পার্স করার পদ্ধতি
একটি স্ট্রিংকে Date-এ পার্স করতে, সঠিক ইনপুট প্যাটার্ন সহ একটি ফরম্যাটার তৈরি করুন এবং .parse(input) কল করুন।
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 যদি শুধু টাইম প্রদান করা হয়, জাভা ডেট পোर्शन হিসেবে ইপক ডেট ব্যবহার করে।
ParseException সঠিকভাবে হ্যান্ডেল করা
parse() ParseException থ্রো করে যখন ইনপুট কনফিগার্ড প্যাটার্নের সাথে ম্যাচ না করে, তাই প্রোডাকশন কোডে এটি ক্যাচ করা উচিত এবং র 第一章 ইনপুট এবং এক্সপেক্টেড প্যাটার্ন লগ করা উচিত।
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) { // সহজ ডিবাগিং-এর জন্য ইনপুট ভ্যালু এবং প্যাটার্ন উভয়ই অন্তর্ভুক্ত করুন। 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" সার্ভিস জুড়ে পুনর্ব্যবহারযোগ্য এক্সেপশন হ্যান্ডেলিং প্যাটার্নের জন্য, Exception Handling in Java এবং Java 8 Date, LocalDate, LocalDateTime, Instant দেখুন।
পার্স করার আগে ডেট স্ট্রিং ভ্যালিডেট করা
SimpleDateFormat ডিফল্টভাবে লেনিয়েন্ট, তাই ইনভ্যালিড ভ্যালু ফেল না করেই রোল ওভার করতে পারে; স্ট্রিক্ট ভ্যালিডেশন এনফোর্স করতে setLenient(false) কল করুন।
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 { // লেনিয়েন্ট মোড ইনভ্যালিড ভ্যালু সাইলেন্টলি রোল ওভার করে এক্সেপশন থ্রো করার বদলে। 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-এ টাইমজোন হ্যান্ডলিং
SimpleDateFormat ফরম্যাট করার আগে ফরম্যাটারে টাইমজোন সেট করে একই Date-কে ভিন্ন টাইমজোনে রেন্ডার করতে পারে। একটি Date অবজেক্ট শুধুমাত্র UTC মিলিসেকেন্ড কাউন্ট সংরক্ষণ করে এবং নিজস্ব কোনো টাইমজোন রক্ষা করে না। টাইমজোন একটি ফরম্যাটিং কনসার্ন, স্টোরেজ কনসার্ন নয়; একই Date ভ্যালু ফরম্যাটার কোন টাইমজোন প্রয়োগ করে তার উপর নির্ভর করে ভিন্ন হিউম্যান-রিডেবল আউটপুট প্রডিউস করে। এর মানে setTimeZone() অবশ্যই format() কল করার আগে ফরম্যাটারে কল করতে হবে; এরপর সেট করলে ইতিমধ্যে প্রডিউস করা আউটপুটের ওপর কোনো ইফেক্ট নেই।
import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.TimeZone; Date timestamp = new Date(1700000000000L); // রিপিটেবল আউটপুটের জন্য ফিক্সড ইনস্ট্যান্ট 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 ডিপার টাইমজোন কনভারশন প্যাটার্নের জন্য, How to Convert Java Date into Specific TimeZone format দেখুন।
সাধারণ টাইমজোন ভুল এবং এড়ানোর উপায়
টাইমজোন বাগ সাধারণত স্টোরড ইনস্ট্যান্ট এবং রেন্ডারড লোকাল টাইমের মাঝপথে বিভ্রান্তির কারণে হয়।
DateUTC মিলিসেকেন্ড সংরক্ষণ করে, এবং টাইমজোন শুধু ফরম্যাট করার সময় প্রয়োগ হয়- একটি শেয়ার্ড ফরম্যাটার ইনস্ট্যান্সে মাল্টিথ্রেডেড এনভায়রনমেন্টে
setTimeZone()কল করা অন্য থ্রেডের ইন-ফ্লাইট কলের জন্য মিড-অপারেশনে টাইমজোন পরিবর্তন করতে পারে, কোনো এক্সেপশন ছাড়া ভুল টাইমজোনে আউটপুট প্রডিউস করে - একটি সার্ভলেট বা স্প্রিং কন্ট্রোলারে HTTP রিকোয়েস্ট জুড়ে একক
SimpleDateFormatইনস্ট্যান্স রিয়ুজ করা একটি রিকোয়েস্টেরsetTimeZone()কল অন্য রিকোয়েস্টের আউটপুটকে প্রভাবিত করতে পারে; প্রতিটি রিকোয়েস্টের জন্য নতুন ইনস্ট্যান্স তৈরি করুন বা স্টেট আইসোলেট করার জন্যThreadLocal<SimpleDateFormat>ব্যবহার করুন TimeZone.getTimeZone("Invalid/Zone")সাইলেন্টলি GMT-এ ফলব্যাক করে কারণ মেথড কনট্রাক্ট অনরিকগনাইজড ID-র জন্য GMT কে ডিফল্ট হিসেবে স্পেসিফাই করে এক্সেপশন থ্রো করার বদলেjava.timeথেকেZoneId.of()দিয়ে জোন ID ভ্যালিডেট করুনTimeZone.getTimeZone()-এ পাস করার আগে;ZoneId.of()ইনভ্যালিড ID-এZoneRulesExceptionথ্রো করে, যা সমস্যাটি এক্সপ্লিসিট করে তোলে
লোকেল-সচেতন ডেট ফরম্যাটিং
ফ্রেঞ্চ মাসের নাম বা জার্মান দিনের নামের মতো লোকেল-স্পেসিফিক ডেট আউটপুট প্রডিউস করতে, SimpleDateFormat কনস্ট্রাক্টরে একটি Locale পাস করুন। সাধারণ অঞ্চলের জন্য বিল্ট-ইন কনস্ট্যান্ট, Locale.US, Locale.UK, Locale.FRENCH, Locale.GERMAN ব্যবহার করুন, বা Locale.Builder দিয়ে কাস্টম লোকেল কনস্ট্রাক্ট করুন যখন কনস্ট্যান্ট কভার করে না এমন অঞ্চলের প্রয়োজন হয়। Locale টেক্সট ফিল্ডের জন্য কোন ভাষা ব্যবহার হবে তা কন্ট্রোল করে যেমন মাসের নাম, দিনের নাম, এবং AM/PM مارকার।
SimpleDateFormat কনস্ট্রাক্টরে Locale স্পেসিফাই করা
দ্বিতীয় কনস্ট্রাক্টর আর্গুমেন্ট হিসেবে একটি Locale পাস করুন। যদি আপনি এটি বাদ দেন, SimpleDateFormat ইন্টারন্যালি Locale.getDefault() কল করে, যা ফরম্যাটারকে 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 অঞ্চল অনুযায়ী মাস এবং দিনের নাম ফরম্যাট করা
একই প্যাটার্ন লোকেল অনুযায়ী ভিন্ন টেক্সট আউটপুট প্রডিউস করে।
| Locale | Pattern | Output |
|---|---|---|
Locale.US | EEEE, dd MMMM yyyy | Tuesday, 14 November 2023 |
Locale.FRENCH | EEEE, dd MMMM yyyy | mardi, 14 novembre 2023 |
Locale.GERMAN | EEEE, dd MMMM yyyy | Dienstag, 14 November 2023 |
সার্ভার এনভায়রনমেন্টে চলমান JVM-এ Locale.getDefault()-এর উপর নির্ভর করলে ইনকনসিস্টেন্ট আউটপুট প্রডিউস করতে পারে কারণ OS লোকেল সেটিংস হস্ট জুড়ে ভিন্ন হয়। সবসময় এক্সপ্লিসিট Locale পাস করুন।
SimpleDateFormat-এ থ্রেড সেফティ সমস্যা
কেন SimpleDateFormat থ্রেড-সেফ নয়
SimpleDateFormat পার্স/ফরম্যাট অপারেশনের সময় ইন্টারন্যাল Calendar এবং NumberFormat স্টেট মিউটেট করে। যদি একাধিক থ্রেড একই ইনস্ট্যান্স ব্যবহার করে, এই মিউটেবল ফিল্ডগুলো মিড-অপারেশনে ওভাররাইট হতে পারে, যা রেস কন্ডিশন এবং আনপ্রিডিক্টেবল আউটপুট সৃষ্টি করে। প্র্যাকটিসে এটি বের হয় এক থ্রেডের ডেট অন্য থ্রেডের রেজাল্টে দেখাওয়া, .parse() কোনো এক্সেপশন ছাড়া সম্পূর্ণ ভুল ডেট রিটার্ন করা, বা ফরম্যাটারের ভিতর থেকে ArrayIndexOutOfBoundsException থ্রো হওয়া হিসেবে। এই ফেলিওরগুলো ইন্টারমিটেন্ট এবং লোড-ডিপেন্ডেন্ট, যা সিঙ্গেল-থ্রেডেড টেস্ট এনভায়রনমেন্টে এগুলো রিপ্রডিউস করা কঠিন করে তোলে।
জাভা থ্রেডিং বিহেভিয়রের ব্যাকগ্রাউন্ডের জন্য, Java Thread Example দেখুন।
ThreadLocal ব্যবহার করে SimpleDateFormat ইনস্ট্যান্স আইসোলেট করা
ThreadLocal<SimpleDateFormat> প্রতিটি থ্রেডকে এর নিজস্ব ফরম্যাটার ইনস্ট্যান্স দিয়ে শেয়ারড মিউটেবল স্টেট এড়াতে সাহায্য করে। থ্রেড-পুল এনভায়রনমেন্ট যেমন সার্ভলেট কন্টেইনার এবং স্প্রিং অ্যাপ্লিকেশনে, থ্রেডগুলো রিকোয়েস্ট জুড়ে রিয়ুজ হয় এবং কখনো টারমিনেট হয় না, যার মানে ThreadLocal ভ্যালুগুলো কখনো অটোমেটিক্যালি রিমুভ হয় না। অপারেশন কমপ্লিট হলে সবসময় FORMATTER.remove() কল করুন, অথবা ফরম্যাটার ইনস্ট্যান্স থ্রেডের লাইফটাইম ধরে থাকবে এবং সাস্টেইনড লোডের অধীনে মেমরি লিক হিসেবে জমা হবে।
import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; public class ThreadSafeLegacyFormatter { // প্রতিটি থ্রেড এক ডেডিকেটেড ফরম্যাটার ইনস্ট্যান্স পায়। 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 { // ক্রস-থ্রেড মিউটেশন নেই কারণ প্রতিটি থ্রেড তার নিজস্ব ফরম্যাটার পড়ে। return FORMATTER.get().format(date); } finally { // ব্যবহার করার পর ইনস্ট্যান্স রিমুভ করুন থ্রেড পুলে মেমরি লিক রোধ করতে। FORMATTER.remove(); } } } DateTimeFormatter-এ স্যুইচ করা থ্রেড-সেফ অল্টারনেটিভ হিসেবে
DateTimeFormatter ইমিউটেবল এবং থ্রেড-সেফ, তাই এক শেয়ার্ড স্ট্যাটিক ইনস্ট্যান্স সেফ।
import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.Locale; // থ্রেড জুড়ে শেয়ার করলে থ্রেড-সেফ নয় SimpleDateFormat unsafe = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); System.out.println(unsafe.format(new Date())); // থ্রেড-সেফ: DateTimeFormatter ইমিউটেবল এবং স্ট্যাটিক ফিল্ড হিসেবে স্টোর করা যায় 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-এ মাইগ্রেশন
DateTimeFormatter-এ মাইগ্রেশন থ্রেড-সেফティ রিস্ক দূর করে, ThreadLocal ওয়ার্কঅরাউন্ড দূর করে, এবং java.time টাইপসহ ক্লিনলি ইন্টিগ্রেট করে। অধিকাংশ কোডবেসের জন্য মাইগ্রেশন মেকানিক্যাল: প্যাটার্ন সিনট্যাক্স প্রায় একই, দুটি API ইনক্রিমেন্টাল রোলআউটের време কো-এক্সিস্ট করতে পারে, এবং আপনাকে একসাথে সবকিছু কনভার্ট করার প্রয়োজন নেই। প্রধান রিস্ক হলো u সিম্বল, যা SimpleDateFormat-এ দিন-অফ-উইক মানে এবং DateTimeFormatter-এ বছর মানে; এই সিম্বল চেক না করে সরাসরি 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 (লিগেসি java.util.Date API) SimpleDateFormat legacyFormatter = new SimpleDateFormat(pattern, Locale.US); Date legacyParsed = legacyFormatter.parse(input); String legacyFormatted = legacyFormatter.format(new Date()); // DateTimeFormatter (মডার্ন 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 প্যাটার্ন | নোট |
|---|---|---|---|
| বছর | yyyy | uuuu বা yyyy | java.time-এ প্রোলেপটিক ইয়ার কনসিস্টেন্সির জন্য uuuu পছন্দ করুন |
| টাইমজোন অফসেট/নেম | z, Z, X | z, Z, x, X | java.time আরও অফসেট ভেরিয়েন্ট ডিফারেনশিয়েট করে (x এবং X) |
| লিটারেল টেক্সট | 'T' | 'T' | দুই APIই লিটারেলের জন্য সিঙ্গেল কোট ব্যবহার করে |
u সিম্বল | দিন-অফ-উইক নম্বর | বছর | প্রচলিত গাচ্ছা: u API জুড়ে অর্থ পরিবর্তন করে |
স্টেপ-বাই-স্টেপ মাইগ্রেশন চেকলিস্ট
এই চেকলিস্টটি ব্যবহার করে একসাথে একটি ফরম্যাটার কনভার্ট করুন এক্সিস্টিং কোডবেসে।
import java.text.SimpleDateFormat;কেimport java.time.format.DateTimeFormatter;দিয়ে রিপ্লেস করুনnew SimpleDateFormat("yyyy-MM-dd")কেDateTimeFormatter.ofPattern("yyyy-MM-dd")দিয়ে রিপ্লেস করুন.parse()কেLocalDate.parse()বাLocalDateTime.parse()দিয়ে রিপ্লেস করুন ইনপুট প্রিসিশনের ওপর নির্ভর করে.format(date)কেformatter.format(localDate)বাformatter.format(localDateTime)দিয়ে রিপ্লেস করুন- সম্ভব হলে
new Date()রিমুভ করুন এবংLocalDate.now()বাInstant.now()ব্যবহার করুন
DateTimeFormatter এক্সক্লूसিভলি java.time টাইপসহ (LocalDate, LocalDateTime, ZonedDateTime, Instant) কাজ করে। এটি সরাসরি java.util.Date এক্সেপ্ট করে না। যদি আপনার কোড থাকে যা এখনো java.util.Date মান প্রডিউস করে, উদাহরণস্বরূপ একটি লিগেসি ORM বা JDBC ড্রাইভার থেকে, প্রথমে date.toInstant() দিয়ে কনভার্ট করুন DateTimeFormatter-এ পাস করার আগে। দুটি API একই কোডবেসে ইনক্রিমেন্টাল মাইগ্রেশনের সময় কো-এক্সিস্ট করতে পারে; আপনাকে একসাথে সবকিছু কনভার্ট করার প্রয়োজন নেই। DateTimeFormatter এছাড়া ParseException-কে java.time.format.DateTimeParseException দিয়ে রিপ্লেস করে, যা একটি আনচেকড এক্সেপশন, তাই ট্রাই-ক্যাচ ব্লক অপশনাল হলেও প্রোডাকশন পার্সিং কোডে এখনো রিকমেন্ডেড।
মাইগ্রেশন কনটেক্সট এবং টাইপ চয়েসের জন্য, Java 8 Date, LocalDate, LocalDateTime, Instant রেফার করুন।
সচরাচর জিজ্ঞাস্য
জাভাতে SimpleDateFormat এবং DateFormat-এর পার্থক্য কী?
DateFormat একটি অ্যাবস্ট্রাক্ট ক্লাস যা ডেট/টাইম ফরম্যাটিং-এর জন্য কনট্রাক্ট ডিফাইন করে। SimpleDateFormat ইটস কংক্রিট সাবক্লাস যা কাস্টম প্যাটার্ন-ভিত্তিক ফরম্যাটিং অনুমতি দেয়। আপনি কোডে SimpleDateFormat সরাসরি ব্যবহার করবেন; আপনি DateFormat রেফারেন্স টাইপ হিসেবে ব্যবহার করবেন যখন আপনি যেকোনো ইমপ্লিমেন্টেশন এক্সেপ্ট করতে চান।
SimpleDateFormat কি থ্রেড-সেফ?
না। SimpleDateFormat ইনস্ট্যান্স থ্রেড-সেফ নয়। সিঙ্ক্রোনাইজেশন ছাড়া একাধিক থ্রেড জুড়ে একক ইনস্ট্যান্স শেয়ার করলে অনপ্রিডিক্টেবল পার্স এবং ফরম্যাট রেজাল্ট হয়। ThreadLocal<SimpleDateFormat> ব্যবহার করুন বা এটিকে java.time.format.DateTimeFormatter দিয়ে রিপ্লেস করুন, যা ইমিউটেবল এবং থ্রেড-সেফ।
SimpleDateFormat ব্যবহার করে dd-MM-yyyy ফরম্যাটের ডেট স্ট্রিং কীভাবে পার্স করব?
SimpleDateFormat কে "dd-MM-yyyy" প্যাটার্ন দিয়ে ইনস্ট্যানশিয়েট করুন, তারপর .parse(yourString) কল করুন। ParseException জন্য ট্রাই-ক্যাচ ব্লকে র্যাপ করুন। নিশ্চিত করুন ইনপুট স্ট্রিং সেপারেটর ক্যারেক্টার সহ প্যাটার্নের সাথে এক্সাক্টলি ম্যাচ করে।
SimpleDateFormat ব্যবহার করে একটি Date কীভাবে ভিন্ন টাইমজোনে কনভার্ট করব?
আপনার SimpleDateFormat ইনস্ট্যান্সে .format(date) কল করার আগে .setTimeZone(TimeZone.getTimeZone("America/New_York")) কল করুন। আন্ডারলাইং Date অবজেক্ট UTC মিলিসেকেন্ড ধরে; ফরম্যাটার আউটপুটের সময় টাইমজোন অফসেট প্রয়োগ করে।
প্যাটার্ন "yyyy-MM-dd'T'HH:mm:ssZ" কী প্রডিউস করে?
এটি একটি ISO 8601-কম্প্যাটিবল টাইমস্ট্যাম্প প্রডিউস করে, উদাহরণস্বরূপ 2024-06-15T14:30:00+0530। T একটি লিটারেল ক্যারেক্টার যা সিঙ্গেল কোটে র্যাপ করা। Z RFC 822 টাইমজোন অফসেট রিপ্রেজেন্ট করে।
SimpleDateFormat থেকে DateTimeFormatter-এ কীভাবে মাইগ্রেট করব?
new SimpleDateFormat("yyyy-MM-dd") কে DateTimeFormatter.ofPattern("yyyy-MM-dd") দিয়ে রিপ্লেস করুন। .parse() কলগুলোকে LocalDate.parse() বা LocalDateTime.parse() দিয়ে রিপ্লেস করুন। .format(date) কলগুলোকে formatter.format(localDate) দিয়ে রিপ্লেস করুন। নোট করুন যে DateTimeFormatter কিছু কনটেক্সটে yর বদলে u ব্যবহার করে বছর জন্য।
কেন SimpleDateFormat এক্সেপশন থ্রো না করে ইনভ্যালিড ডেট পার্স করে?
ডিফল্টভাবে, SimpleDateFormat লেনিয়েন্ট পার্সিং মোড ব্যবহার করে, যা আউট-অফ-রেঞ্জ ভ্যালু রিজেক্ট করার বদলে অ্যাডজাস্ট করে। পার্স করার আগে .setLenient(false) কল করুন স্ট্রিক্ট ভ্যালিডেশন এনফোর্স করতে এবং ইনভ্যালিড ইনপুটে ParseException থ্রো করতে।
SimpleDateFormat ব্যবহার করে নির্দিষ্ট লোকেলে ডেট কীভাবে ফরম্যাট করব?
Locale কনস্ট্রাক্টরের দ্বিতীয় আর্গুমেন্ট হিসেবে পাস করুন: new SimpleDateFormat("dd MMMM yyyy", Locale.FRENCH)। এটি মাস এবং দিনের নাম নির্দিষ্ট ভাষায় রেন্ডার করে, যা একাধিক অঞ্চল সার্ভ করার অ্যাপ্লিকেশনের জন্য ক্রিটিক্যাল।
উপসংহার
এই গাইডে DateFormat এবং SimpleDateFormat ফান্ডামেন্টালস, প্যাটার্ন সিনট্যাক্স, ফরম্যাটিং এবং পার্সিং ওয়ার্কফ্লো, টাইমজোন বিহেভিয়র, লোকেল-সচেতন রেন্ডারিং, থ্রেড সেফটি ইস্যু, এবং DateTimeFormatter-এ মাইগ্রেশন কভার করা হয়েছে।
এখন আপনি লিগেসি এবং মডার্ন কোডের জন্য সঠিক ফরম্যাটার বেছে নিতে পারেন, স্ট্রিক্ট ভ্যালিডেশন সহ ডিফেনসিভলি ইনপুট পার্স করতে পারেন, সার্ভার এনভায়রনমেন্টে লোকেল এবং টাইমজোন ড্রিফট এড়াতে পারেন, এবং শেয়ারড ডেট ফরম্যাটার থেকে কনকারেন্সি রিস্ক দূর করতে পারেন।
পরবর্তী ধাপের জন্য, Java 8 Date, LocalDate, LocalDateTime, Instant, Java 8 Features with Examples, Exception Handling in Java, এবং How to Convert Java Date into Specific TimeZone format রিভিউ করুন জাভা অ্যাপ্লিকেশনে ডেট/টাইম হ্যান্ডলিং আধুনিক করতে চালিয়ে যেতে।
রেফারেন্স:
- SimpleDateFormat API Doc
- DateFormat API Doc
- DateTimeFormatter API Doc
এই কাজটি ক্রিয়েটিভ কমন্স অ্যাট্রিবিউশন-ননকমার্শিয়াল- শেয়ারআলাইক ৪.০ ইন্টারন্যাশনাল লাইসেন্সের অধীনে লাইসেন্সপ্রাপ্ত।