با ارائه net core.، شاهده استفادهی گسترده از DateTimeOffset بجای DateTime بودیم و این استفاده به مرور در کدهای خودمان هم ورود کرد. DateTimeOffset به شما این اجازه را میدهد که دقیقا بدانید ساعت وارد شده در سیستم، دقیقا مربوطه به چه منطقه زمانی است. در پروژهای که مدتی است با نسخهی Asp.net core 3.1 در حال طراحی و به روزرسانی بخشهای مختلف آن هستیم، یکی از موارد، سیستم زمانی آن است که باید در زمانهای مناسب و مدنظر کاربر، فعالیتهای تنظیم شدهی توسط کاربر را به انجام برساند.
در اینجا سامانه به صورت Paas آغاز به فعالیت کرد. در این نوع سیستمها، تاریخ و ساعت سرور بر اساس منطقهی زمانی صفر، یعنی گرینویچ یا نصف النهار مبدا تنظیم شدهاست. یعنی زمانی که شما ساعت سیستم را دریافت میکنید، Offset بر روی صفر تنظیم شدهاست و اگر کاربر تهران (ایران) ساعتی را بخواهد تنظیم کند، این تاریخ حتما باید یک آفست 3.5 داشته باشد تا محاسبات زمانی سیستم دقیق کار کند؛ در غیر اینصورت سه ساعت و نیم زودتر، فعالیت موردنظر آغاز میگردد و باعث خطا و بی اعتبار شدن سامانه میگردد.
همچنین در بعضی کشورهای مانند ایران، Daylight Saving Time یا به اختصار DST نیز پیاده سازی میشود که در ین حالت در کشور مربوطه، نیمه اول سال که هوا گرمتر است ساعتها یک ساعت به جلو کشیده شده و با آغاز روزهای سرد سال، ساعت بجای قبلی خود باز میگردد و به همین دلیل، آفست زمانی آن 4.5 میباشد که البته ممکن است بنا به دلایلی این DST اجرا نگردد که بیش از ده سال پیش کشور ما نیز چنین تجربهای را چند سالی داشت.
به همین دلیل باید این موضوع تغییر آفست را جدی گرفت. حال در سامانهی ما گاها افرادی هستند که در خارج از کشور با آن کار میکنند و از آنجا که سامانه بر اساس ساعت تهران این فعالیت را انجام میدهد، باید در این قسمت به روزرسانیهایی را به انجام میرساندیم. بدین ترتیب در قسمت پروفایل کاربر، لیستی به نام منطقه زمانی قرار دادیم تا بر اساس آن، کاربر بتواند منطقه زمانی خود را انتخاب کند تا از این پس، زمان خود را بر اساس زمان تهران مشخص نکند. پس با استفاده از کلاس موجود در دات نت TimeZoneInfo لیستی از TimeZoneها را به دست آوردم که هر timezone شامل ID، نام نمایشی، میزان آفست آن منطقه، آیا شامل DST میگردد یا خیر و ... میشود.
در این حالت برای هر کاربر، Zone ID را ذخیره کرده و با هر بار استفاده بر اساس ZoneId، اطلاعات آن منطقه زمانی را به دست میآوردم. همه چیز درست کار میکرد ولی زمانیکه سامانه توسط داکر روی سرویسهای Paas اجرا شد، در این حالت چون سیستم مذکور یک لینوکس است که توسط Nginx اجرا میگردد و اینکه TimeZoneInfo یک سیستم WindowsBased است، به مشکل برخورد کرد و نتوانست ZoneID مورد نظر را در سیستم بیابد. سیستمهای دیگر مانند لینوکس، از ساختاری با نام IANA میباشد که توسط ICANN حمایت میشود و دیتابیسهای به روز آن در این آدرس قرار دارد. به همین علت سیستم مجددا RollBack شد تا آن را اصلاح نماییم.
جهت اصلاح این مشکل سه مورد زیر را بررسی کردم:
یک. استفاده از کتابخانه مبدل منطقه زمانی: این کتابخانه تبدیل حالتهای زمانی از ویندوز به IANA و بالعکس را دارد. همچنین این امکان را به شما میدهد که به راحتی با وارد نمودن ZoneId به هر شکلی که وارد شود، چه به صورت ویندوزی و چه به صورت IANA باشد، خروجی TimeZoneInfo مورد نظر را تامین مینماید. البته در سیستم عامل ویندوز همان شکل قبل را دارد ولی در حالت لینوکسی، نام نمایشی مناطق شکل مناسبی ندارد و فقط بیشتر به شکل اختلاف زمانی میباشد که دو مرتبه تکرار شده است.
دو. استفاده از کتابخانه NodaTime: کتابخانه NodaTime، کتابخانهی خوشنامی در مورد مسائل تاریخ و ساعت میباشد و همچنین قابلیت مناطق زمانی را بر اساس سیستم IANA فراهم میکند
سه. ارتقا پروژه به دات نت 6: تیم دات نت، در نسخهی ،6 در زمینهی تاریخ و ساعت بهبودهای فراوانی داشتهاند که تایپهای جدید DateOnly و TimeOnly نیز نمونههایی از آن میباشد ولی بهبودهایی هم در زمینه TimeZoneها نیز صورت گرفتهاست و از حالت WindowsBased به حالت CrossPlatform تغییر یافتهاست. در حال حاضر در صورتیکه در نسخه 6، شما از مناطق زمانی چه در ویندوز و چه در لینوکس استفاده کنید، یا اینکه در یک سیستم IANA از ZoneIdهای ویندوزی استفاده کنید و یا بالعکس، هیچ مشکلی وجود ندارد.
با توجه به این موضوع، ما سیستم را از نسخهی 3.1 به نسخه 6 به روزرسانی کردیم و به راحتی و بدون تغییر کدها توانستیم مناطق زمانی را به راحتی بدست آوریم. البته این نکته را باید مدنظر داشته باشید که در سیستم ویندوزی، همه چیز مطابق قبل است ولی در یک سیستم مبتنی بر IANA، ممکن است بعضی از نامهای نمایشی تکراری باشند، ولی ZONEIDها متفاوت هستند؛ مثلا برای ایران دو منطقه زمانی، یا برای ترکیه سه یا چهار منطقه زمانی وجود داشت؛ با نامهای نمایشی یکسان ولی با ZoneIdهای متفاوت به شکل Iran و دیگری به شکل Asia/tehran بود و ترکیه هم با چند نام شهر متفاوت است.