בחלק הקודם עסקנו בהבנת אלמנט הזמן באפליקציה וראינו כיצד אפשר לייצר אובייקט זמן ב-JS באופן פשוט ומגוון. בחלק הזה נבין כיצד עובדים עם הזמן באופן מתקדם יותר בעזרת דוגמאות למקרים מייצגים.
האתמול הוא המחר
ישנם מקרים שבהם רוצים לקבל זמן שהוא יחסי להיום. נניח שיש לנו צורך להגדיר טווח תאריכים שנע בין אתמול לבין מחר. האינסטינקט הראשון הוא לייצר תאריכים באופן קשיח, אבל זה פתרון מוגבל מאד. איך מייצרים זמנים יחסיים בלי קשר לתאריך הנוכחי? יותר מכך, איך מתמודדים עם הבעיה הזאת כאשר לפעמים אתמול שייך לחודש הקודם, או מחר שייך לחודש הבא? בשביל להבין איך תוקפים את הבעיה צריך להכיר תכונה מסויימת של אובייקט ה-Date: הוא mutable, כלומר כמו כל אובייקט סטנדרטי אפשר לשנות את הערכים בתוכו. בראייה פונקציונלית זה אוי ואבוי, אבל במקרה שלנו זה ישרת אותנו.
נתחיל ביצירת היום הנוכחי:
const today = new Date()
ניצור את אתמול. נתחיל בדיוק באותו האופן. ניצור את היום שוב.
const yesterday = new Date()
נעזר במתודה שמאפשרת לנו לשנות את היום בתאריך בלבד.
yesterday.setDate(today.getDate() - 1)
לפי אותו ההיגיון נוכל לייצר גם את מחר
const tomorrow = new Date()
tomorrow.setDate(today.getDate() + 1)
כאשר תבדקו את הערכים אתם תגלו שמבחינת דרישה פשוטה קיבלנו את מה שביקשנו: 24 שעות אחורה ו-24 שעות קדימה. אבל לפעמים רוצים משהו קצת יותר מדויק. נעבור לדוגמה הבאה.
מוקדם בבוקר ומאוחר בלילה
הרבה פעמים מבקשים את תחילת היום או סופו, ולא שעה שרירותית כמו בדוגמה הקודמת. לכן אנחנו נעגל את השעות.
yesterday.setHours(0)
אם נבדוק עכשיו נגלה שהממזר עיגל רק את השעות. ומה עם השאר?
yesterday.setMinutes(0)
yesterday.setSeconds(0)
יופי. עכשיו אתמול מסודר. ומה עם מחר? כאן יש שתי גישות. הראשונה תקבע באופן קשיח מהו סופו של היום:
tomorrow.setHours(23)
tomorrow.setMinutes(59)
tomorrow.setSeconds(59)
הגישה השניה תגיד "רגע אחד, סופו של מחר הוא תחילתו של מחרתיים!" ואז:
tomorrow.setDate(today.getDate() + 2)
tomorrow.setHours(0)
tomorrow.setMinutes(0)
tomorrow.setSeconds(0)
ואם נרצה להגיע לאותה התוצאה כמו קודם בדיוק, נשנה את השורה האחרונה לזה:
tomorrow.setSeconds(-1)
חודש בחודשו
כשהבוסים שלכם יודעים איזה תותחים אתם ב-JS ויש להם דרישה חדשה בשביל שלא יהיה לכם משעמם. צריך לבחור מתחילת החודש עד סופו. נעשה משהו דומה לדוגמה הקודמת. רק צריך לזכור שהימים בחודש מתחילים ב-1 להבדיל מהזמן ומהחודשים.
const today = new Date()
const start = new Date()
start.setDate(1)
start.setHours(0)
start.setMinutes(0)
start.setSeconds(0)
ומה לגבי סוף החודש? להבדיל מהשעות ביום, אנחנו לא יודעים כמה ימים יש בחודש. אז נעשה את הטריק שעשינו בדוגמה הקודמת. נלך חודש קדימה ונוריד יום. אבל הפעם נהיה עוד יותר מתוחכמים ונגלה טריק חדש ומופלא: אפשר לייצר אובייקט חדש על בסיס אובייקט קיים!
const end = new Date(start)
end.setMonth(start.getMonth() + 1)
איזה יום היום?
השמחה כאן כפולה, כי הימים בשבוע מתחילים דווקא ביום א' ובאינדקס 0.
new Date().getDay()
// 3
אם רוצים להפוך את כל העסק לשמי, אפשר לעשות זאת בקלות ואפילו בשורה אחת:
console.log(["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][new Date().getDay()])
טוב, נעשה זאת בשתי שורות. אנחנו בעד קוד קריא.
const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
const dayOfWeek = new Date().getDay()
console.log(days[dayOfWeek])
// Wednesday
כמה זמן עבר בין היום ובין מחר?
האמת שכאן ממש הופתעתי לטובה. מסתבר שאפשר להחסיר שני תאריכים אחד מהשני.
const date1 = new Date(2022, 4, 11)
const date2 = new Date(2022, 4, 10)
console.log(date1 - date2)
// 86400000
ונזכור שאלה מילישניות. ולכן
console.log(86400000 / 1000 / 24 / 60 / 60)
// 1
אתם בטח שואלים את עצמכם איך זה שההפרש בין שני אובייקטים הוא מספר. שאלה מעולה! רואים שאתם תלמידים מצטיינים. בגלל שאתם כאלה תותחים, אתם בטח יודעים מה זה, נכון?:
Object.prototype.toString()
רק בשביל להראות שגם אני יודע, זאת הדרך של אובייקט לייצג את עצמו כאשר מנסים להתייחס אליו כמו אל מחרוזת. אתם יכולים להסתכל על זה בתור התיאור המילולי של האובייקט.
מסתבר שיש עוד מתודה שמיועדת להצגת הערך של האובייקט עצמו. הנה דוגמא בסיסית מאד:
const a = {}
a.valueOf = () => 5
a.toString = () => 'a fancy object'
console.log(String(a))
console.log(a - 1)
// a fancy object
// 4
הסבר פניך לתייר
אם נדמה לכם שזה הכל, אתם טועים ובגדול!
אנחנו אוהבים לראות תאריכים בפורמט כזה:
day/month/year
אבל לא תמיד זה ככה. לפעמים הסדר שונה, כמו בארה"ב:
month/day/year
לפעמים התו המפריד שונה:
day.month.year
ולפעמים רוצים להציג תאריך בצורה אחרת לגמרי:
יום רביעי, 11 במאי 2022
איך משיגים את כל התצורות האלה? טוב ששאלתם. בשביל זה יש את:
.toLocaleDateString()
אם תשתמשו בו כמו שהוא, תקבלו את ברירת המחדל. במקרה שלי זה ככה:
new Date().toLocaleDateString()
// '5/12/2022'
בפועל יש למתודה הזאת פרמטר שמאפשר לכם לבחור אחת מתוך שיטות הצגה מקובלות ברחבי העולם:
new Date().toLocaleDateString(‘en-US’)
// '5/12/2022'
new Date().toLocaleDateString('en-GB')
// '12/05/2022'
new Date().toLocaleDateString('de-DE')
// '12.5.2022'
new Date().toLocaleDateString('he-IL')
// '12.5.2022'
ומה אם אתם רוצים דרך קצת יותר מתוחכמת להציג תאריכים? מסתבר שיש דרך כזאת. יש פרמטר נוסף. אלה הן אפשרויות ההגדרה של הפורמט. השילוב בין שני הפרמטרים יכול לתת לכם כמעט כל צירוף מקובל של תאריכים. הנה כמה דוגמאות:
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }
console.log(new Date().toLocaleDateString('he-IL', options))
// יום חמישי, 12 במאי 2022
console.log(new Date().toLocaleDateString('en-US', options))
// Thursday, May 12, 2022
options.weekday = 'short'
console.log(new Date().toLocaleDateString('en-US', options))
// Thu, May 12, 2022
ועוד היד נטויה.
כדאי לכם מאד ללמוד על סטנדרטים לוקאליים (לא רק תאריכים) בקישור הזה. זה יכול להיות שימושי במקרה של פניה לקהל בינלאומי.
חבל על הזמן
במאמר זה נגענו במקרים בהם יש צורך במניפולציה על אובייקט ה-Date. ראינו איך אפשר לתמרן אותו בצורה שימושית, למדנו איך למדוד הפרשי זמן וכן כיצד להציג את הזמן לפי סטנדרטים מגוונים.
אתם אמורים להיות מצוידים עכשיו עם מספיק ידע בשביל שאם ראשת הצוות שלכם תשאל אתכם מתי אתם מתקנים את נושא התאריכים באתר, תוכלו לענות לה ככה:
new Date(Date.now() + 86400000)