Skip to main content

کار با تاريخ و زمان

Working with dates and times

در این درس از دوره Java Essential Training، به صورت تخصصی و کاربردی به بررسی نحوه کار با تاریخ و زمان در جاوا پرداخته می‌شود؛ جایی که با استفاده از کلاس‌های Date و Calendar، فرآیندهای دریافت، فرمت‌بندی و تغییر داده‌های مربوط به زمان به شیوه‌ای دقیق و حرفه‌ای پیاده‌سازی می‌شوند. در این آموزش، علاوه بر معرفی متدهای کلیدی و عملیات پایه‌ای مانند مقایسه و افزودن واحدهای زمانی، به بررسی چالش‌ها و محدودیت‌های موجود در این کلاس‌ها و ارائه بهترین شیوه‌های مدیریت تاریخ و زمان در پروژه‌های مهندسی پرداخته می‌شود؛ همچنین مروری بر جایگزین‌های مدرن نظیر java.time صورت می‌گیرد تا متخصصان بتوانند با بهره‌گیری از استانداردهای روز، کدهای بهینه و مقاوم برای کاربردهای حساس به زمان ایجاد کنند.

لینک کمکی (official link) – آموزش جامع مدیریت Date & Time در جاوا: کار با Date, Calendar و java.time API

در جاوا دو تا API کاملاً متفاوت برای کار کردن با تاریخ و زمان وجود دارد. یکی مجموعه اولیه و اصلی از کلاس ها که در اواسط دهه 90 در جاوا ارائه شدند، و یک API تاریخ و زمان کاملاً جدید که با جاوا 8 آورده شد. اگر شما با یک نسخه سازمانی یا Enterprise از جاوا کار میکنید و یا با یک رانتایم جاوا 8 کار میکنید، اونوقت است که دیگرمیتوانید از API جدید استفاده کنید. همونطور که قبلاً هم گفتم نسخه سازمانی جاوا یا java EE برای برنامه های enterprise و بزرگ که معمولاً بر روی شبکه های بزرگ مخصوصاً اینترنت نصب و اجرا میشوند، کاربرد دارد. حالا اگر با ورژن های قدیمی تر جاوا کار میکنید و یا با مقوله برنامه نویسی اندروید میخواهید کار کنید، که هنوز ویژگی های جاوا 8 برای آن پیاده سازی نشده، پس مجبور هستید که از کلاس های قدیمی تر استفاده کنید.

من در حال کار روی پروژه ای با نام DatesAndTimes هستم، که یک کلاس main با یک متد main خالی دارد و کارم رو با API ی original یاد شده یا همان تاریخ اصلی و اولیه شروع میکنم.

خب؛ اول از همه میام یک نمونه از کلاس Date ایجاد میکنم، که عضوی از پکیج java.util هست.

از اونجایی که این کلاس عضوی از java.lang نیست، برای اینکه بتوانیم از آن استفاده کنیم، باید پکیج آن ایمپورت بشود، که با انتخاب کلاس Date بطور اتوماتیک پکیج آن ایمپورت میشه.

من نام شیء ام رو d میذارم و بعد با کلمه new و متد constructor date نمونه سازی و معرفی اش میکنم.

همانطور که میبینید اینجا نسخه های مختلفی از این متد constructor وجود دارد، ولی نسخه هایی که روی آنها خط کشیده شده، برای بیشتر نسخه های جاوا به این معنی هست که این نسخه ها دیگر کارایی ندارند و از دور خارج هستند.

با استفاده از کلاس Date به این شکل، نمیتوانید یک تاریخ با سال و ماه و روز خاص ایجاد کنید، ولی خب این روش یک راه خوب برای ایجاد یک شیء date هست که میتواند زمان لحظه جاری رو نشان بدهد.

پس من اینجا از این روش استفاده میکنم.

خب؛ حالا میام این شیء date رو در خروجی کنسول نمایش میدهم.

وقتی که برنامه ام رو با زدن کلیدهای ترکیبی shift و F10 اجرا میکنم، میبینیم که یک تاریخ با یک فرمت تاریخ خاص بهم برمیگرداند.

که این فرمت تاریخ به این شکل هست که، با روز هفته شروع میشه، و بعدش نام ماه آورده شده، بعد اینکه چندمین روز ماه هست، بعد ساعت و منطقه زمانی و در آخر هم سال رو آورده.

حالا کاری که میخواهم بکنم این است که یک تاریخ خاص رو نشون بدهم.

پس اینبار بجای استفاده از کلاس date، از یک کلاس با نام GregorianCalendar استفاده میکنم.

من این کلاس رو بعد از تایپ حروف اولش از لیست پیشنهادی انتخاب میکنم و ایمپورتش هم اتوماتیک اضافه میشود و نام این شیء رو هم gc میگذارم و با عبارت new_GregorianCalendar نمونه سازی و معرفی اش میکنم و سه مقدار اینتیجر رو بهش میدم: یکی برای سال، یکی ماه، و یک روز ماه که همگی اعداد صحیح هستند.

مثلاً  برای سال، 2009، برای ماه، 1 و برای روز هم 28 رو وارد میکنم.

