Menu
flag Ar iconالعربيةdown icon

الوقت في Golang: Now وSleep وFormat وParse والمدد

كيف تتعامل مع التواريخ والأوقات في Go: time.Now وtime.Sleep، وحساب المدد، وتخطيط المرجع 2006-01-02 15:04:05 لـ Format وParse، والمناطق الزمنية، والطوابع الزمنية Unix، والمؤقّتات وtickers.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

الأساسيات في برنامج واحد

تعيد time.Now() الوقت المحلي الحالي، وتوقف time.Sleep الـ goroutine الحالية، وتقيس time.Since الوقت المنقضي، وتبني time.Date لحظة محدّدة. تتناول بقية هذه الصفحة كل قطعة بدورها. تستخدم الأمثلة تواريخ ثابتة وتوقيت UTC لتكون مخرجاتها واحدة أينما شغّلتها.

Sleep وDuration

الـ time.Duration عدد من النوع int64 للنانوثواني. تعرّف الحزمة ثوابت لبناء قيم مقروءة:

الثابتالقيمة
time.Nanosecond1
time.Microsecond1000 ns
time.Millisecond1000 µs
time.Second1000 ms
time.Minute60 s
time.Hour60 min

لا يوجد time.Day، لأن اليوم ليس دائمًا 24 ساعة عندما تتغيّر المنطقة الزمنية للتوقيت الصيفي. استخدم AddDate للأيام التقويمية (انظر أدناه).

خطآن شائعان يأتيان من كون Duration عددًا صحيحًا:

  • time.Sleep(5) تنام 5 نانوثوانٍ. اضرب دائمًا بوحدة: time.Sleep(5 * time.Second).
  • time.Sleep(n * time.Second) لا تُترجم عندما يكون n متغيّرًا من النوع int. حوّله: time.Duration(n) * time.Second. والثابت مثل 5 يعمل دون تحويل لأن الثوابت عديمة النوع تتكيّف مع النوع Duration.

تقبل ParseDuration الوحدات ns وus (أو µs) وms وs وm وh، مدمجة مثل "2h45m" أو "1.5s". ولا وحدة فيها للأيام.

التنسيق: تخطيط المرجع 2006-01-02

لا تستخدم Go الصيغة %Y-%m-%d ولا yyyy-MM-dd. التخطيط هو الوقت المرجعي

Mon Jan 2 15:04:05 MST 2006

مكتوبًا بالشكل الذي تريد أن تبدو به مخرجاتك. اختيرت القيم بحيث تكون كل منها فريدة: الشهر 1، واليوم 2، والساعة 3 (أو 15)، والدقيقة 4، والثانية 5، والسنة 6 (2006)، وإزاحة المنطقة -7 (-0700). اقرأها هكذا: 01/02 03:04:05PM '06 -0700.

رموز التخطيط التي ستحتاجها أكثر:

الرمزالمعنىمثال
2006 / 06السنة، 4 أو 2 أرقام2026 / 26
01 / 1 / Jan / Januaryالشهر03 / 3 / Mar / March
02 / 2 / _2يوم الشهر (بصفر في البداية، عادي، بمسافة في البداية)05 / 5 / " 5"
Mon / Mondayيوم الأسبوعThu / Thursday
15الساعة، بنظام 24 ساعة09
03 / 3الساعة، بنظام 12 ساعة09 / 9
04 / 4الدقيقة07 / 7
05 / 5الثانية03 / 3
PM / pmعلامة AM أو PMAM
.000 / .999كسور الثانية (ثابتة / مع حذف الأصفار الزائدة).250 / .25
MSTاختصار المنطقةUTC
-0700 / -07:00إزاحة المنطقة الرقمية+0000 / +00:00
Z07:00مثل -07:00، لكنه يطبع Z لتوقيت UTCZ

التخطيطات المعرّفة مسبقًا:

الثابتالتخطيط
time.RFC33392006-01-02T15:04:05Z07:00 (استخدمه للواجهات البرمجية وJSON)
time.RFC3339Nano2006-01-02T15:04:05.999999999Z07:00
time.DateTime (Go 1.20)2006-01-02 15:04:05
time.DateOnly (Go 1.20)2006-01-02
time.TimeOnly (Go 1.20)15:04:05
time.Kitchen3:04PM
time.RFC1123Mon, 02 Jan 2006 15:04:05 MST (تواريخ HTTP تستخدم http.TimeFormat بدلًا منه)

