time — פונקציות הקשורות לזמן

המודול time מספק פונקציות לקבלת השעה והתאריך הנוכחיים, מדידת מרווחי זמן והשהיות.

עידן הזמן (Time Epoch): דגמי OpenMV Cam מבוססי Alif ו-i.MX RT משתמשים בעידן POSIX של 1970-01-01 00:00:00 UTC. דגמי OpenMV Cam מבוססי STM32 משתמשים בעידן של 2000-01-01 00:00:00 UTC. ניתן לקבוע את שנת העידן בזמן ריצה באמצעות gmtime(0)[0].

שמירה על תאריך/שעה לוחי בפועל: זה דורש שעון זמן אמת (RTC). ב-OpenMV Cam זמן המערכת מסופק על ידי האובייקט machine.RTC. ניתן להגדיר את הזמן הלוחי הנוכחי באמצעות machine.RTC().datetime(tuple) והוא נשמר על ידי אחד מהבאים:

  • סוללת גיבוי (רכיב אופציונלי בחלק מדגמי OpenMV Cam).

  • פרוטוקול זמן רשתי כגון ntptime (דורש חיבור רשת).

  • הגדרתו ידנית בכל הפעלה. ה-RTC נשמר אז בדרך כלל לאורך איפוסים רכים, אך אובד בעת אובדן מתח אלא אם מותקנת סוללת גיבוי.

אם הזמן הלוחי אינו נשמר, הפונקציות שלהלן המתייחסות לזמן המוחלט הנוכחי לא יתנהגו כמצופה.

פונקציות

time.gmtime(secs: int | None = None) Tuple[int, int, int, int, int, int, int, int]
time.localtime(secs: int | None = None) Tuple[int, int, int, int, int, int, int, int]

ממיר את הזמן secs המבוטא בשניות מאז העידן (ראו למעלה) ל-tuple בן 8 איברים המכיל: (year, month, mday, hour, minute, second, weekday, yearday) אם secs לא סופק או הוא None, נעשה שימוש בזמן הנוכחי מה-RTC.

הפונקציה gmtime() מחזירה tuple תאריך-שעה ב-UTC, ו-localtime() מחזירה tuple תאריך-שעה בזמן מקומי.

הפורמט של הרשומות ב-tuple בן 8 האיברים הוא:

  • year כולל את המאה (למשל 2014).

  • month הוא 1-12

  • mday הוא 1-31

  • hour הוא 0-23

  • minute הוא 0-59

  • second הוא 0-59

  • weekday הוא 0-6 עבור שני-ראשון

  • yearday הוא 1-366

time.mktime(date_time_tuple: Tuple[int, int, int, int, int, int, int, int]) int

זוהי הפונקציה ההופכית של localtime. הארגומנט שלה הוא tuple מלא בן 8 איברים המבטא זמן כפי ש-localtime עושה. היא מחזירה מספר שלם שהוא מספר השניות מאז עידן הזמן.

time.sleep(seconds: float) None

ישן למשך מספר השניות הנתון. seconds יכול להיות מספר עם נקודה צפה, כדי לישון למשך מספר שניות שאינו שלם. עבור השהיות עדינות יותר או של מספרים שלמים בלבד השתמשו בפונקציות sleep_ms() ו-sleep_us().

קריאה ל-sleep(), כולל sleep(0), מובטח שתקרא לפונקציות callback ממתינות.

time.sleep_ms(ms: int) None

השהיה למשך מספר נתון של מילישניות, צריך להיות חיובי או 0.

פונקציה זו תשהה למשך מספר המילישניות הנתון לכל הפחות, אך עשויה להימשך זמן רב יותר אם עיבוד אחר חייב להתבצע, למשל מטפלי פסיקה או threads אחרים. העברת 0 עבור ms עדיין תאפשר לעיבוד אחר זה להתרחש. השתמשו ב-sleep_us() עבור השהיות מדויקות יותר.

קריאה ל-sleep_ms(), כולל sleep_ms(0), מובטח שתקרא לפונקציות callback ממתינות.

time.sleep_us(us: int) None

השהיה למשך מספר נתון של מיקרושניות, צריך להיות חיובי או 0.

פונקציה זו מנסה לספק השהיה מדויקת של us מיקרושניות לכל הפחות, אך היא עשויה להימשך זמן רב יותר אם למערכת יש עיבוד אחר בעדיפות גבוהה יותר לבצע.

time.ticks_ms() int

מחזיר מונה מילישניות עולה עם נקודת ייחוס שרירותית, הגולש (wraps around) לאחר ערך מסוים.

ערך הגלישה (wrap-around) אינו נחשף במפורש, אך נתייחס אליו כ-TICKS_MAX כדי לפשט את הדיון. המחזוריות של הערכים היא TICKS_PERIOD = TICKS_MAX + 1. מובטח ש-TICKS_PERIOD יהיה חזקה של שתיים, אך מלבד זאת הוא עשוי להשתנות מפורט לפורט. אותו ערך מחזוריות משמש את כל הפונקציות ticks_ms(), ticks_us(), ticks_cpu() (לשם הפשטות). לפיכך, פונקציות אלו יחזירו ערך בטווח [0 .. TICKS_MAX], כולל, בסך הכול TICKS_PERIOD ערכים. שימו לב שנעשה שימוש בערכים אי-שליליים בלבד. ברוב המקרים, עליכם להתייחס לערכים המוחזרים מפונקציות אלו כאל ערכים אטומים. הפעולות היחידות הזמינות עבורם הן הפונקציות ticks_diff() ו-ticks_add() המתוארות להלן.