خب حالا، میخواهم که یک روز به این تاریخی که ایجاد کردم اضافه کنم.

همونطور که در لیست پیشنهادی مشخص است، کلاس GregorianCalendar متدهایی دارد برای تغییر دادن و دستکاری اجزا مختلف و محتویات یک تاریخ.

من اینجا یک متدی با نام add رو فراخوانی میکنم و بعد باید مشخص کنم که چه نوع اطلاعاتی رو میخواهم اضافه کنم و آنرا نشان بدهم. یعنی یک سال رو میخواهم، یک ماه رو یا یک روز رو و این رو میتوانیم با یک ثابت از کلاس GregorianCalendar نشان بدهیم.

من کلاس GregorianCalendar رو فراخوانی میکنم و بعد یک دات میگذارم و بعدش هم date رو وارد میکنم.

توجه داشته باشید که اینجا توی این لیست پیشنهادی، ثابت هایی برای همه انواع مختلف دیگر اطلاعاتی که ممکن است بخواهید دستکاری کنید وجود داره.

یعنی در واقع با استفاده از این ثابت ها میتوانید هر عملیاتی که خواستید رو روی تاریخ تان انجام بدهید و قسمت های مختلف تاریخ تان رو دستکاری کنید.

خب؛ حالا عدد 1 رو وارد میکنم و این یعنی یک روز به تاریخی که داشتم اضافه بشود.

بعد برای بدست آوردن شیء date، و نمایش این تاریخی که ایجاد و دستکاری کردم، میام یک date ایجاد میکنم و نامش رو d2 میگذارم و مقدارش رو از طریق متد gc.gettime تعیین میکنم و این متد یک شی date رو برمیگرداند.

درواقع با فراخوانی متد gettime برای متغیر gc می‌آییم تاریخی که مربوط به این متغیر هست رو بدست میاوریم و نوع بازگشتی این متد هم date هست.

و حالا میتوانیم نتیجه رو در خروجی نمایش بدهیم.

و با اجرا برنامه میبینیم که تاریخی که به ما نشان میدهد 1ام مارس 2009 هست.

خب توجه کنید یک اتفاق جالبی اینجا افتاد.

وقتی که من این داده ها رو مقداردهی اولیه کردم، گفتم که میخواهم شماره ماه ام 1 باشد، و بعد هم اومدم یک روز به عدد 28 که مربوط به روز میشد اضافه کردم ولی چیزی که به من برگرداند 1ام مارس هست.

چه اتفاقی افتاد؟ خب در API اولیه، شماره گذاری ماه ها از عدد صفر شروع میشود. پس با این حساب شماره ماه ژانویه میشود 0، فوریه میشود 1، مارس میشه 2، و الی آخر. پس اگه من 1 و 28 رو وارد کنم، دقیقاً شبیه به همین مثال چند لحظه پیش؛ اونوقت منظور 28 ام فوریه هست، یعنی آخرین روز ماه فوریه در اون سال و زمانی که میام یک روز به این تاریخ اضافه میکنم، برای من 1ام مارس برگردانده میشود.

خب؛ حالا میخواهم این تاریخ رو فرمت کنم.

میتوانیم اینکار رو با یک کلاسی با نام DateFormat انجام بدهیم.

نام این شیء رو df میگذارم و متد DateFormat.getDateInstance رو برای آن فراخونی میکنم.

همانطور که در نسخه های این متد میبینید، میتوانید متد getDateInstance رو فراخونی کنید و هیچ پارامتری به آن ندهید، یعنی گزینه no parameters رو انتحاب کنید؛ میتوانید یک style به آن بدهید و یا میتوانید یک style و یک locale به آن بدهید.

من اینجا با استفاده از یک ثابت از کلاس DateFormat یک style برای آن تعریف میکنم.

من از ثابت FULL استفاده میکنم و بعد هم میام تاریخم رو با استفاده از دستور system output در خروجی نمایش میدهم و df.format رو صدا میزنم و تاریخم رو یعنی d2 رو به آن میدهم و اینبار با اجرای برنامه میبینیم که یک تاریخ با یک فرمت زیباتر و شکیل تری در خروجی نمایش داده میشود.

کلاس DateFormat چندین ثابت دارد که میتوانید از آن استفاده کنید، همچنین این کلاس از الگوهای صریح تاریخ هم پشتیبانی میکند که میتوانید از اونها برای فرمت یک تاریخ برای اهداف خاص استفاده کنید.

خب؛ تا اینجا کار کمی در مورد سینتکس نسخه قدیمی API جاوا توضیح دادم، ولی حالا بیایید تا یک نگاهی هم به سینتکس نسخه 8 جاوا بیندازیم. همونطور که می بینید، در جاوا 8، مقادیر تاریخ و زمان میتوانند توسط یک کلاس به نام، LocalDate، یا LocalDateTime، یا LocalTime نشان داده بشوند.

من فعلاً برای پیشروی در کارم از LocalDateTime استفاده میکنم و نام آنرا هم ldt میگذارم، این نام رو انتخاب کردم چونکه برگرفته از حروف اول LocalDateTime هست.