الخطأ الكلاسيكي كتابة تخطيط بأرقام خاطئة، مثل "2023-01-01". لا ترفضه Go. بل تنسخ الأحرف التي لا تعرفها وتستبدل التي تعرفها: كل 2 هو اليوم، و3 ساعة نظام 12 ساعة، و01 كلاهما الشهر، فيُنسَّق 5 مارس الساعة 9:07 بالشكل 5059-03-03. والتخطيط مثل "YYYY-MM-DD" لا يحتوي أي رموز أصلًا فيطبع نفسه دون تغيير. إذا بدت التواريخ المنسّقة غريبة، فتحقّق من أن التخطيط يستخدم قيم المرجع بالضبط.

تحليل النصوص إلى أوقات

تستخدم time.Parse(layout, value) التخطيطات نفسها، وتعيد خطأ يجب أن تفحصه:

دون منطقة في المدخل تعيد Parse توقيت UTC. النص نفسه لوقت الساعة قد يعني لحظات مختلفة حسب المنطقة، ولهذا توجد ParseInLocation. تسمّي رسالة الخطأ الجزء الذي فشلت مطابقته، وهذا يساعد عند تتبّع أخطاء تخطيط.

المناطق الزمنية

الـ time.Time لحظة زائد موقع يُستخدم للعرض. تغيير الموقع بـ In يغيّر طريقة الطباعة، لا اللحظة.

  • time.UTC متاح دائمًا. خزّن الأوقات وأرسلها بتوقيت UTC (أو RFC 3339 مع إزاحة) وحوّل فقط للعرض.
  • time.Local هي منطقة الجهاز. على الخوادم وفي الحاويات تكون غالبًا UTC، وعلى الحاسوب المحمول ليست كذلك، فتتصرّف الشيفرة التي تعتمد عليها بشكل مختلف في كل مكان.
  • تقرأ time.LoadLocation("Europe/Berlin") قاعدة بيانات IANA من نظام التشغيل. صور الحاويات المصغّرة تفتقدها غالبًا، فيعيد الاستدعاء عندها خطأ. الاستيراد الفارغ _ "time/tzdata" يضمّن قاعدة البيانات في ملفك التنفيذي (نحو 450 KB) فتعمل دائمًا. عالج الخطأ دائمًا.
  • تنشئ time.FixedZone(name, offsetSeconds) منطقة بإزاحة ثابتة. لا قواعد توقيت صيفي فيها، فاستخدمها للإزاحات التي تلقّيتها، لا للمناطق المسمّاة.

الحساب والمقارنة

أمور تلاحظها في المخرجات:

  • تعطي AddDate(0, 1, 0) على 31 يناير 3 مارس، لا 28 فبراير. تضيف Go شهرًا لتحصل على "31 فبراير" ثم تطبّع الفائض. إذا احتجت "اليوم نفسه في الشهر التالي مع التقييد بآخر الشهر"، فاكتب ذلك المنطق بنفسك.
  • تعيد Sub قيمة Duration، وحدّها الأقصى نحو 292 سنة. للفروق بالأيام التقويمية، قارن التواريخ عند منتصف الليل UTC واقسم على 24 ساعة.
  • للحصول على بداية اليوم، أعد بناء الوقت من Date(). تقرّب t.Truncate(24 * time.Hour) بالنسبة إلى الوقت الصفري في UTC، فتعطي إجابة خاطئة لأي منطقة غير UTC.

قارن بـ Equal وBefore وAfter، ولا تقارن بـ == أبدًا. يتضمّن time.Now() قراءة ساعة رتيبة، تُستخدم لتبقى time.Since صحيحة إذا عُدّلت ساعة النظام. تقارن == تلك القراءة والموقع أيضًا، فقد لا تتساوى قيمتا Time للحظة نفسها. وللسبب نفسه لا تستخدم time.Time مفتاحًا لخريطة دون تطبيعه أولًا (تزيل t.UTC().Round(0) القراءة الرتيبة).

الـ time.Time الصفري هو 1 يناير من السنة 1، الساعة 00:00 UTC. افحصه بـ t.IsZero().

قياس الوقت المنقضي

start := time.Now()
doWork()
log.Printf("doWork took %v", time.Since(start))

time.Since(start) تساوي time.Now().Sub(start)، وtime.Until(deadline) تساوي deadline.Sub(time.Now()). كلتاهما تستخدمان الساعة الرتيبة عند توفّرها، فهما آمنتان من تغييرات ساعة النظام. ولقياس أداء الشيفرة استخدم دعم قياس الأداء في الحزمة testing بدل التوقيت اليدوي.

المؤقّتات والـ tickers

تعيد time.After(d) قناة تستقبل مرة واحدة بعد d. وtime.Timer هو الشيء نفسه مع تابع Stop. وtime.Ticker يسلّم قيمة كل فترة حتى توقفه.