הערה: ביצוע פעולות מתמטיות סטנדרטיות (+, -) או אופרטורים יחסיים (<, <=, >, >=) ישירות על ערכים אלו יוביל לתוצאה לא תקפה. ביצוע פעולות מתמטיות ולאחר מכן העברת תוצאותיהן כארגומנטים ל-ticks_diff() או ticks_add() יוביל גם הוא לתוצאות לא תקפות מהפונקציות האחרונות.

time.ticks_us() int

בדיוק כמו ticks_ms() למעלה, אך במיקרושניות.

time.ticks_cpu() int

דומה ל-ticks_ms() ו-ticks_us(), אך עם הרזולוציה הגבוהה ביותר האפשרית במערכת. זה בדרך כלל מחזורי שעון של ה-CPU, ולכן הפונקציה נקראת כך. אך אין הכרח שתהיה זו שעון CPU, מקור תזמון אחר הזמין במערכת (למשל טיימר ברזולוציה גבוהה) יכול לשמש במקום. יחידת התזמון המדויקת (הרזולוציה) של פונקציה זו אינה מצוינת ברמת המודול time, אך התיעוד עבור פורט מסוים עשוי לספק מידע ספציפי יותר. פונקציה זו מיועדת ל-benchmarking עדין מאוד או ללולאות זמן-אמת צמודות מאוד. הימנעו משימוש בה בקוד נייד. היא זמינה בכל דגמי OpenMV Cam.

time.ticks_add(ticks: int, delta: int) int

מסיט ערך ticks במספר נתון, שיכול להיות חיובי או שלילי. בהינתן ערך ticks, פונקציה זו מאפשרת לחשב ערך ticks של delta ticks לפניו או אחריו, בהתאם להגדרת הערכים על פי אריתמטיקה מודולרית (ראו ticks_ms() למעלה). הפרמטר ticks חייב להיות תוצאה ישירה של קריאה לפונקציות ticks_ms(), ticks_us() או ticks_cpu() (או מקריאה קודמת ל-ticks_add()). עם זאת, delta יכול להיות מספר שלם שרירותי או ביטוי מספרי. ticks_add() שימושית לחישוב מועדי סיום עבור אירועים/משימות. (הערה: עליכם להשתמש בפונקציה ticks_diff() כדי לעבוד עם מועדי סיום.)

דוגמאות:

# Find out what ticks value there was 100ms ago
print(ticks_add(time.ticks_ms(), -100))

# Calculate deadline for operation and test for it
deadline = ticks_add(time.ticks_ms(), 200)
while ticks_diff(deadline, time.ticks_ms()) > 0:
    do_a_little_of_something()

# Find out TICKS_MAX used by this port
print(ticks_add(0, -1))
time.ticks_diff(ticks1: int, ticks2: int) int

מודד את הפרש ה-ticks בין ערכים המוחזרים מהפונקציות ticks_ms(), ticks_us() או ticks_cpu(), כערך מסומן שעשוי לגלוש.

סדר הארגומנטים זהה לזה של אופרטור החיסור, ל-ticks_diff(ticks1, ticks2) יש אותה משמעות כמו ל-ticks1 - ticks2. עם זאת, ערכים המוחזרים מהפונקציות ticks_ms() וכו« עשויים לגלוש, ולכן שימוש ישיר בחיסור עליהם יפיק תוצאה שגויה. זו הסיבה שיש צורך ב-ticks_diff(), היא מממשת אריתמטיקה מודולרית (או ליתר דיוק, טבעתית) כדי להפיק תוצאה נכונה גם עבור ערכים שגלשו (כל עוד אינם מרוחקים מדי זה מזה, ראו להלן). הפונקציה מחזירה ערך מסומן בטווח [-TICKS_PERIOD/2 .. TICKS_PERIOD/2-1] (זו הגדרת טווח טיפוסית למספרים שלמים בינאריים מסומנים במשלים לשתיים). אם התוצאה שלילית, פירוש הדבר ש-ticks1 התרחש מוקדם יותר בזמן מ-ticks2. אחרת, פירוש הדבר ש-ticks1 התרחש לאחר ticks2. זה תקף רק אם ticks1 ו-ticks2 מרוחקים זה מזה ב-TICKS_PERIOD/2-1 ticks לכל היותר. אם זה אינו מתקיים, תוחזר תוצאה שגויה. באופן ספציפי, אם שני ערכי ticks מרוחקים ב-TICKS_PERIOD/2-1 ticks, הפונקציה תחזיר ערך זה. עם זאת, אם TICKS_PERIOD/2 של ticks בזמן אמת חלפו ביניהם, הפונקציה תחזיר -TICKS_PERIOD/2 במקום, כלומר ערך התוצאה יגלוש לטווח השלילי של הערכים האפשריים.

