הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

מעגל היצירה: בעיה, פיתרון, יכולת, בעיה

16/09/2023

כשיש בעיה הדבר הטבעי לעשות הוא לחפש פיתרון. כשמצאנו הפיתרון יפתח בפנינו אפשרויות ויכולות חדשות, איתן נוכל ליצור כלים חדשים שיובילו לבעיות חדשות.

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

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

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

זה רק קוד

15/09/2023

קחו את הקוד הכי יפה, שימו אותו בארון ותחזרו עוד 5 שנים. הוא עדיין יישאר יפה? הוא עדיין יעבוד? יהיה עדיין מי שירצה לתחזק אותו? לא בטוח בכלל.

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

כשאנחנו אומרים ש"קוד זה רק קוד" המשמעות היא-

  1. לא נקשרנו לקוד שכתבנו. אנחנו נשמח לבנות מחדש מנגנונים כולל מנגנוני ליבה של המערכת אם בניה מחדש כזאת תשפר את עבודה המערכת.

  2. בנינו מראש מנגנונים שיאפשרו לשנות את הקוד כשנצטרך. הקוד לא "מתעד את עצמו" אלא יש הערות במקום שמסבירות מה המטרה של הקוד ומה הפונקציות צריכות לעשות. יצרנו תוכניות בדיקה כדי שאפשר יהיה לשנות חלקים בקוד ולוודא שלא שברנו כלום.

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

  4. הקפדנו להשתמש בשפה מנותקת לגבי הקוד. זה לא ה"קוד שלי" או "המנוע של בר", זה "ממשק המשתמש", ה"מנוע" או "ה API". ככל שנקפיד להוציא את הכותבים מהקוד ולהפוך אותו לתוצאת עבודה משותפת של כל הצוות כך יהיה קל יותר לשתף אחריות, אשמה וגם לשכתב כשצריך.

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

שני הכללים של Generators בפייתון

14/09/2023

לפייתון לא אכפת איזה Generators נרצה לכתוב, אבל יש שני כללים שכשאנחנו חורגים מהם כדאי לחשוב שנית אם Generator הוא הפיתרון הנכון-

  1. גנרטור לא מחשב את כל הערכים מראש.

  2. גנרטור לא תופס יותר זיכרון ככל שמחשבים יותר פריטים.

האינטואיציה של הכלל הראשון היא שאם גנרטור צריך לחשב את כל הערכים מראש עדיף להחזיר את כל מה שהוא חישב בתור רשימה (או כל מבנה נתונים אחר) ולא צריך לעשות yield כל פעם לאיבר הבא. האינטואיציה של הכלל השני היא שאנשים שמשתמשים בלולאת for עם גנרטור לא מצפים שצריכת הזיכרון תעלה ככל שמושכים יותר איברים, ובמקום אנחנו חושבים שכל פריט בו אנחנו מטפלים משוחרר מהזיכרון באיטרציה הבאה של הלולאה.

ועם הכללים האלה אפשר לראות כמה Generators שעדיף היה לכתוב אותם בתור פונקציות רגילות. דוגמה ראשונה היא groupby, שבניגוד לזו מ itertools מחזירה את כל הקבוצות עם כל הפריטים בכל קבוצה:

def groupby(sequence, key):
    groups = defaultdict(list)
    for item in sequence:
        groups[key(item)].append(item)

    for key, values in groups.items():
        yield key, values

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

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

import time
import random

def uniq(seq):
    seen = set()
    for i in seq:
        if i not in seen:
            yield i
            seen.add(i)

def random_numbers():
    while True:
        yield random.randint(1, 100)

for i in uniq(random_numbers()):
    time.sleep(2)
    print(i)

אם נדלג בעין על הגדרת הפונקציה uniq, אפשר לפספס את תוספת הזיכרון שתגרום לתוכנית בסוף להתרסק. כשאני מוותר על הגנרטור ומעביר את הקוד פנימה ללולאה התוצאה לדעתי יותר ברורה:

import time
import random

def random_numbers():
    while True:
        yield random.randint(1, 100)

seen = set()
for i in random_numbers():
    if i not in seen:
        time.sleep(2)
        print(i)
        seen.add(i)

איך להפעיל בקלות פונקציית C מתוך פייתון

13/09/2023

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

קוד? בטח. התוכנית הבאה טוענת את libc ומפעילה את הפונקציה rand מתוכה:

from ctypes import *
from ctypes.util import find_library

libc_location = find_library('c')
libc = cdll.LoadLibrary(libc_location)

print(libc.rand())

פשוט לא? בשביל להעביר פרמטרים לתוכנית C יש לנו 3 סוגי משתנים מובנים ב ctypes שאפשר להעביר כמו שהם:

  1. האוביקט None יהפוך ל NULL ב C

  2. אוביקט Bytes יהפוך ל const chat * ב C

  3. מספר int יהפוך ל int ב C.

לכן בשביל להפעיל את הפונקציה mkdir וליצור תיקייה חדשה מתוך קוד C אני יכול לכתוב:

from ctypes import *
from ctypes.util import find_library

libc_location = find_library('c')
libc = cdll.LoadLibrary(libc_location)

libc.mkdir(b"newdir")

בשביל העברת פרמטרים יותר מתוחכמים אנחנו צריכים להגדיר את טיפוסי הנתונים של הפונקציות ב C. זו אגב נקודת התורפה של ספריית ctypes, שמקבלת מענה רק בספריה אחרת בשם cffi, אבל זה כבר סיפור לפוסט אחר. בינתיים בכל מקרה ובתוך ctypes הדרך להפעיל פונקציות שצריכות פרמטרים יותר מתוחכמים היא להגדיר את טיפוסי הנתונים של אותן פונקציות. לדוגמה הפונקציה pow של libm מקבלת שני double-ים ומחזירה double ולכן בשביל להפעיל אותה אני כותב:

from ctypes import *
from ctypes.util import find_library

libm = cdll.LoadLibrary(find_library('m'))

# Works - use c_double, returns c_double
libm.pow.restype = c_double
libm.pow.argtypes = [c_double, c_double]
print(libm.pow(c_double(2), c_double(3)))

ואפשר כמובן להגדיר גם מבני נתונים מסובכים יותר כמו struct-ים ופונקציות, לדוגמה בפוסט כאן הראיתי איך להעביר פונקציית Callback מפייתון לפונקציית C בעזרת ספריית ctypes.

סך הכל ctypes מספקת פיתרון מאוד נוח כשאנחנו צריכים לגשת לספריה מקומפלת קיימת מתוך קוד פייתון. ככל שהספריה תהיה יותר גדולה והממשק יותר מתוחכם, אולי נרצה להוסיף פיתרון כמו cffi שיודע לקרוא הגדרות של פונקציות בשפת C ולתרגם אותן אוטומטית לפייתון, וכך לחסוך לעצמנו את ההגדרה הכפולה.

טייפסקריפט ללא טייפסקריפט: קריאת JSDoc

12/09/2023

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

המשך קריאה

למה שמישהו ירצה להיפרד מטייפסקריפט?

11/09/2023

הויכוח ברוב הרשתות בימים האחרונים סביב ההודעה של DHH על פרידה מטייפסקריפט בפרויקט Turbo8 הציג את הסיפור בתור בחירה פשוטה בין "כתיבת קוד מהיר" ל"כתיבת קוד איכותי", והיה מאוד מפתה לשים את DHH במשבצת ה"כתיבת קוד מהיר". אבל לפני שארגיש בנוח עם החלוקה הזאת, יהיה מעניין להיכנס ל PR הרלוונטי ולראות מה זה בעצם אומר להיפרד מ TypeScript ולמה DHH היה כל כך נחוש.

כאן אפשר למצוא את כל הקבצים שהשתנו: https://github.com/hotwired/turbo/pull/971/files.

בואו ננסה למצוא כמה מוקדים מעניינים-

המשך קריאה

חדש ב Node.JS - תמיכה מובנית בקבצי env

10/09/2023

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

בקיצור בואו נראה על מה מדובר-

המשך קריאה

מתי עוברים לשעון חורף (ועוד כמה טיפים על אזורי זמן)

09/09/2023

מכונות יוניקס - ולכן גם לינוקס ומק, שומרות בסיס נתונים של אזורי זמן בתיקיה מיוחדת על המחשב שנקראת /usr/share/zoneinfo. הקבצים שם הם בינאריים שמתארים את ההפרש של אזור הזמן שמתאים לקובץ, וגם את כל השינויים באזור הזמן ובמיוחד בהיבט של מעבר בין שעון קיץ לחורף. בואו נצא לחקור קצת את הקבצים שם ולשחק עם אזורי זמן.

תחילה רשימת הקבצים בתיקייה, לפחות אצלי על המק:

$ ls -ld /usr/share/zoneinfo/
lrwxr-xr-x  1 root  wheel  38 Apr 28 23:44 /usr/share/zoneinfo/ -> /var/db/timezone/tz/2023c.1.0/zoneinfo

$ ls -F /var/db/timezone/tz/2023c.1.0/zoneinfo/
+VERSION        CET             Eire            GMT0            Japan           Navajo          Turkey          leapseconds
Africa/         CST6CDT         Etc/            Greenwich       Kwajalein       PRC             UCT             posixrules
America/        Canada/         Europe/         HST             Libya           PST8PDT         US/             zone.tab
Antarctica/     Chile/          Factory         Hongkong        MET             Pacific/        UTC
Arctic/         Cuba            GB              Iceland         MST             Poland          Universal
Asia/           EET             GB-Eire         Indian/         MST7MDT         Portugal        W-SU
Atlantic/       EST             GMT             Iran            Mexico/         ROC             WET
Australia/      EST5EDT         GMT+0           Israel          NZ              ROK             Zulu
Brazil/         Egypt           GMT-0           Jamaica         NZ-CHAT         Singapore       iso3166.tab

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

$ xxd /usr/share/zoneinfo/Israel| head -4
00000000: 545a 6966 3200 0000 0000 0000 0000 0000  TZif2...........
00000010: 0000 0000 0000 0008 0000 0008 0000 0000  ................
00000020: 0000 0094 0000 0008 0000 0011 9e30 4588  .............0E.
00000030: c859 cf00 c8fa a600 c938 9c80 cce5 eb80  .Y.......8......

הפורמט מתואר בפירוט בתיעוד כאן. הדבר החשוב משם הוא לראות שקובץ כזה כולל הרבה מעבר להפרש השעות. הפקודה zdump מדפיסה את הזמן הנוכחי באזור זמן שמתאים לקובץ מהמאגר:

$ zdump Israel
Israel  Fri Sep  8 14:14:43 2023 IDT

$ zdump Europe/Paris
Europe/Paris  Fri Sep  8 13:15:03 2023 CEST

$ zdump Chile/Continental
Chile/Continental  Fri Sep  8 08:15:45 2023 -03

ועם המתג המתאים היא יכולה להציג את השינויים שקובץ zoneinfo כולל, כלומר המעברים בין שעון חורף לקיץ. זה המצב אצלנו:

$ zdump -v Israel

Israel  Fri Dec 13 20:45:52 1901 UTC = Fri Dec 13 23:06:32 1901 JMT isdst=0
Israel  Sat Dec 14 20:45:52 1901 UTC = Sat Dec 14 23:06:32 1901 JMT isdst=0
Israel  Mon Dec 31 21:39:19 1917 UTC = Mon Dec 31 23:59:59 1917 JMT isdst=0
Israel  Mon Dec 31 21:39:20 1917 UTC = Mon Dec 31 23:39:20 1917 IST isdst=0
Israel  Fri May 31 23:59:59 1940 UTC = Sat Jun  1 01:59:59 1940 IST isdst=0
Israel  Sat Jun  1 00:00:00 1940 UTC = Sat Jun  1 03:00:00 1940 IDT isdst=1
Israel  Mon Sep 30 23:59:59 1940 UTC = Tue Oct  1 02:59:59 1940 IDT isdst=1
Israel  Tue Oct  1 00:00:00 1940 UTC = Tue Oct  1 02:00:00 1940 IST isdst=0
Israel  Sat Nov 16 23:59:59 1940 UTC = Sun Nov 17 01:59:59 1940 IST isdst=0
Israel  Sun Nov 17 00:00:00 1940 UTC = Sun Nov 17 03:00:00 1940 IDT isdst=1
Israel  Sat Oct 31 23:59:59 1942 UTC = Sun Nov  1 02:59:59 1942 IDT isdst=1
Israel  Sun Nov  1 00:00:00 1942 UTC = Sun Nov  1 02:00:00 1942 IST isdst=0
Israel  Wed Mar 31 23:59:59 1943 UTC = Thu Apr  1 01:59:59 1943 IST isdst=0
Israel  Thu Apr  1 00:00:00 1943 UTC = Thu Apr  1 03:00:00 1943 IDT isdst=1
Israel  Sun Oct 31 23:59:59 1943 UTC = Mon Nov  1 02:59:59 1943 IDT isdst=1
Israel  Mon Nov  1 00:00:00 1943 UTC = Mon Nov  1 02:00:00 1943 IST isdst=0
Israel  Fri Mar 31 23:59:59 1944 UTC = Sat Apr  1 01:59:59 1944 IST isdst=0
Israel  Sat Apr  1 00:00:00 1944 UTC = Sat Apr  1 03:00:00 1944 IDT isdst=1
Israel  Tue Oct 31 23:59:59 1944 UTC = Wed Nov  1 02:59:59 1944 IDT isdst=1
Israel  Wed Nov  1 00:00:00 1944 UTC = Wed Nov  1 02:00:00 1944 IST isdst=0
Israel  Sun Apr 15 23:59:59 1945 UTC = Mon Apr 16 01:59:59 1945 IST isdst=0
Israel  Mon Apr 16 00:00:00 1945 UTC = Mon Apr 16 03:00:00 1945 IDT isdst=1
Israel  Wed Oct 31 23:59:59 1945 UTC = Thu Nov  1 02:59:59 1945 IDT isdst=1
Israel  Thu Nov  1 00:00:00 1945 UTC = Thu Nov  1 02:00:00 1945 IST isdst=0
Israel  Mon Apr 15 23:59:59 1946 UTC = Tue Apr 16 01:59:59 1946 IST isdst=0
Israel  Tue Apr 16 00:00:00 1946 UTC = Tue Apr 16 03:00:00 1946 IDT isdst=1
Israel  Thu Oct 31 23:59:59 1946 UTC = Fri Nov  1 02:59:59 1946 IDT isdst=1
Israel  Fri Nov  1 00:00:00 1946 UTC = Fri Nov  1 02:00:00 1946 IST isdst=0
Israel  Sat May 22 23:59:59 1948 UTC = Sun May 23 01:59:59 1948 IST isdst=0
Israel  Sun May 23 00:00:00 1948 UTC = Sun May 23 04:00:00 1948 IDDT isdst=1
Israel  Tue Aug 31 23:59:59 1948 UTC = Wed Sep  1 03:59:59 1948 IDDT isdst=1
Israel  Wed Sep  1 00:00:00 1948 UTC = Wed Sep  1 03:00:00 1948 IDT isdst=1
Israel  Sun Oct 31 23:59:59 1948 UTC = Mon Nov  1 02:59:59 1948 IDT isdst=1
Israel  Mon Nov  1 00:00:00 1948 UTC = Mon Nov  1 02:00:00 1948 IST isdst=0
Israel  Sat Apr 30 23:59:59 1949 UTC = Sun May  1 01:59:59 1949 IST isdst=0
Israel  Sun May  1 00:00:00 1949 UTC = Sun May  1 03:00:00 1949 IDT isdst=1
Israel  Mon Oct 31 23:59:59 1949 UTC = Tue Nov  1 02:59:59 1949 IDT isdst=1
Israel  Tue Nov  1 00:00:00 1949 UTC = Tue Nov  1 02:00:00 1949 IST isdst=0
Israel  Sat Apr 15 23:59:59 1950 UTC = Sun Apr 16 01:59:59 1950 IST isdst=0
Israel  Sun Apr 16 00:00:00 1950 UTC = Sun Apr 16 03:00:00 1950 IDT isdst=1
Israel  Thu Sep 14 23:59:59 1950 UTC = Fri Sep 15 02:59:59 1950 IDT isdst=1
Israel  Fri Sep 15 00:00:00 1950 UTC = Fri Sep 15 02:00:00 1950 IST isdst=0
Israel  Sat Mar 31 23:59:59 1951 UTC = Sun Apr  1 01:59:59 1951 IST isdst=0
Israel  Sun Apr  1 00:00:00 1951 UTC = Sun Apr  1 03:00:00 1951 IDT isdst=1
Israel  Sat Nov 10 23:59:59 1951 UTC = Sun Nov 11 02:59:59 1951 IDT isdst=1
Israel  Sun Nov 11 00:00:00 1951 UTC = Sun Nov 11 02:00:00 1951 IST isdst=0
Israel  Sat Apr 19 23:59:59 1952 UTC = Sun Apr 20 01:59:59 1952 IST isdst=0
Israel  Sun Apr 20 00:00:00 1952 UTC = Sun Apr 20 03:00:00 1952 IDT isdst=1
Israel  Sat Oct 18 23:59:59 1952 UTC = Sun Oct 19 02:59:59 1952 IDT isdst=1
Israel  Sun Oct 19 00:00:00 1952 UTC = Sun Oct 19 02:00:00 1952 IST isdst=0
Israel  Sat Apr 11 23:59:59 1953 UTC = Sun Apr 12 01:59:59 1953 IST isdst=0
Israel  Sun Apr 12 00:00:00 1953 UTC = Sun Apr 12 03:00:00 1953 IDT isdst=1
Israel  Sat Sep 12 23:59:59 1953 UTC = Sun Sep 13 02:59:59 1953 IDT isdst=1
Israel  Sun Sep 13 00:00:00 1953 UTC = Sun Sep 13 02:00:00 1953 IST isdst=0
Israel  Sat Jun 12 23:59:59 1954 UTC = Sun Jun 13 01:59:59 1954 IST isdst=0
Israel  Sun Jun 13 00:00:00 1954 UTC = Sun Jun 13 03:00:00 1954 IDT isdst=1
Israel  Sat Sep 11 23:59:59 1954 UTC = Sun Sep 12 02:59:59 1954 IDT isdst=1
Israel  Sun Sep 12 00:00:00 1954 UTC = Sun Sep 12 02:00:00 1954 IST isdst=0
Israel  Sat Jun 11 23:59:59 1955 UTC = Sun Jun 12 01:59:59 1955 IST isdst=0
Israel  Sun Jun 12 00:00:00 1955 UTC = Sun Jun 12 03:00:00 1955 IDT isdst=1
Israel  Sat Sep 10 23:59:59 1955 UTC = Sun Sep 11 02:59:59 1955 IDT isdst=1
Israel  Sun Sep 11 00:00:00 1955 UTC = Sun Sep 11 02:00:00 1955 IST isdst=0
Israel  Sat Jun  2 23:59:59 1956 UTC = Sun Jun  3 01:59:59 1956 IST isdst=0
Israel  Sun Jun  3 00:00:00 1956 UTC = Sun Jun  3 03:00:00 1956 IDT isdst=1
Israel  Sat Sep 29 23:59:59 1956 UTC = Sun Sep 30 02:59:59 1956 IDT isdst=1
Israel  Sun Sep 30 00:00:00 1956 UTC = Sun Sep 30 02:00:00 1956 IST isdst=0
Israel  Sat Apr 27 23:59:59 1957 UTC = Sun Apr 28 01:59:59 1957 IST isdst=0
Israel  Sun Apr 28 00:00:00 1957 UTC = Sun Apr 28 03:00:00 1957 IDT isdst=1
Israel  Sat Sep 21 23:59:59 1957 UTC = Sun Sep 22 02:59:59 1957 IDT isdst=1
Israel  Sun Sep 22 00:00:00 1957 UTC = Sun Sep 22 02:00:00 1957 IST isdst=0
Israel  Sat Jul  6 21:59:59 1974 UTC = Sat Jul  6 23:59:59 1974 IST isdst=0
Israel  Sat Jul  6 22:00:00 1974 UTC = Sun Jul  7 01:00:00 1974 IDT isdst=1
Israel  Sat Oct 12 20:59:59 1974 UTC = Sat Oct 12 23:59:59 1974 IDT isdst=1
Israel  Sat Oct 12 21:00:00 1974 UTC = Sat Oct 12 23:00:00 1974 IST isdst=0
Israel  Sat Apr 19 21:59:59 1975 UTC = Sat Apr 19 23:59:59 1975 IST isdst=0
Israel  Sat Apr 19 22:00:00 1975 UTC = Sun Apr 20 01:00:00 1975 IDT isdst=1
Israel  Sat Aug 30 20:59:59 1975 UTC = Sat Aug 30 23:59:59 1975 IDT isdst=1
Israel  Sat Aug 30 21:00:00 1975 UTC = Sat Aug 30 23:00:00 1975 IST isdst=0
Israel  Sat Aug  2 21:59:59 1980 UTC = Sat Aug  2 23:59:59 1980 IST isdst=0
Israel  Sat Aug  2 22:00:00 1980 UTC = Sun Aug  3 01:00:00 1980 IDT isdst=1
Israel  Sat Sep 13 21:59:59 1980 UTC = Sun Sep 14 00:59:59 1980 IDT isdst=1
Israel  Sat Sep 13 22:00:00 1980 UTC = Sun Sep 14 00:00:00 1980 IST isdst=0
Israel  Sat May  5 21:59:59 1984 UTC = Sat May  5 23:59:59 1984 IST isdst=0
Israel  Sat May  5 22:00:00 1984 UTC = Sun May  6 01:00:00 1984 IDT isdst=1
Israel  Sat Aug 25 21:59:59 1984 UTC = Sun Aug 26 00:59:59 1984 IDT isdst=1
Israel  Sat Aug 25 22:00:00 1984 UTC = Sun Aug 26 00:00:00 1984 IST isdst=0
Israel  Sat Apr 13 21:59:59 1985 UTC = Sat Apr 13 23:59:59 1985 IST isdst=0
Israel  Sat Apr 13 22:00:00 1985 UTC = Sun Apr 14 01:00:00 1985 IDT isdst=1
Israel  Sat Aug 31 20:59:59 1985 UTC = Sat Aug 31 23:59:59 1985 IDT isdst=1
Israel  Sat Aug 31 21:00:00 1985 UTC = Sat Aug 31 23:00:00 1985 IST isdst=0
Israel  Sat May 17 21:59:59 1986 UTC = Sat May 17 23:59:59 1986 IST isdst=0
Israel  Sat May 17 22:00:00 1986 UTC = Sun May 18 01:00:00 1986 IDT isdst=1
Israel  Sat Sep  6 20:59:59 1986 UTC = Sat Sep  6 23:59:59 1986 IDT isdst=1
Israel  Sat Sep  6 21:00:00 1986 UTC = Sat Sep  6 23:00:00 1986 IST isdst=0
Israel  Tue Apr 14 21:59:59 1987 UTC = Tue Apr 14 23:59:59 1987 IST isdst=0
Israel  Tue Apr 14 22:00:00 1987 UTC = Wed Apr 15 01:00:00 1987 IDT isdst=1
Israel  Sat Sep 12 20:59:59 1987 UTC = Sat Sep 12 23:59:59 1987 IDT isdst=1
Israel  Sat Sep 12 21:00:00 1987 UTC = Sat Sep 12 23:00:00 1987 IST isdst=0
Israel  Sat Apr  9 21:59:59 1988 UTC = Sat Apr  9 23:59:59 1988 IST isdst=0
Israel  Sat Apr  9 22:00:00 1988 UTC = Sun Apr 10 01:00:00 1988 IDT isdst=1
Israel  Sat Sep  3 20:59:59 1988 UTC = Sat Sep  3 23:59:59 1988 IDT isdst=1
Israel  Sat Sep  3 21:00:00 1988 UTC = Sat Sep  3 23:00:00 1988 IST isdst=0
Israel  Sat Apr 29 21:59:59 1989 UTC = Sat Apr 29 23:59:59 1989 IST isdst=0
Israel  Sat Apr 29 22:00:00 1989 UTC = Sun Apr 30 01:00:00 1989 IDT isdst=1
Israel  Sat Sep  2 20:59:59 1989 UTC = Sat Sep  2 23:59:59 1989 IDT isdst=1
Israel  Sat Sep  2 21:00:00 1989 UTC = Sat Sep  2 23:00:00 1989 IST isdst=0
Israel  Sat Mar 24 21:59:59 1990 UTC = Sat Mar 24 23:59:59 1990 IST isdst=0
Israel  Sat Mar 24 22:00:00 1990 UTC = Sun Mar 25 01:00:00 1990 IDT isdst=1
Israel  Sat Aug 25 20:59:59 1990 UTC = Sat Aug 25 23:59:59 1990 IDT isdst=1
Israel  Sat Aug 25 21:00:00 1990 UTC = Sat Aug 25 23:00:00 1990 IST isdst=0
Israel  Sat Mar 23 21:59:59 1991 UTC = Sat Mar 23 23:59:59 1991 IST isdst=0
Israel  Sat Mar 23 22:00:00 1991 UTC = Sun Mar 24 01:00:00 1991 IDT isdst=1
Israel  Sat Aug 31 20:59:59 1991 UTC = Sat Aug 31 23:59:59 1991 IDT isdst=1
Israel  Sat Aug 31 21:00:00 1991 UTC = Sat Aug 31 23:00:00 1991 IST isdst=0
Israel  Sat Mar 28 21:59:59 1992 UTC = Sat Mar 28 23:59:59 1992 IST isdst=0
Israel  Sat Mar 28 22:00:00 1992 UTC = Sun Mar 29 01:00:00 1992 IDT isdst=1
Israel  Sat Sep  5 20:59:59 1992 UTC = Sat Sep  5 23:59:59 1992 IDT isdst=1
Israel  Sat Sep  5 21:00:00 1992 UTC = Sat Sep  5 23:00:00 1992 IST isdst=0
Israel  Thu Apr  1 21:59:59 1993 UTC = Thu Apr  1 23:59:59 1993 IST isdst=0
Israel  Thu Apr  1 22:00:00 1993 UTC = Fri Apr  2 01:00:00 1993 IDT isdst=1
Israel  Sat Sep  4 20:59:59 1993 UTC = Sat Sep  4 23:59:59 1993 IDT isdst=1
Israel  Sat Sep  4 21:00:00 1993 UTC = Sat Sep  4 23:00:00 1993 IST isdst=0
Israel  Thu Mar 31 21:59:59 1994 UTC = Thu Mar 31 23:59:59 1994 IST isdst=0
Israel  Thu Mar 31 22:00:00 1994 UTC = Fri Apr  1 01:00:00 1994 IDT isdst=1
Israel  Sat Aug 27 20:59:59 1994 UTC = Sat Aug 27 23:59:59 1994 IDT isdst=1
Israel  Sat Aug 27 21:00:00 1994 UTC = Sat Aug 27 23:00:00 1994 IST isdst=0
Israel  Thu Mar 30 21:59:59 1995 UTC = Thu Mar 30 23:59:59 1995 IST isdst=0
Israel  Thu Mar 30 22:00:00 1995 UTC = Fri Mar 31 01:00:00 1995 IDT isdst=1
Israel  Sat Sep  2 20:59:59 1995 UTC = Sat Sep  2 23:59:59 1995 IDT isdst=1
Israel  Sat Sep  2 21:00:00 1995 UTC = Sat Sep  2 23:00:00 1995 IST isdst=0
Israel  Thu Mar 14 21:59:59 1996 UTC = Thu Mar 14 23:59:59 1996 IST isdst=0
Israel  Thu Mar 14 22:00:00 1996 UTC = Fri Mar 15 01:00:00 1996 IDT isdst=1
Israel  Sun Sep 15 20:59:59 1996 UTC = Sun Sep 15 23:59:59 1996 IDT isdst=1
Israel  Sun Sep 15 21:00:00 1996 UTC = Sun Sep 15 23:00:00 1996 IST isdst=0
Israel  Thu Mar 20 21:59:59 1997 UTC = Thu Mar 20 23:59:59 1997 IST isdst=0
Israel  Thu Mar 20 22:00:00 1997 UTC = Fri Mar 21 01:00:00 1997 IDT isdst=1
Israel  Sat Sep 13 20:59:59 1997 UTC = Sat Sep 13 23:59:59 1997 IDT isdst=1
Israel  Sat Sep 13 21:00:00 1997 UTC = Sat Sep 13 23:00:00 1997 IST isdst=0
Israel  Thu Mar 19 21:59:59 1998 UTC = Thu Mar 19 23:59:59 1998 IST isdst=0
Israel  Thu Mar 19 22:00:00 1998 UTC = Fri Mar 20 01:00:00 1998 IDT isdst=1
Israel  Sat Sep  5 20:59:59 1998 UTC = Sat Sep  5 23:59:59 1998 IDT isdst=1
Israel  Sat Sep  5 21:00:00 1998 UTC = Sat Sep  5 23:00:00 1998 IST isdst=0
Israel  Thu Apr  1 23:59:59 1999 UTC = Fri Apr  2 01:59:59 1999 IST isdst=0
Israel  Fri Apr  2 00:00:00 1999 UTC = Fri Apr  2 03:00:00 1999 IDT isdst=1
Israel  Thu Sep  2 22:59:59 1999 UTC = Fri Sep  3 01:59:59 1999 IDT isdst=1
Israel  Thu Sep  2 23:00:00 1999 UTC = Fri Sep  3 01:00:00 1999 IST isdst=0
Israel  Thu Apr 13 23:59:59 2000 UTC = Fri Apr 14 01:59:59 2000 IST isdst=0
Israel  Fri Apr 14 00:00:00 2000 UTC = Fri Apr 14 03:00:00 2000 IDT isdst=1
Israel  Thu Oct  5 21:59:59 2000 UTC = Fri Oct  6 00:59:59 2000 IDT isdst=1
Israel  Thu Oct  5 22:00:00 2000 UTC = Fri Oct  6 00:00:00 2000 IST isdst=0
Israel  Sun Apr  8 22:59:59 2001 UTC = Mon Apr  9 00:59:59 2001 IST isdst=0
Israel  Sun Apr  8 23:00:00 2001 UTC = Mon Apr  9 02:00:00 2001 IDT isdst=1
Israel  Sun Sep 23 21:59:59 2001 UTC = Mon Sep 24 00:59:59 2001 IDT isdst=1
Israel  Sun Sep 23 22:00:00 2001 UTC = Mon Sep 24 00:00:00 2001 IST isdst=0
Israel  Thu Mar 28 22:59:59 2002 UTC = Fri Mar 29 00:59:59 2002 IST isdst=0
Israel  Thu Mar 28 23:00:00 2002 UTC = Fri Mar 29 02:00:00 2002 IDT isdst=1
Israel  Sun Oct  6 21:59:59 2002 UTC = Mon Oct  7 00:59:59 2002 IDT isdst=1
Israel  Sun Oct  6 22:00:00 2002 UTC = Mon Oct  7 00:00:00 2002 IST isdst=0
Israel  Thu Mar 27 22:59:59 2003 UTC = Fri Mar 28 00:59:59 2003 IST isdst=0
Israel  Thu Mar 27 23:00:00 2003 UTC = Fri Mar 28 02:00:00 2003 IDT isdst=1
Israel  Thu Oct  2 21:59:59 2003 UTC = Fri Oct  3 00:59:59 2003 IDT isdst=1
Israel  Thu Oct  2 22:00:00 2003 UTC = Fri Oct  3 00:00:00 2003 IST isdst=0
Israel  Tue Apr  6 22:59:59 2004 UTC = Wed Apr  7 00:59:59 2004 IST isdst=0
Israel  Tue Apr  6 23:00:00 2004 UTC = Wed Apr  7 02:00:00 2004 IDT isdst=1
Israel  Tue Sep 21 21:59:59 2004 UTC = Wed Sep 22 00:59:59 2004 IDT isdst=1
Israel  Tue Sep 21 22:00:00 2004 UTC = Wed Sep 22 00:00:00 2004 IST isdst=0
Israel  Thu Mar 31 23:59:59 2005 UTC = Fri Apr  1 01:59:59 2005 IST isdst=0
Israel  Fri Apr  1 00:00:00 2005 UTC = Fri Apr  1 03:00:00 2005 IDT isdst=1
Israel  Sat Oct  8 22:59:59 2005 UTC = Sun Oct  9 01:59:59 2005 IDT isdst=1
Israel  Sat Oct  8 23:00:00 2005 UTC = Sun Oct  9 01:00:00 2005 IST isdst=0
Israel  Thu Mar 30 23:59:59 2006 UTC = Fri Mar 31 01:59:59 2006 IST isdst=0
Israel  Fri Mar 31 00:00:00 2006 UTC = Fri Mar 31 03:00:00 2006 IDT isdst=1
Israel  Sat Sep 30 22:59:59 2006 UTC = Sun Oct  1 01:59:59 2006 IDT isdst=1
Israel  Sat Sep 30 23:00:00 2006 UTC = Sun Oct  1 01:00:00 2006 IST isdst=0
Israel  Thu Mar 29 23:59:59 2007 UTC = Fri Mar 30 01:59:59 2007 IST isdst=0
Israel  Fri Mar 30 00:00:00 2007 UTC = Fri Mar 30 03:00:00 2007 IDT isdst=1
Israel  Sat Sep 15 22:59:59 2007 UTC = Sun Sep 16 01:59:59 2007 IDT isdst=1
Israel  Sat Sep 15 23:00:00 2007 UTC = Sun Sep 16 01:00:00 2007 IST isdst=0
Israel  Thu Mar 27 23:59:59 2008 UTC = Fri Mar 28 01:59:59 2008 IST isdst=0
Israel  Fri Mar 28 00:00:00 2008 UTC = Fri Mar 28 03:00:00 2008 IDT isdst=1
Israel  Sat Oct  4 22:59:59 2008 UTC = Sun Oct  5 01:59:59 2008 IDT isdst=1
Israel  Sat Oct  4 23:00:00 2008 UTC = Sun Oct  5 01:00:00 2008 IST isdst=0
Israel  Thu Mar 26 23:59:59 2009 UTC = Fri Mar 27 01:59:59 2009 IST isdst=0
Israel  Fri Mar 27 00:00:00 2009 UTC = Fri Mar 27 03:00:00 2009 IDT isdst=1
Israel  Sat Sep 26 22:59:59 2009 UTC = Sun Sep 27 01:59:59 2009 IDT isdst=1
Israel  Sat Sep 26 23:00:00 2009 UTC = Sun Sep 27 01:00:00 2009 IST isdst=0
Israel  Thu Mar 25 23:59:59 2010 UTC = Fri Mar 26 01:59:59 2010 IST isdst=0
Israel  Fri Mar 26 00:00:00 2010 UTC = Fri Mar 26 03:00:00 2010 IDT isdst=1
Israel  Sat Sep 11 22:59:59 2010 UTC = Sun Sep 12 01:59:59 2010 IDT isdst=1
Israel  Sat Sep 11 23:00:00 2010 UTC = Sun Sep 12 01:00:00 2010 IST isdst=0
Israel  Thu Mar 31 23:59:59 2011 UTC = Fri Apr  1 01:59:59 2011 IST isdst=0
Israel  Fri Apr  1 00:00:00 2011 UTC = Fri Apr  1 03:00:00 2011 IDT isdst=1
Israel  Sat Oct  1 22:59:59 2011 UTC = Sun Oct  2 01:59:59 2011 IDT isdst=1
Israel  Sat Oct  1 23:00:00 2011 UTC = Sun Oct  2 01:00:00 2011 IST isdst=0
Israel  Thu Mar 29 23:59:59 2012 UTC = Fri Mar 30 01:59:59 2012 IST isdst=0
Israel  Fri Mar 30 00:00:00 2012 UTC = Fri Mar 30 03:00:00 2012 IDT isdst=1
Israel  Sat Sep 22 22:59:59 2012 UTC = Sun Sep 23 01:59:59 2012 IDT isdst=1
Israel  Sat Sep 22 23:00:00 2012 UTC = Sun Sep 23 01:00:00 2012 IST isdst=0
Israel  Thu Mar 28 23:59:59 2013 UTC = Fri Mar 29 01:59:59 2013 IST isdst=0
Israel  Fri Mar 29 00:00:00 2013 UTC = Fri Mar 29 03:00:00 2013 IDT isdst=1
Israel  Sat Oct 26 22:59:59 2013 UTC = Sun Oct 27 01:59:59 2013 IDT isdst=1
Israel  Sat Oct 26 23:00:00 2013 UTC = Sun Oct 27 01:00:00 2013 IST isdst=0
Israel  Thu Mar 27 23:59:59 2014 UTC = Fri Mar 28 01:59:59 2014 IST isdst=0
Israel  Fri Mar 28 00:00:00 2014 UTC = Fri Mar 28 03:00:00 2014 IDT isdst=1
Israel  Sat Oct 25 22:59:59 2014 UTC = Sun Oct 26 01:59:59 2014 IDT isdst=1
Israel  Sat Oct 25 23:00:00 2014 UTC = Sun Oct 26 01:00:00 2014 IST isdst=0
Israel  Thu Mar 26 23:59:59 2015 UTC = Fri Mar 27 01:59:59 2015 IST isdst=0
Israel  Fri Mar 27 00:00:00 2015 UTC = Fri Mar 27 03:00:00 2015 IDT isdst=1
Israel  Sat Oct 24 22:59:59 2015 UTC = Sun Oct 25 01:59:59 2015 IDT isdst=1
Israel  Sat Oct 24 23:00:00 2015 UTC = Sun Oct 25 01:00:00 2015 IST isdst=0
Israel  Thu Mar 24 23:59:59 2016 UTC = Fri Mar 25 01:59:59 2016 IST isdst=0
Israel  Fri Mar 25 00:00:00 2016 UTC = Fri Mar 25 03:00:00 2016 IDT isdst=1
Israel  Sat Oct 29 22:59:59 2016 UTC = Sun Oct 30 01:59:59 2016 IDT isdst=1
Israel  Sat Oct 29 23:00:00 2016 UTC = Sun Oct 30 01:00:00 2016 IST isdst=0
Israel  Thu Mar 23 23:59:59 2017 UTC = Fri Mar 24 01:59:59 2017 IST isdst=0
Israel  Fri Mar 24 00:00:00 2017 UTC = Fri Mar 24 03:00:00 2017 IDT isdst=1
Israel  Sat Oct 28 22:59:59 2017 UTC = Sun Oct 29 01:59:59 2017 IDT isdst=1
Israel  Sat Oct 28 23:00:00 2017 UTC = Sun Oct 29 01:00:00 2017 IST isdst=0
Israel  Thu Mar 22 23:59:59 2018 UTC = Fri Mar 23 01:59:59 2018 IST isdst=0
Israel  Fri Mar 23 00:00:00 2018 UTC = Fri Mar 23 03:00:00 2018 IDT isdst=1
Israel  Sat Oct 27 22:59:59 2018 UTC = Sun Oct 28 01:59:59 2018 IDT isdst=1
Israel  Sat Oct 27 23:00:00 2018 UTC = Sun Oct 28 01:00:00 2018 IST isdst=0
Israel  Thu Mar 28 23:59:59 2019 UTC = Fri Mar 29 01:59:59 2019 IST isdst=0
Israel  Fri Mar 29 00:00:00 2019 UTC = Fri Mar 29 03:00:00 2019 IDT isdst=1
Israel  Sat Oct 26 22:59:59 2019 UTC = Sun Oct 27 01:59:59 2019 IDT isdst=1
Israel  Sat Oct 26 23:00:00 2019 UTC = Sun Oct 27 01:00:00 2019 IST isdst=0
Israel  Thu Mar 26 23:59:59 2020 UTC = Fri Mar 27 01:59:59 2020 IST isdst=0
Israel  Fri Mar 27 00:00:00 2020 UTC = Fri Mar 27 03:00:00 2020 IDT isdst=1
Israel  Sat Oct 24 22:59:59 2020 UTC = Sun Oct 25 01:59:59 2020 IDT isdst=1
Israel  Sat Oct 24 23:00:00 2020 UTC = Sun Oct 25 01:00:00 2020 IST isdst=0
Israel  Thu Mar 25 23:59:59 2021 UTC = Fri Mar 26 01:59:59 2021 IST isdst=0
Israel  Fri Mar 26 00:00:00 2021 UTC = Fri Mar 26 03:00:00 2021 IDT isdst=1
Israel  Sat Oct 30 22:59:59 2021 UTC = Sun Oct 31 01:59:59 2021 IDT isdst=1
Israel  Sat Oct 30 23:00:00 2021 UTC = Sun Oct 31 01:00:00 2021 IST isdst=0
Israel  Thu Mar 24 23:59:59 2022 UTC = Fri Mar 25 01:59:59 2022 IST isdst=0
Israel  Fri Mar 25 00:00:00 2022 UTC = Fri Mar 25 03:00:00 2022 IDT isdst=1
Israel  Sat Oct 29 22:59:59 2022 UTC = Sun Oct 30 01:59:59 2022 IDT isdst=1
Israel  Sat Oct 29 23:00:00 2022 UTC = Sun Oct 30 01:00:00 2022 IST isdst=0
Israel  Thu Mar 23 23:59:59 2023 UTC = Fri Mar 24 01:59:59 2023 IST isdst=0
Israel  Fri Mar 24 00:00:00 2023 UTC = Fri Mar 24 03:00:00 2023 IDT isdst=1
Israel  Sat Oct 28 22:59:59 2023 UTC = Sun Oct 29 01:59:59 2023 IDT isdst=1
Israel  Sat Oct 28 23:00:00 2023 UTC = Sun Oct 29 01:00:00 2023 IST isdst=0
Israel  Thu Mar 28 23:59:59 2024 UTC = Fri Mar 29 01:59:59 2024 IST isdst=0
Israel  Fri Mar 29 00:00:00 2024 UTC = Fri Mar 29 03:00:00 2024 IDT isdst=1
Israel  Sat Oct 26 22:59:59 2024 UTC = Sun Oct 27 01:59:59 2024 IDT isdst=1
Israel  Sat Oct 26 23:00:00 2024 UTC = Sun Oct 27 01:00:00 2024 IST isdst=0
Israel  Thu Mar 27 23:59:59 2025 UTC = Fri Mar 28 01:59:59 2025 IST isdst=0
Israel  Fri Mar 28 00:00:00 2025 UTC = Fri Mar 28 03:00:00 2025 IDT isdst=1
Israel  Sat Oct 25 22:59:59 2025 UTC = Sun Oct 26 01:59:59 2025 IDT isdst=1
Israel  Sat Oct 25 23:00:00 2025 UTC = Sun Oct 26 01:00:00 2025 IST isdst=0
Israel  Thu Mar 26 23:59:59 2026 UTC = Fri Mar 27 01:59:59 2026 IST isdst=0
Israel  Fri Mar 27 00:00:00 2026 UTC = Fri Mar 27 03:00:00 2026 IDT isdst=1
Israel  Sat Oct 24 22:59:59 2026 UTC = Sun Oct 25 01:59:59 2026 IDT isdst=1
Israel  Sat Oct 24 23:00:00 2026 UTC = Sun Oct 25 01:00:00 2026 IST isdst=0
Israel  Thu Mar 25 23:59:59 2027 UTC = Fri Mar 26 01:59:59 2027 IST isdst=0
Israel  Fri Mar 26 00:00:00 2027 UTC = Fri Mar 26 03:00:00 2027 IDT isdst=1
Israel  Sat Oct 30 22:59:59 2027 UTC = Sun Oct 31 01:59:59 2027 IDT isdst=1
Israel  Sat Oct 30 23:00:00 2027 UTC = Sun Oct 31 01:00:00 2027 IST isdst=0
Israel  Thu Mar 23 23:59:59 2028 UTC = Fri Mar 24 01:59:59 2028 IST isdst=0
Israel  Fri Mar 24 00:00:00 2028 UTC = Fri Mar 24 03:00:00 2028 IDT isdst=1
Israel  Sat Oct 28 22:59:59 2028 UTC = Sun Oct 29 01:59:59 2028 IDT isdst=1
Israel  Sat Oct 28 23:00:00 2028 UTC = Sun Oct 29 01:00:00 2028 IST isdst=0
Israel  Thu Mar 22 23:59:59 2029 UTC = Fri Mar 23 01:59:59 2029 IST isdst=0
Israel  Fri Mar 23 00:00:00 2029 UTC = Fri Mar 23 03:00:00 2029 IDT isdst=1
Israel  Sat Oct 27 22:59:59 2029 UTC = Sun Oct 28 01:59:59 2029 IDT isdst=1
Israel  Sat Oct 27 23:00:00 2029 UTC = Sun Oct 28 01:00:00 2029 IST isdst=0
Israel  Thu Mar 28 23:59:59 2030 UTC = Fri Mar 29 01:59:59 2030 IST isdst=0
Israel  Fri Mar 29 00:00:00 2030 UTC = Fri Mar 29 03:00:00 2030 IDT isdst=1
Israel  Sat Oct 26 22:59:59 2030 UTC = Sun Oct 27 01:59:59 2030 IDT isdst=1
Israel  Sat Oct 26 23:00:00 2030 UTC = Sun Oct 27 01:00:00 2030 IST isdst=0
Israel  Thu Mar 27 23:59:59 2031 UTC = Fri Mar 28 01:59:59 2031 IST isdst=0
Israel  Fri Mar 28 00:00:00 2031 UTC = Fri Mar 28 03:00:00 2031 IDT isdst=1
Israel  Sat Oct 25 22:59:59 2031 UTC = Sun Oct 26 01:59:59 2031 IDT isdst=1
Israel  Sat Oct 25 23:00:00 2031 UTC = Sun Oct 26 01:00:00 2031 IST isdst=0
Israel  Thu Mar 25 23:59:59 2032 UTC = Fri Mar 26 01:59:59 2032 IST isdst=0
Israel  Fri Mar 26 00:00:00 2032 UTC = Fri Mar 26 03:00:00 2032 IDT isdst=1
Israel  Sat Oct 30 22:59:59 2032 UTC = Sun Oct 31 01:59:59 2032 IDT isdst=1
Israel  Sat Oct 30 23:00:00 2032 UTC = Sun Oct 31 01:00:00 2032 IST isdst=0
Israel  Thu Mar 24 23:59:59 2033 UTC = Fri Mar 25 01:59:59 2033 IST isdst=0
Israel  Fri Mar 25 00:00:00 2033 UTC = Fri Mar 25 03:00:00 2033 IDT isdst=1
Israel  Sat Oct 29 22:59:59 2033 UTC = Sun Oct 30 01:59:59 2033 IDT isdst=1
Israel  Sat Oct 29 23:00:00 2033 UTC = Sun Oct 30 01:00:00 2033 IST isdst=0
Israel  Thu Mar 23 23:59:59 2034 UTC = Fri Mar 24 01:59:59 2034 IST isdst=0
Israel  Fri Mar 24 00:00:00 2034 UTC = Fri Mar 24 03:00:00 2034 IDT isdst=1
Israel  Sat Oct 28 22:59:59 2034 UTC = Sun Oct 29 01:59:59 2034 IDT isdst=1
Israel  Sat Oct 28 23:00:00 2034 UTC = Sun Oct 29 01:00:00 2034 IST isdst=0
Israel  Thu Mar 22 23:59:59 2035 UTC = Fri Mar 23 01:59:59 2035 IST isdst=0
Israel  Fri Mar 23 00:00:00 2035 UTC = Fri Mar 23 03:00:00 2035 IDT isdst=1
Israel  Sat Oct 27 22:59:59 2035 UTC = Sun Oct 28 01:59:59 2035 IDT isdst=1
Israel  Sat Oct 27 23:00:00 2035 UTC = Sun Oct 28 01:00:00 2035 IST isdst=0
Israel  Thu Mar 27 23:59:59 2036 UTC = Fri Mar 28 01:59:59 2036 IST isdst=0
Israel  Fri Mar 28 00:00:00 2036 UTC = Fri Mar 28 03:00:00 2036 IDT isdst=1
Israel  Sat Oct 25 22:59:59 2036 UTC = Sun Oct 26 01:59:59 2036 IDT isdst=1
Israel  Sat Oct 25 23:00:00 2036 UTC = Sun Oct 26 01:00:00 2036 IST isdst=0
Israel  Thu Mar 26 23:59:59 2037 UTC = Fri Mar 27 01:59:59 2037 IST isdst=0
Israel  Fri Mar 27 00:00:00 2037 UTC = Fri Mar 27 03:00:00 2037 IDT isdst=1
Israel  Sat Oct 24 22:59:59 2037 UTC = Sun Oct 25 01:59:59 2037 IDT isdst=1
Israel  Sat Oct 24 23:00:00 2037 UTC = Sun Oct 25 01:00:00 2037 IST isdst=0
Israel  Mon Jan 18 03:14:07 2038 UTC = Mon Jan 18 05:14:07 2038 IST isdst=0
Israel  Tue Jan 19 03:14:07 2038 UTC = Tue Jan 19 05:14:07 2038 IST isdst=0

או בהשוואה למקומות שכבר לא מזיזים את השעון:

$ zdump -v  /usr/share/zoneinfo/America/Bogota

/usr/share/zoneinfo/America/Bogota  Fri Dec 13 20:45:52 1901 UTC = Fri Dec 13 15:49:36 1901 BMT isdst=0
/usr/share/zoneinfo/America/Bogota  Sat Dec 14 20:45:52 1901 UTC = Sat Dec 14 15:49:36 1901 BMT isdst=0
/usr/share/zoneinfo/America/Bogota  Mon Nov 23 04:56:15 1914 UTC = Sun Nov 22 23:59:59 1914 BMT isdst=0
/usr/share/zoneinfo/America/Bogota  Mon Nov 23 04:56:16 1914 UTC = Sun Nov 22 23:56:16 1914 -05 isdst=0
/usr/share/zoneinfo/America/Bogota  Sun May  3 04:59:59 1992 UTC = Sat May  2 23:59:59 1992 -05 isdst=0
/usr/share/zoneinfo/America/Bogota  Sun May  3 05:00:00 1992 UTC = Sun May  3 01:00:00 1992 -04 isdst=1
/usr/share/zoneinfo/America/Bogota  Sun Feb  7 03:59:59 1993 UTC = Sat Feb  6 23:59:59 1993 -04 isdst=1
/usr/share/zoneinfo/America/Bogota  Sun Feb  7 04:00:00 1993 UTC = Sat Feb  6 23:00:00 1993 -05 isdst=0
/usr/share/zoneinfo/America/Bogota  Mon Jan 18 03:14:07 2038 UTC = Sun Jan 17 22:14:07 2038 -05 isdst=0
/usr/share/zoneinfo/America/Bogota  Tue Jan 19 03:14:07 2038 UTC = Mon Jan 18 22:14:07 2038 -05 isdst=0