تصل النبضات الثلاث عند 20 و40 و60 ms قبل مؤقّت الـ 110 ms بوقت طويل، فيتوقّف البرنامج بعد النبضة الثالثة. تشغّل time.AfterFunc(d, f) الدالة f في goroutine خاصة بها بعد d، وهذا مفيد لعمل مؤجّل لمرة واحدة.

منذ Go 1.23 تُجمع المؤقّتات والـ tickers التي لم يعد يشير إليها شيء حتى لو لم تستدعِ Stop قط، ولم تعد قناة المؤقّت الموقوف أو المعاد ضبطه تسلّم قيمة قديمة. لكن استدعاء Stop مع defer يبقى الطريقة الواضحة للقول إن حياة الـ ticker انتهت. وعندما ينطبق حد زمني على عملية كاملة لا على انتظار واحد، تُقرأ context.WithTimeout عادة أفضل من مؤقّت.

الوقت في JSON

يُسلسَل time.Time من نصوص RFC 3339 وإليها في JSON تلقائيًا، بدقة النانوثانية:

type Event struct {
	Name string    `json:"name"`
	At   time.Time `json:"at"`
}
// {"name":"deploy","at":"2026-09-23T14:30:00Z"}

نص JSON بصيغة مختلفة يفشل فكّ ترميزه. للطوابع الزمنية Unix أو الصيغ المخصّصة، خزّن int64 أو نصًا وحوّل، أو عرّف نوعًا له UnmarshalJSON خاص به.

أخطاء شائعة

  • time.Sleep(1) أو time.Sleep(n) برقم مجرّد. هذه نانوثوانٍ.
  • تخطيطات بأرقام خاطئة. "2023-01-01" و"YYYY-MM-DD" ليست تخطيطات. استخدم "2006-01-02".
  • الخلط بين الدقائق والشهور. الدقائق 04، والشهور 01. تطبع "15:01" الساعة ثم الشهر، لا الدقيقة.
  • المقارنة بـ ==. استخدم Equal.
  • الاعتماد على time.Local. تختلف بين الأجهزة. كن صريحًا بـ time.UTC أو بموقع محمّل.
  • تجاهل الخطأ الصادر عن LoadLocation أو Parse. كلتاهما تفشلان مع المدخلات الحقيقية. تعيد Parse الفاشلة الوقت الصفري، الذي يُطبع كسنة 1، وتعيد LoadLocation الفاشلة موقعًا nil يجعل t.In(loc) تسبّب panic.

الأسئلة الشائعة

كيف أجعل البرنامج ينام (sleep) في Go؟

استدعِ time.Sleep مع time.Duration: time.Sleep(2 * time.Second) أو time.Sleep(500 * time.Millisecond). الرقم المجرّد مثل time.Sleep(2) يُترجم لكنه ينام 2 نانوثانية، لأن Duration تعدّ النانوثواني. ولا توقف Sleep إلا الـ goroutine الحالية.

لماذا تستخدم Go الصيغة 2006-01-02 15:04:05 لتنسيق التواريخ؟

تنسّق Go التواريخ بالمثال. التخطيط هو الوقت المرجعي Mon Jan 2 15:04:05 MST 2006 مكتوبًا بالشكل الذي تريد أن تبدو به مخرجاتك. أجزاؤه تتصاعد بالترتيب الأمريكي: الشهر 1، اليوم 2، الساعة 3 (15 بنظام 24 ساعة)، الدقيقة 4، الثانية 5، السنة 6 (2006)، إزاحة المنطقة 7 (-0700). لذا تعني "2006-01-02" سنة ثم شهرًا ثم يومًا، وتعني "02/01/2006" يومًا ثم شهرًا ثم سنة.

كيف أحلّل نص تاريخ في Go؟

استخدم time.Parse(layout, value) مع تخطيط مكتوب بالوقت المرجعي: t, err := time.Parse("2006-01-02", "2026-09-23"). افحص err دائمًا. دون معلومات منطقة في النص تكون النتيجة بتوقيت UTC؛ استخدم time.ParseInLocation لتفسيره في منطقة أخرى.

كيف أحصل على طابع زمني Unix في Go؟

تعيد time.Now().Unix() الثواني منذ 1 يناير 1970 UTC كقيمة int64. وتعطي UnixMilli() وUnixMicro() وUnixNano() وحدات أدق. وللاتجاه المعاكس استخدم time.Unix(sec, 0) أو time.UnixMilli(ms).

كيف أقارن وقتين في Go؟

استخدم t1.Before(t2) وt1.After(t2) وt1.Equal(t2). لا تستخدم ==: فهي تقارن أيضًا الموقع وقراءة الساعة الرتيبة، فقد لا تتساوى قيمتان للحظة نفسها. وتعطي t2.Sub(t1) الفرق كـ Duration.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن