فهرست

جست‌وجوی ابزارهاگزارش تغییرات

برای جابه‌جایی برای باز کردنمسئله را توضیح دهید، نه نام ابزار را

راهنما

ماه یک مدت‌زمان نیست، و دیگر دام‌های تاریخ

تاریخ‌ها مانند اعداد رفتار می‌کنند تا وقتی که ناگهان نکنند. ماه طول ثابتی ندارد، روز همیشه ۲۴ ساعت نیست، و «چند روز فاصله» بسته به اینکه دو سر بازه را بشمارید یا نه دو پاسخ درست دارد. هر یک از این‌ها در نرم‌افزارهای واقعی باگ‌های واقعی ساخته است.

دو پاسخ درست برای «چند روز»

دوشنبه تا جمعه اگر تفریق کنید چهار روز است، و اگر روزهای درگیر را بشمارید پنج روز.

هر دو در عمل به کار می‌روند. هتل برای چهار شب میان ورود روز دوشنبه و خروج روز جمعه پول می‌گیرد. جشنواره‌ای پنج‌روزه که از دوشنبه تا جمعه برگزار می‌شود، شامل دو سر می‌شمارد. مدت‌های اخطار، استحقاق مرخصی و مهلت‌های دادگاه هر کدام به‌گونه‌ای از یکی از این دو استفاده می‌کنند، و قانون معمولاً می‌گوید کدام.

قاعدهٔ درستی وجود ندارد، فقط قاعدهٔ اعلام‌شده هست. ابزاری که تفاضل روز را گزارش می‌کند باید بگوید کدام را انجام می‌دهد، و قراردادی که این را مشخص نمی‌کند ابهامی به اندازهٔ تقریباً یک روز در خود دارد.

پیش از ادامهٔ مطلب

اشتراکی از ۳۱ ژانویه شروع می‌شود و ماهانه تمدید می‌شود. تمدید دوم کی است؟

  • بله — و همان تاریخ دوم است که غافلگیرکننده است.

  • این یعنی افزودن دو ماه به تاریخ اولیه. بیشتر سیستم‌ها به جای آن یک ماه به نتیجهٔ قبلی اضافه می‌کنند.

  • برخی سیستم‌ها به این شکل سرریز می‌کنند، اما محدود کردن به پایان ماه بسیار رایج‌تر است.

۲۸ فوریه، سپس ۲۸ مارس. محدود کردن به پایان ماه قاعدهٔ معمول است، و پیامدی دارد که دانستنش می‌ارزد: دو بار افزودن یک ماه با یک بار افزودن دو ماه یکی نیست. از ۳۱ ژانویه، محدود کردن ۲۸ فوریه و سپس ۲۸ مارس می‌دهد؛ افزودن مستقیم دو ماه ۳۱ مارس می‌دهد. هیچ‌کدام باگ نیست، و هر سیستمی که حساب ماهانهٔ تکرارشونده انجام می‌دهد باید یکی را انتخاب کند و به آن پایبند بماند.

ماه یک طول نیست

روز، ساعت و ثانیه مدت‌زمان‌اند: کمیت‌های ثابتی که می‌توان جمع کرد. ماه چنین نیست. ماه یک واحد تقویمی است که طولش بستگی دارد به اینکه کدام ماه باشد.

پس «یک ماه پس از ۳۱ ژانویه» پاسخ بدیهی‌ای ندارد. ۳۱ فوریه‌ای وجود ندارد. قاعده‌های رایج این‌ها هستند:

  • محدود کردن به پایان ماه. ۲۸ فوریه، یا ۲۹ در سال کبیسه. رایج‌ترین.
  • سرریز. ۲ یا ۳ مارس، با اجازه دادن به شمارش روز که از پایان ماه بگذرد.

محدود کردن انتخاب معمول است و پیامدی دارد که دانستنش می‌ارزد: دو بار افزودن یک ماه می‌تواند با یک بار افزودن دو ماه متفاوت باشد. از ۳۱ ژانویه، محدود کردن ۲۸ فوریه و سپس ۲۸ مارس می‌دهد؛ افزودن مستقیم دو ماه ۳۱ مارس می‌دهد. هیچ‌کدام باگ نیست، و هر سیستمی که حساب ماهانهٔ تکرارشونده انجام می‌دهد باید یکی را انتخاب کند و یکدست بماند.

یک زمان‌بندی تکرارشونده می‌تواند در عوض ۳۱ ژانویه را به عنوان لنگر دائمی نگه دارد: فوریه جایگزین پایان‌ماهِ خودش را می‌گیرد، سپس مارس به سی‌ویکم برمی‌گردد. این یک قاعدهٔ عمدی سوم است، نه اصلاحی بر دو قاعدهٔ بالا. عیب در انتخاب یکی از آن‌ها نیست؛ عیب در انجام حساب ماهانه است بدون اینکه بگویید زمان‌بندی کدام را منظور دارد.

همین برای سال‌ها هم صادق است، جایی که تنها تاریخ دردسرساز ۲۹ فوریه است، و هر بار دردسرساز است.

روز همیشه ۲۴ ساعت نیست

جایی که ساعت تابستانی اجرا می‌شود، یک روز در سال ۲۳ ساعت دارد و روز دیگری ۲۵ ساعت. روزها را در ۸۶٬۴۰۰ ثانیه ضرب کنید و در بیشتر سال درست هستید.

در لبه‌ها از این هم بدتر می‌شود. مناطق زمانی قواعدشان را تغییر می‌دهند — پایگاه‌دادهٔ IANA که آن‌ها را ثبت می‌کند چند بار در سال به‌روز می‌شود، بیشتر به این دلیل که حوزهٔ قضایی‌ای تصمیمی گرفته است. کشورهایی آفست خود را یک‌باره تغییر داده‌اند، و معدودی هنگام عبور از خط تاریخ یک روز تقویمی را جا انداخته‌اند.

قواعد عملی‌ای که تقریباً از همهٔ این‌ها جلوگیری می‌کند:

  • در UTC کار کنید و فقط برای نمایش به زمان محلی تبدیل کنید.
  • یک لحظه را به عنوان لحظه ذخیره کنید، نه به عنوان زمان ساعت دیواری محلی با منطقهٔ زمانی ضمنی.
  • هرگز تعداد ثابتی ثانیه برای یک روز، ماه یا سال فرض نکنید.
  • تفاضل‌های تقویمی را روی تاریخ‌های تقویمی محاسبه کنید، نه با تقسیم میلی‌ثانیه‌های سپری‌شده.

و به همین دلیل تایمر باید ساعت را بخواند

شمارش معکوسی که هر بار که یک بازه فعال می‌شود یک ثانیه از جمع خودش کم می‌کند، رانش پیدا می‌کند، و همیشه در یک جهت.

بازه‌ها تضمین‌شده نیستند. مرورگر در زبانهٔ پس‌زمینه آن‌ها را به‌شدت کُند می‌کند، دستگاه می‌تواند به خواب برود و بیدار شود، و هر تیک کمی دیر است نه کمی زود. هر یک از این‌ها ثانیه‌ای است که شمارنده هرگز کم نکرده، بنابراین تایمری که در زبانهٔ دیگری در حال اجرا رها شده به‌طور محسوسی دیر تمام می‌شود.

راه‌حل، بازهٔ دقیق‌تر نیست. راه‌حل این است که زمان شروع تایمر را ثبت کنید و زمان باقی‌مانده را در هر تیک از ساعت واقعی به دست آورید. آن‌وقت کُند شدن فقط برای لحظه‌ای نمایشی کهنه به شما تحمیل می‌کند نه خطایی انباشته، و تایمر همان لحظه‌ای که دوباره به زبانه نگاه می‌شود درست است.

این اصلی کلی برای هر چیزی است که زمان سپری‌شده را دنبال می‌کند: بازه چیزی است که بازترسیم را برمی‌انگیزد، و ساعت چیزی است که پاسخ از آن می‌آید.

پرسش‌های رایج

بین دوشنبه و جمعه چند روز فاصله است؟

چهار یا پنج، و هر دو درست‌اند. چهار، تفاضل است — تعداد شب‌های میان آن‌ها. پنج، شمارشِ شاملِ روزهای درگیر است، که منظور یک رزرو تعطیلات یا اقامت در هتل همان است. هیچ‌کدام درست‌تر از دیگری نیست، بنابراین هر ابزاری باید بگوید کدام را گزارش می‌کند، و هر قراردادی باید بگوید کدام را منظور دارد.

چرا افزودن یک ماه مبهم است؟

چون ماه‌ها طول‌های متفاوتی دارند، بنابراین یک ماه پس از ۳۱ ژانویه پاسخ بدیهی‌ای ندارد — بسته به قاعده، ۲۸ فوریه، ۲ مارس یا ۳ مارس. بیشتر سیستم‌ها به پایان ماه مقصد محدود می‌کنند، که یعنی دو بار افزودن یک ماه می‌تواند با یک بار افزودن دو ماه متفاوت باشد. روزها بی‌ابهام‌اند؛ ماه‌ها نه.

آیا یک روز همیشه ۲۴ ساعت است؟

نه. در مناطقی که ساعت تابستانی دارند، یک روز در سال ۲۳ ساعت است و روز دیگری ۲۵ ساعت. برخی مناطق زمانی آفست خود را به‌کلی تغییر داده‌اند، و معدودی یک روز تقویمی را جا انداخته‌اند. محاسبهٔ مدت‌زمان با ضرب روزها در ۸۶٬۴۰۰ ثانیه در بیشتر مواقع درست است و در مواردی اشتباه است که بازتولیدشان دشوار است.

چرا تایمر باید ساعت را بخواند نه اینکه تیک‌ها را بشمارد؟

چون بازه‌ها قابل اعتماد نیستند. مرورگر تایمرها را در یک زبانهٔ پس‌زمینه کُند می‌کند، دستگاه به خواب می‌رود، و هر تیک اندکی رانش پیدا می‌کند. تایمری که تیک‌های خودش را می‌شمارد به‌تدریج از زمان واقعی عقب می‌افتد، و هر چه بیشتر کار کند خطا بزرگ‌تر می‌شود. خواندن ساعت واقعی در هر بار، نمایش را صرف‌نظر از اینکه چه بلایی سر بازه‌ها آمده درست نگه می‌دارد.

ابزارهای مرتبط

منابع