«تاریخ و زمان چیزی است که به کودکان خردسال یاد میدهیم. چقدر میتواند سخت باشد؟»
بسیاری از برنامهنویسان این اشتباه را مرتکب شدهاند و تجربهی پس از آن معمولاً تأثیر بدی بر سلامت و شادیشان میگذارد.
هر کسی که برنامهنویسی غیرساده با تاریخ و زمان انجام میدهد، دستکم باید آماده باشد مشکلات احتمالی را درک و آنها را کاهش دهد.
این سند تلاش میکند نمای کلیای از نحوهی برخورد Julia با تاریخ و زمان ارائه دهد، اما برای جزئیات بیشتر مراجعه به راهنما ضروری خواهد بود. یک ویکیکتاب هم هست که بعضی خوانندگان ممکن است توضیحاتش را روشنتر بدانند و شامل یک نمودار مفید از سلسلهمراتب نوعها است.
Dates
بیشتر قابلیتهای پایه در Dates قرار دارند؛ ماژولی که در نصب پیشفرض گنجانده شده اما بخشی از کتابخانهی استاندارد نیست.
برای استفاده از این ماژول دو گزینه وجود دارد:
import Dates را اضافه کنید و سپس پیش از همهی فراخوانیهای تابع Dates. بگذارید.using Dates را اضافه کنید که کل ماژول را به فضای نام جاری میآورد (بهجز چند اسم مسئلهدار).# option 1
julia> import Dates
julia> Dates.now()
2025-06-21T16:02:39.080
julia> now() # wrong: need to include `Dates.` after an import
ERROR: UndefVarError: `now` not defined in `Main`
# option 2
julia> using Dates
julia> now() # functions are now in the namespace
2025-06-21T16:03:04.161
ماژول Dates بزرگ و پیچیده است، اما چهار نوع اصلی از قابلیتها را فراهم میکند:
Dates.Date که شامل روز-ماه-سال است اما زمانِ روز را ندارد.Dates.Time که شامل زمانِ روز است اما تاریخ ندارد.Dates.DateTime که تاریخ و زمان را با هم ترکیب میکند.Dates.Period که بازههای زمانی/تاریخی را مدیریت میکند.توجه داشته باشید که یک DateTime عموماً اطلاعات منطقهی زمانی را شامل نمیشود (Python به این نوع، datetime «ساده» میگوید).
یک استثنا now() است که زمان محلی را از ساعت سیستم شما میگیرد و در صورت نیاز میتواند آن را به UTC تبدیل کند.
شاید رایجترین نیازها اینها باشند:
Dates.Dates.Date، Time یا DateTime.today()) و/یا زمان (با now()).برای کاهش حواسپرتی بصری، بیشتر کدهای نمونه در ادامهی این سند فرض میکنند که using Dates انجام شده و از آوردن نام ماژول Dates. در فراخوانیهای تابع پرهیز میکنند.
راههای بسیاری برای نوشتن تاریخ و زمان وجود دارد که معمولاً وابسته به فرهنگاند. تاریخهایی که کاملاً عددیاند، مانند «7/6/23»، مبهم و گیجکنندهاند و به اشتباهات پرهزینهی زیادی در سازمانهای چندملیتی منجر شدهاند (نویسنده این را از تجربهی تلخ شخصی میگوید).
استاندارد بینالمللی در ISO 8601 تعریف شده است و دو مزیت اصلی دارد:
در مثال قبلی دیدیم که Date.now() مقدار 2025-06-21T16:03:04.161 را برگرداند.
این مقدار از بخشهای مختلفی ساخته میشود:
YYYY-MM-DD برای بخش تاریخ.hh:mm:ss برای بخش زمان.قالبهای رشتهای دیگر در بخش بعدی بحث خواهند شد.
Dates.Date یک نوع نسبتاً ساده و تنها-تاریخی است که هیچ درکی از زمانها یا منطقههای زمانی ندارد.
# constructor with year, month, day arguments
julia> date1 = Date(2025, 06, 23)
2025-06-23
# constructor with ISO 8601 string
julia> date2 = Date("2025-06-23")
2025-06-23
julia> date1 == date2
true
julia> typeof(date1)
Date
توابع دسترسیدهنده برای بخشهای جداگانهی تاریخ وجود دارند و اینها بهصورت جفتهایی هستند که با بزرگ یا کوچک بودن حرف از هم متمایز میشوند.
# lowercase returns an integer
julia> month(date1)
6
julia> typeof(month(date1))
Int64
# Propercase returns a Period type
julia> Month(date1)
6 months
julia> typeof(Month(date1))
Month
انواع مختلفی از توابع وجود دارند که درکی از تقویم دارند. مثال بعدی فقط چند مورد را نشان میدهد.
julia> date1
2025-06-23
julia> dayofweek(date1) # 1 = Monday, 7 = Sunday
1
julia> dayname(date1)
"Monday"
julia> daysinmonth(date1)
30
julia> isleapyear(date1)
false
julia> lastdayofmonth(date1)
2025-06-30
Dates.Time نوع پایه و تنها-زمانی است.
هیچ درکی از تاریخ ندارد: زمانها در نیمهشب بهطور خودکار به Time(0, 0, 0) برمیگردند.
قالب کامل سازنده Time(hour, min, sec, millisec, microsec) یا معادل ISO 8601 آن است.
همهی پارامترها اختیاریاند و بهطور پیشفرض 0 خواهند بود.
julia> Time(14, 57, 25, 142)
14:57:25.142
julia> Time("14:57:25.142")
14:57:25.142
julia> Time(14, 57, 25, 142, 32)
14:57:25.142032
مانند Date، بخشهای جداگانه با توابع دسترسیدهنده در دسترس هستند:
julia> minute(t) # => integer
57
julia> Minute(t) # => Period
57 minutes
Dates.DateTime بیشتر ویژگیهای نوعهای Date و Time را با هم ترکیب میکند.
julia> dt1 = DateTime(2025, 6, 23, 14, 57, 25, 142)
2025-06-23T14:57:25.142
# date1 and t were defined in previous examples
julia> dt2 = DateTime(date1, t)
2025-06-23T14:57:25.142
پارامترهای سال، ماه و روز بهطور پیشفرض 1 هستند و همهی پارامترهای زمان بهطور پیشفرض 0.
به خاطر سپردن ترتیب درست همهی این پارامترها میتواند چالشبرانگیز باشد، بنابراین قالب ISO ممکن است برای ورودی ترجیح داده شود.
بهطور جایگزین، میتوان یک DateTime را از یک Date و یک Time ساخت، همانطور که در مثال بالا آمد.
هر یک از اجزای تاریخ/زمان نوع Period مخصوص خود را دارد، از Year تا Nanosecond، که بازهای از زمان را نمایش میدهد.
اینها بهویژه برای محاسبات حسابی مفیدند.
julia> dt1
2025-06-23T14:57:25.142
julia> Year(21)
21 years
julia> Second(61)
61 seconds
julia> dt1 + Year(21) - Second(61)
2046-06-23T14:56:24.142
julia> Date(2025, 07, 03) - Date(2025, 04, 25)
69 days
هنگام کار با نوعهای Period، Julia تلاش میکند دربارهی بینظمیهای تقویمی مانند طول ماه هوشمندانه عمل کند و در صورت لزوم گرد میکند.
# February has fewer days than January
julia> Date(2025, 1, 31) + Month(1)
2025-02-28
پیشتر به استاندارد ISO 8601 اشاره کردیم که نمایش پیشفرض تاریخ/زمان در Julia هنگام قالببندی یا تجزیهی رشتهها است.
بدیهی است که قالبهای بسیار دیگری نیز بهطور مکرر و اغلب به شیوههای وابسته به فرهنگ استفاده میشوند.
برای رسیدگی به اینها، Julia نوع DateFormat را دارد که میتوان آن را از یک رشتهی قالب با هر پیچیدگی دلخواه ساخت.
# dateformat"" string syntax
julia> dtfmt = dateformat"d/m/y"
dateformat"d/m/y"
julia> typeof(dtfmt)
DateFormat{Symbol("d/m/y"), Tuple{Dates.DatePart{'d'}, Dates.Delim{Char, 1}, Dates.DatePart{'m'}, Dates.Delim{Char, 1}, Dates.DatePart{'y'}}}
# DateFormat constructor
julia> DateFormat("d/m/y")
dateformat"d/m/y"
مثال بالا بسیار ساده است، فقط یک تاریخ در قالب روز/ماه/سال که در اروپا رایج است. دو گونه از نحوهی نگارش نشان داده شده است، اما نتیجه یکسان است.
سپس میتوان از یک DateFormat برای تجزیهی هر رشتهی مناسبی استفاده کرد:
julia> DateTime("14/7/2023", dtfmt)
2023-07-14T00:00:00
ساختن یک DateFormat سربار قابلتوجهی دارد، بنابراین انجام این کار فقط یک بار (همانطور که اینجا با dtfmt انجام شد) هنگام حلقه زدن روی رشتههای تاریخ/زمانِ زیاد برای کارایی مفید است.
قالبها میتوانند بسیار پیچیدهتر از این باشند، بنابراین برای جزئیات به راهنما مراجعه کنید.
از همان DateFormat میتوان برای خروجی دادن یک تاریخ/زمان در هر قالب رشتهای دلخواه، با استفاده از تابع Dates.format() استفاده کرد.
متأسفانه به نظر میرسد تعارضی در فضای نام با format وجود دارد (دستکم تا Julia 1.11.5)، بنابراین بهتر است حتی پس از using Dates پیشوند Dates. را بگذارید.
julia> dt1
2025-06-23T14:57:25.142
julia> Dates.format(dt1, dateformat"e, u d")
"Mon, Jun 23"
همانطور که مستند شده است، "e, u d" نمایش متنی مختصر برای روز هفته و ماه را میدهد.
نمایش متنی بهطور پیشفرض انگلیسی است. زبانهای دیگر میتوانند اضافه شوند، هرچند پشتیبانی از این کار در حال حاضر چندان مطلوب نیست.
در این تمرین شما روی یک برنامهریز قرار ملاقات برای یک سالن زیبایی در نیویورک کار خواهید کرد که در ۱۵ سپتامبر ۲۰۱۲ افتتاح شد.
شما پنج تسک دارید که همهی آنها به تاریخهای قرار ملاقات مربوط میشوند. زمانها در قالب ۲۴ ساعته هستند (بدون ق.ظ/ب.ظ).
تابع schedule_appointment() را پیادهسازی کنید تا یک نمایش متنی از تاریخ قرار ملاقات را به قالب DateTime متناظر تجزیه کند.
توجه داشته باشید که ورودی به ترتیب ماه/روز/سال آمریکایی است.
julia> schedule_appointment("07/25/2023 13:45:00")
2023-07-25T13:45:00
تابع has_passed() را پیادهسازی کنید که یک تاریخ قرار ملاقات میگیرد و بررسی میکند که آیا قرار ملاقات در جایی در گذشته بوده است:
julia> has_passed(DateTime(1999, 12, 31, 9, 0, 0))
true
تابع is_afternoon_appointment() را پیادهسازی کنید که یک تاریخ قرار ملاقات میگیرد و بررسی میکند که آیا قرار ملاقات در بعدازظهر است (>= ۱۲:۰۰ و < ۱۸:۰۰):
julia> is_afternoon_appointment(DateTime(2023, 3, 29, 15, 0, 0))
true
تابع description() را پیادهسازی کنید که یک تاریخ قرار ملاقات میگیرد و توصیفی از آن تاریخ و زمان برمیگرداند:
julia> describe(DateTime(2023, 3, 29, 15, 0, 0))
"You have an appointment on Wednesday, March 29, 2023 at 15:00"
تابع anniversary_date() را پیادهسازی کنید که تاریخ سالگرد امسال را برمیگرداند، که ۱۵ سپتامبر است:
julia> anniversary_date() # run during 2025
2025-09-15