הבסיס בתוכנית אחת
time.Now() מחזירה את הזמן המקומי הנוכחי, time.Sleep משהה את ה-goroutine הנוכחית, time.Since מודדת זמן שעבר, ו-time.Date בונה רגע מסוים. שאר הדף עובר על כל חלק בתורו. הדוגמאות משתמשות בתאריכים קבועים וב-UTC כדי שהפלט שלהן יהיה זהה בכל מקום שבו מריצים אותן.
Sleep ו-Duration
time.Duration הוא int64 שסופר ננו שניות. החבילה מגדירה קבועים לבניית ערכים קריאים:
| קבוע | ערך |
|---|---|
time.Nanosecond | 1 |
time.Microsecond | 1000 ns |
time.Millisecond | 1000 µs |
time.Second | 1000 ms |
time.Minute | 60 s |
time.Hour | 60 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.
ה-tokens של הפריסה שתצטרכו הכי הרבה:
| Token | משמעות | דוגמה |
|---|---|---|
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 או PM | AM |
.000 / .999 | שברי שנייה (קבוע / בלי אפסים בסוף) | .250 / .25 |
MST | קיצור אזור הזמן | UTC |
-0700 / -07:00 | היסט מספרי של אזור הזמן | +0000 / +00:00 |
Z07:00 | כמו -07:00, אבל מדפיס Z עבור UTC | Z |
פריסות מוגדרות מראש:
| קבוע | פריסה |
|---|---|
time.RFC3339 | 2006-01-02T15:04:05Z07:00 (השתמשו בזה ל-APIs ול-JSON) |
time.RFC3339Nano | 2006-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.Kitchen | 3:04PM |
time.RFC1123 | Mon, 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" לא מכילה אף token ומודפסת כמו שהיא. אם תאריכים מעוצבים נראים מוזר, בדקו שהפריסה משתמשת בדיוק בערכי הייחוס.
פענוח מחרוזות לזמנים
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 כמפתח של map בלי לנרמל אותו קודם (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()). שתיהן משתמשות בשעון המונוטוני כשהוא זמין, ולכן הן בטוחות מפני שינויים בשעון המערכת. למדידת ביצועים של קוד, השתמשו בתמיכה של Go ב-benchmarks בחבילה testing במקום למדוד זמן ביד.
Timers ו-tickers
time.After(d) מחזירה channel שמקבל ערך פעם אחת אחרי d. time.Timer הוא אותו דבר עם מתודת Stop. time.Ticker מספק ערך בכל מחזור עד שעוצרים אותו.
שלושת ה-ticks ב-20, 40 ו-60 ms מגיעים הרבה לפני ה-timer של 110 ms, כך שהתוכנית נעצרת אחרי ה-tick השלישי. time.AfterFunc(d, f) מריצה את f ב-goroutine משלה אחרי d, וזה נוח לעבודה חד פעמית מושהית.
מאז Go 1.23, timers ו-tickers שאין אליהם עוד הפניה מפונים על ידי ה-garbage collector גם אם אף פעם לא קוראים ל-Stop, וה-channel של timer שנעצר או אופס כבר לא מספק ערך ישן. קריאה ל-Stop עם defer היא עדיין הדרך הברורה לומר שחייו של ה-ticker הסתיימו. כשמגבלת זמן חלה על פעולה שלמה ולא על המתנה אחת, context.WithTimeout בדרך כלל נקרא טוב יותר מ-timer.
זמן ב-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 בפורמט אחר נכשלת ב-unmarshal. ל-Unix timestamps או לפורמטים מותאמים, שמרו 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 timestamp ב-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.