خب و بعد هم با استفاده از عبارت LocalDateTime.now نمونه سازی و معرفی اش میکنم.

که بد هم نیست بدانید، این یک متد از کلاس LocalDateTime هست.

که این کار معادل هست با ایجاد یک شیء date بدون هیچ پارامتری. ولی دقت کنید که وقتی من این کلاس رو ایجاد کردم، IntelliJ IDEA اومد یک  عبارت ایمپورت به بالا کدم اضافه کرد و همونطور که میبینید این API جدید در یک پکیجی با نام java.time بجای java.util دارد به بهره برداری و کار با تاریخ و زمان ادامه میدهد.

حالا میام این مقدار رو در خروجی نمایش آن میدهم.

و برای اینکار فقط شیء LocalDateTime رو به دستور system out ام میدهم و با اجرا برنامه میبینیم که این رشته در خروجی چاپ میشود.

این فرمت یک timestamp یونیکس هست، خب؛ بد نیست بدانید timestamp به معنی “برچسب زمان” است و این یعنی یک ساختار و شکل خاص از مقدار تاریخ زمان یا باصطلاح date-time، هست که در بعضی دیتابیس ها نشان داده میشود.

خب؛ حالا میخواهم بهتون نشان بدهم که چطوری یک روز خاص رو با استفاده از کلاس LocalDate نشان بدهید. من یک شیء LocalDate ایجاد میکنم، نامش رو ld میگذارم و مقدارش رو با صدا زدن LocalDate و بعد متد of از این کلاس تعیین میکنم.

همانطور که میبینید دو نسخه متفاوت از این متد وجود دارد من از نسخه ای استفاده میکنم که یک سال، یک ماه و یک روز رو همگی به شکل اینتیجر میخواهد.

و همان مقادیری که قبلاً دادم رو یکبار دیگر اینجا وارد میکنم:

یعنی 2009، 1 و 28.

و بعد این مقدار رو بدون اعمال هیچ فرمتی در خروجی چاپ میکنم.

و وقتی از برنامه اجرا می گیرم، میبینیم که تاریخ 28ام ژانویه 2009 رو به ما نشان میدهد.

خب؛ این هم تفاوت بین API تاریخ قدیمی و نسخه جدید. در نسخه جدید API، شماره گذاری ماه های سال از 1 تا 12 هست.

ولی در نسخه قدیمی API، شماره گذاری ماه ها از 0 تا 11 بود.

در آخر میخواهم بهتون نشان بدهم که چطوری یک LocalDate رو فرمتش کنید.

میام یک نمونه از یک کلاسی با نام DateTimeFormatter رو ایجاد و فراخونی میکنم، که عضوی از پکیج java.time.format هست.

و نامش رو dtf میگذارم.

خب؛ حالا روشهای مختلفی برای انجام اینکار وجود دارد.

که من یک روش ساده رو با استفاده از یک ثابتی از کلاسDateTimeFormatter به شما نشان میدهم.

پس DateTimeFormatter رو تایپش میکنم و من اینجا بعد از تایپ DateTimeFormatter از لیست پیشنهادی ISO_DATE رو انتخاب میکنم و بعد هم میام و مقدار تاریخ فرمت شده رو با دستور dtf.format و دادن متغیر ld بهش، در خروجی نمایش میدهم.

متغیر ld هم همان متغیری هست که این بالا ایجاد کردیم.

توجه داشته باشید همینطور که مشخص است متد format، دنبال کلاسی هست با نام TemporalAccessor.

که یک superclass یا کلاس والد کلاس های خیلی قدیمی خاصی هست که استفاده میکنید یعنی کلاس های LocalDate، LocalDateTime، و LocalTime.

من از این کد اجرا میگیرم و میبینیم که دقیقاً همان خروجی قبلی رو به ما نمایش میدهد.

حالا بیایید یک فرمت خیلی خاص رو امتحان کنیم.

اینبار، فرمتم رو با استفاده از یک متد با نام ofPattern ایجاد میکنم. یعنی اینجا بجای ISO_DATE میگذارم ofPattern.

خب؛ متد ofPattern، یک الگو رشته ای میخواهد و من عبارت M بزرگ اسلش d با حرف کوچک اسلش yyyy رو وارد میکنم.

و بعد یکبار دیگر از کدم اجرا میگیرم و این هم نتیجه.

اینبار میبینیم که یک تاریخ با فرمتی مختصرتر و خواناتر بهمون نشان میدهد.

پیشنهاد میکنم یک نگاهی به اسناد و اطلاعات جاوا بیندازید تا اطلاعات بیشتری درباره چگونگی ایجاد این الگوها، چگونگی نمایش ماه ها به شکل اعداد یا رشته ها و چگونگی اضافه کردن مقادیری به روز و ماه کسب کنید.

پس یکبار دیگر بطور خلاصه میگویم، دو تا API برای کار کردن با تاریخ و زمان در جاوا وجود دارد. اگر با جاوا 8 کار میکنید میتوانید از API جدید استفاده کنید، ولی در غیر اینصورت باید از مجموعه کلاس های قدیمی تر استفاده کنید.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دوره ها
درس ها
Tha PMIS
طهاکو من
0