נימוק לא פורמלי של האילוצים שלעיל: נניח שאתם נעולים בחדר ללא אמצעי לנטר את חלוף הזמן מלבד שעון סטנדרטי בעל 12 חריצים. אז אם תביטו בלוח השעון כעת, ולא תביטו שוב במשך 13 שעות נוספות (למשל, אם תיפלו לשינה ארוכה), אז כשתביטו שוב לבסוף, ייתכן שייראה לכם שחלפה רק שעה אחת. כדי להימנע מטעות זו, פשוט הביטו בשעון באופן סדיר. היישום שלכם צריך לעשות את אותו הדבר. מטפורת ”השינה הארוכה מדי“ ממופה גם ישירות להתנהגות היישום: אל תיתנו ליישום שלכם להריץ משימה בודדת כלשהי למשך זמן רב מדי. הריצו משימות בשלבים, ובצעו מעקב זמן ביניהם.

ticks_diff() תוכננה להתאים לדפוסי שימוש שונים, ביניהם:

  • Polling עם פסק זמן. במקרה זה, סדר האירועים ידוע, ותתמודדו רק עם תוצאות חיוביות של ticks_diff()

    # Wait for GPIO pin to be asserted, but at most 500us
    start = time.ticks_us()
    while pin.value() == 0:
        if time.ticks_diff(time.ticks_us(), start) > 500:
            raise TimeoutError
    
  • תזמון אירועים. במקרה זה, תוצאת ticks_diff() עשויה להיות שלילית אם אירוע מתעכב:

    # This code snippet is not optimized
    now = time.ticks_ms()
    scheduled_time = task.scheduled_time()
    if ticks_diff(scheduled_time, now) > 0:
        print("Too early, let's nap")
        sleep_ms(ticks_diff(scheduled_time, now))
        task.run()
    elif ticks_diff(scheduled_time, now) == 0:
        print("Right at time!")
        task.run()
    elif ticks_diff(scheduled_time, now) < 0:
        print("Oops, running late, tell task to run faster!")
        task.run(run_faster=true)
    

הערה: אל תעבירו ערכי time() ל-ticks_diff(), עליכם להשתמש בפעולות מתמטיות רגילות עליהם. אך שימו לב ש-time() עשויה (ואכן תעשה זאת) גם לגלוש. זה ידוע בשם https://en.wikipedia.org/wiki/Year_2038_problem .

time.time() int

מחזיר את מספר השניות, כמספר שלם, מאז העידן, בהנחה שה-RTC הבסיסי מוגדר ונשמר כמתואר לעיל. אם RTC אינו מוגדר, פונקציה זו מחזירה את מספר השניות מאז נקודת ייחוס בזמן הספציפית לפורט (עבור לוחות מוטמעים ללא RTC מגובה-סוללה, בדרך כלל מאז ההפעלה או האיפוס). אם ברצונכם לפתח יישום MicroPython נייד, אל לכם להסתמך על פונקציה זו כדי לספק דיוק גבוה משנייה. אם אתם זקוקים לדיוק גבוה יותר, חותמות זמן מוחלטות, השתמשו ב-time_ns(). אם זמנים יחסיים מקובלים אזי השתמשו בפונקציות ticks_ms() ו-ticks_us(). אם אתם זקוקים לזמן לוחי, gmtime() או localtime() ללא ארגומנט היא בחירה טובה יותר.

הבדל מ-CPython

ב-CPython פונקציה זו מחזירה את מספר השניות מאז עידן Unix (1970-01-01 00:00 UTC) כערך עם נקודה צפה, בדרך כלל בדיוק של מיקרושניות. ב-OpenMV Cam היא מחזירה מספר שלם בדיוק של שנייה אחת – החומרה אינה יכולה לייצג גם טווח זמן ארוך וגם דיוק תת-שנייתי במספר עם נקודה צפה – והעידן שונה בין לוח ללוח (ראו עידן הזמן למעלה). ללא RTC מגובה-סוללה שהוגדר, היא במקום זאת סופרת שניות מאז ההפעלה/האיפוס.

time.time_ns() int

דומה ל-time() אך מחזירה ננו-שניות מאז העידן, כמספר שלם (בדרך כלל מספר שלם גדול, ולכן יקצה זיכרון ב-heap).

בנאים

class time.clock

מחזיר אובייקט שעון.

מתודות

tick() None

מתחיל לעקוב אחר הזמן החולף.

fps() float

מפסיק לעקוב אחר הזמן החולף ומחזיר את ה-FPS הנוכחי (פריימים לשנייה).

תמיד קראו ל-tick תחילה לפני קריאה לפונקציה זו.

avg() float

מפסיק לעקוב אחר הזמן החולף ומחזיר את הזמן החולף הממוצע הנוכחי במילישניות.

תמיד קראו ל-tick תחילה לפני קריאה לפונקציה זו.

reset() None

מאפס את אובייקט השעון.