حكاية من الوقت الزائد والضياع. وفقًا لـ py3

منذ بضعة أسابيع ، اكتشفت في بنيتنا التحتية خطأ صغيرًا في التكوين في متغير البيئة TZ. أدى تصحيح هذا الخطأ إلى إزعاج التوازن الهش للأخطاء في الكون ورسومات RPS لأحد المشاريع في الجرافيت الخاص بنا. سأخبرك كيف طاردت بعد عدة ساعات لعدة أيام.


كيف بدأ كل شيء


البرنامج النصي ، الذي تم إطلاقه يدويًا وعمل بشكل مثالي ، ألقى خطأ عند البدء من cron.d. أشارت دراسة سطحية للسجلات في نص عادي ما هو الخطأ.


#   
$ TZ='' clickhouse-client; echo exit=$?
ClickHouse client version 20.3.2.1.
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 20.3.2 revision 54433.
Poco::Exception. Code: 1000, e.code() = 0, e.displayText() = Exception: Could not determine time zone from TZ variable value: '': filesystem error: in file_size: Is a directory [/usr/share/zoneinfo] (version 20.3.2.1)
exit=232

خطأ معنا أو في البرنامج؟


هل سلوك البرنامج صحيح أم أنه خطأ؟


تشير وثائق غنو إلى أن هناك 3 تنسيقات ممكنة لمتغير البيئة TZ:


  • تنسيق بدون التوقيت الصيفي (DST) std offset. أمثلة EST+5،GMT+0
  • تنسيق مع DST: std offset dst [offset],start[/time],end[/time]. مثال EST+5EDT,M3.2.0/2,M11.1.0/2.
  • اسم ملف وصف المنطقة الزمنية. قد تبدأ بنقطتين :. إذا كان الحرف الأول (أو التالي للنقطتين) خطًا مائلًا /، فيجب أن يكون هذا هو المسار المطلق للملف. إذا لم يكن كذلك ، ثم /usr/share/zoneinfo/${TZ}.

لماذا يحتاج عميل ClickHouse إلى معرفة بالتوقيت المحلي؟


Date DateTime DBMS timestamp, toDateTime('2020-02-02 20:20:20') (, , ) UInt32. , . TZ , , 98% .


, ClickHouse ( Poco) , . .



, . cron.d TZ, . . , 2020-04-15 2020-04-20 .



2020-04-22 ( ): " RPS "


تستضيف غير UTC


, -, . .


self.now = int(datetime.datetime.utcnow().timestamp())
...
dt = datetime.datetime.strptime(time_str, time_format).utctimetuple()
timestamp = time.mktime(dt)

datetime.utcnow()?


Return the current UTC date and time, with tzinfo=None.
This is like now(), but returns the current UTC date and time, as a naive datetime object. An aware current UTC datetime can be obtained by calling datetime.now(timezone.utc). See also now().
Warning: Because naive datetime objects are treated by many datetime methods as local times, it is preferred to use aware datetimes to represent times in UTC. As such, the recommended way to create an object representing the current time in UTC is by calling datetime.now(timezone.utc).

, UTC, tzinfo=None datetime. .timestamp() UNIX time , UTC. : TZ=UTC


datetime.now().timestamp(). , .timestamp(), datetime.now(timezone.utc)


datetime.utctimetuple()?


datetime.timetuple():
Return time.struct_time such as returned by time.localtime().
datetime.utctimetuple():
If datetime instance d is naive, this is the same as d.timetuple() except that tm_isdst is forced to 0 regardless of what d.dst() returns. DST is never in effect for a UTC time.
If d is aware, d is normalized to UTC time, by subtracting d.utcoffset(), and a time.struct_time for the normalized time is returned. tm_isdst is forced to 0.
Warning: Because naive datetime objects are treated by many datetime methods as local times, it is preferred to use aware datetimes to represent times in UTC; as a result, using utcfromtimetuple may give misleading results. If you have a naive datetime representing UTC, use datetime.replace(tzinfo=timezone.utc) to make it aware, at which point you can use datetime.timetuple().

. time.struct_time, time.mktime(). , python2. , . , UNIX timestamp .


Python, , .


, datetime.strptime().timestamp()


TZ


, . - , - UTC, - , . , .


, RPS :


تستضيف UTC


, , . , .


, :


  • , TZ=''
  • UTC strptime()
  • UTC, strptime()
  • strptime()

strptime 2020-04-24T05:31:55+02:00


python


#!/usr/bin/env python
from datetime import datetime, timezone  # noqa
from time import mktime
def pprint(d: dict):
    for k in d:
        print("{}: {}".format(k, d[k]))
now = {'now': datetime.now(),
       # 'now_tz': datetime.now(timezone.utc), # the same as now for timestamp
       'utcnow': datetime.utcnow()}
now_ts = [int(now[k].timestamp()) for k in now]
now_dict = {k: [now_ts[i], now_ts[i] - now_ts[0]] for i, k in enumerate(now)}
pprint(now_dict)
# pprint(now)
# print('Timestamps in now: {}'.format(set(now_ts)))
print()
ts_c = 1587699115  # the known correct value
time_format = "%Y-%m-%dT%H:%M:%S%z"
time_str = "2020-04-24T05:31:55+02:00"
timetuples = {
    'timetuple': datetime.strptime(time_str, time_format).timetuple(),
    'utctimetuple': datetime.strptime(time_str, time_format).utctimetuple(),
}
ts = {
    'timestamp': [
        int(datetime.strptime(time_str, time_format).timestamp()),
        int(datetime.strptime(time_str, time_format).timestamp()) - ts_c,
    ],
    'timetuple': [
        int(mktime(timetuples['timetuple'])),
        int(mktime(timetuples['timetuple'])) - ts_c,
    ],
    'utctimetuple': [
        int(mktime(timetuples['utctimetuple'])),
        int(mktime(timetuples['utctimetuple'])) - ts_c,
    ],
}
pprint(ts)
# pprint(timetuples)
# print('Timestamps in ts: {}'.format(set(int(v[0]) for v in ts.values())))

python TZ


#!/usr/bin/env bash
for tz in '' Europe/Moscow UTC Europe/Berlin
do
  date "+==TZ=${tz} %s=="
  TZ=$tz python example.py
  date '+++%s++' -d '2020-04-24T05:31:55+02:00'
done


TZ. , +02:00.


\ TZ''+03:00UTC+02:00 ( unset TZ)
now()/now(tz)++++
utcnow()+-+-
timestamp()++++
timetuple()+mktime()---+
utctimetuple()+mktime()+-+-

now timestamp . , timetuple + mktime .


timestamp

, TZ=''


==TZ='' 1587914590==
now: [1587914590, 0]
utcnow: [1587914590, 0]
timestamp: [1587699115, 0]
timetuple: [1587706315, 7200] - TZ - UTC
utctimetuple: [1587699115, 0]
++1587699115++

TZ='+03:00', UTC strptime()


==TZ=Europe/Moscow 1587914590==
now: [1587914590, 0]
utcnow: [1587903790, -10800] - UTC - TZ
timestamp: [1587699115, 0]
timetuple: [1587695515, -3600] - +02:00 - TZ
utctimetuple: [1587688315, -10800] - UTC - TZ
++1587699115++

TZ=UTC, strptime()


==TZ=UTC 1587914590==
now: [1587914590, 0]
utcnow: [1587914590, 0]
timestamp: [1587699115, 0]
timetuple: [1587706315, 7200] - +02:00 - UTC
utctimetuple: [1587699115, 0]
++1587699115++

TZ='+02:00', strptime(), unset TZ


==TZ=Europe/Berlin 1587914590==
now: [1587914590, 0]
utcnow: [1587907390, -7200] - UTC - TZ
timestamp: [1587699115, 0]
timetuple: [1587699115, 0]
utctimetuple: [1587695515, -3600] - UTC - TZ...    DST!
++1587699115++

, .



تنصح Tikki Schellen الرائعة بشكل معقول : "لا تأخذ بعض الوقت بيديك العاريتين." بالنسبة لي ، في ترتيب الخطر ، وقع في سطر واحد مع DNS. حاول تجنبه بشكل عام كلما أمكن ذلك.


وفي هذا الوقت المثير للاهتمام ، أود أن أبقى بصحة جيدة. حاول البقاء في المنزل وإذا شعرت فجأة بالملل الشديد وليس لديك ما تفعله ، يمكنك لعب الألعاب من InnoGames . بالمناسبة ، لدينا شواغر مفتوحة


All Articles