אז עכשיו שאנחנו מבינים את בסיס הנתונים של אזורי הזמן בואו נסכם בכמה טריקים שיכולים לעזור לנו כשמדברים עם אנשים מכל העולם. הטריק הראשון הוא שבשביל לראות את השעה במקום מסוים אפשר להשתמש ב zdump:

$ zdump  /usr/share/zoneinfo/America/Bogota
/usr/share/zoneinfo/America/Bogota  Fri Sep  8 06:22:09 2023 -05

ואפשר גם להשתמש רק בשם של אזור הזמן בלי הנתיב המלא:

$ zdump  America/Bogota
America/Bogota  Fri Sep  8 06:22:28 2023 -05

ואפילו אם אין לכם את zdump על המחשב תוכלו להשתמש ב date ולהעביר את אזור הזמן בתור משתנה סביבה:

$ TZ=America/Bogota date
Fri Sep  8 06:23:15 -05 2023

הטריק השני הוא שבשביל לזהות מתי פעם הבאה צריך להזיז את השעון כל מה שצריך זה לחפש שורות בקובץ אזור הזמן:

zdump -v Israel| grep 2023|grep isdst=1
Israel  Fri Mar 24 00:00:00 2023 UTC = Fri Mar 24 03:00:00 2023 IDT isdst=1
Israel  Sat Oct 28 22:59:59 2023 UTC = Sun Oct 29 01:59:59 2023 IDT isdst=1

ואנחנו רואים שב 2023 מזיזים את השעון פעמיים, פעם אחת ב 24/3 זה היה המעבר לשעון קיץ, ופעם שניה תהיה ב 29/10 כשנעבור לשעון חורף.

איך לזהות הודעה באנגלית תקנית

08/09/2023

שאלה 59 בפרויקט אוילר מציגה את האתגר הבא - נתונה הודעה מוצפנת במפתח הצפנה המורכב מ-3 אותיות קטנות בלבד, והמשימה שלנו היא למצוא את הטקסט המקורי.

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

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

בסופו של דבר נזכרתי שיש לי רשימה של כל המילים באנגלית ממש אצלי על המחשב, וגם אצלכם, בקובץ /usr/share/dict/words. משם הדרך היתה קצרה לחיפוש הודעות בהן לפחות 40% מהמילים הן מילים חוקיות באנגלית מה שהוביל להודעה הנכונה. הפיתרון המלא בפייתון היה:

from pathlib import Path
import string
import sys
from itertools import cycle

english_words = set([c.removesuffix('\n').lower() for c in Path('/usr/share/dict/words').open().readlines()])
message = [int(i) for i in Path('./0059_cipher.txt').open().read().split(',')]
key = [97, 98, 99]

def decrypt(message, key):
   return ''.join([chr(i) for i in [p[0] ^ p[1] for p in zip(message, cycle(key))]])

for i in range(ord('a'), ord('z') + 1):
    for j in range(ord('a'), ord('z') + 1):
        for k in range(ord('a'), ord('z') + 1):
            key = [i, j, k]
            plaintext = decrypt(message, key)
            words = plaintext.split()
            valid_words = [w for w in plaintext.split() if w in english_words]
            if len(valid_words) / len(words) > 0.4:
                print(plaintext)
                print(sum(ord(ch) for ch in plaintext))