TimeZoneInfo in .NET Core when hosting on unix (nginx) - c#

For example, when I try to do the following.
TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time")
I get the error, that the TimeZone is not available on the local computer. When I run this locally it works, but there I run it on windows. When deployed it runs on a Unix machine in Nginx. I can see that FindSystemTimeZoneById is looking in the wrong folder when it comes to Unix. Is there any way to make this work?

.Net Core using system timezone. Unfortunately Windows and Linux have different timezone system. Now you have two ways:
Use other (and universal) impementation of timezone like Noda time
Translate
between Windows and IANA time zones, e.g. using the TimeZoneConverter micro-library.

Working of off the previous answer, we can avoid the expensive try/catch by checking which OS we're running on:
using System;
using System.Runtime.InteropServices;
TimeZoneInfo easternStandardTime;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
}

Can you please try this?
TimeZoneInfo easternZone;
try
{
easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
}
catch (TimeZoneNotFoundException)
{
easternZone = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
}
You can review the list of IANA time zones here https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

If you want to try a Windows time zone and then fallback on a IANA one if the Windows one doesn't exist:
var tzi = TimeZoneInfo.GetSystemTimeZones().Any(x => x.Id == "Eastern Standard Time") ?
TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time") :
TimeZoneInfo.FindSystemTimeZoneById("America/New_York");

Starting with .NET 6, it is finally possible to work with time zones in a cross-platform manner.
The TimeZoneInfo.FindSystemTimeZoneById(string) method automatically accepts either Windows or IANA time zones on either platform and convert them if needed.
// Both of these will now work on any supported OS where ICU and time zone data are available.
TimeZoneInfo tzi1 = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
TimeZoneInfo tzi2 = TimeZoneInfo.FindSystemTimeZoneById("Australia/Sydney");
Note that, as specified on the link, the .NET Core Alpine Linux-based Docker images do not have the necessary tzdata installed by default, so it must be installed in your Dockerfile for this to work correctly.

I was able to support this use-case in my development docker image by doing the following:
cp /usr/share/zoneinfo/America/Los_Angeles "/usr/share/zoneinfo/Pacific Standard Time"
Obviously, I don't think that would be a good idea for production deployments. But it might help in some scenarios.

Quick and dirty solution: serialize your TimeZoneInfo with ToSerializedString in a dummy app on Windows, save the output, then deserialize with FromSerializedString where you need it.
On Windows:
Console.WriteLine(TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time").ToSerializedString());
Output:
Eastern Standard Time;-300;(UTC-05:00) Eastern Time (US & Canada);Eastern Standard Time;Eastern Daylight Time;[01:01:0001;12:31:2006;60;[0;02:00:00;4;1;0;];[0;02:00:00;10;5;0;];][01:01:2007;12:31:9999;60;[0;02:00:00;3;2;0;];[0;02:00:00;11;1;0;];];
Then:
// TimeZoneInfo is immutable
public static readonly TimeZoneInfo EST = TimeZoneInfo.FromSerializedString(
"Eastern Standard Time;-300;(UTC-05:00) Eastern Time (US & Canada);Eastern Standard Time;Eastern Daylight Time;[01:01:0001;12:31:2006;60;[0;02:00:00;4;1;0;];[0;02:00:00;10;5;0;];][01:01:2007;12:31:9999;60;[0;02:00:00;3;2;0;];[0;02:00:00;11;1;0;];];");

I ended up writing a small helper function:
public static TimeZoneInfo GetTimeZone(string unixId, string windowsId)
{
foreach (TimeZoneInfo timezone in TimeZoneInfo.GetSystemTimeZones())
{
if (timezone.Id == windowsId|| timezone.Id == unixId)
{
return timezone;
}
}
return null;
}

Related

Getting Timezone info issue on AWS Lambda C# [duplicate]

For example, when I try to do the following.
TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time")
I get the error, that the TimeZone is not available on the local computer. When I run this locally it works, but there I run it on windows. When deployed it runs on a Unix machine in Nginx. I can see that FindSystemTimeZoneById is looking in the wrong folder when it comes to Unix. Is there any way to make this work?
.Net Core using system timezone. Unfortunately Windows and Linux have different timezone system. Now you have two ways:
Use other (and universal) impementation of timezone like Noda time
Translate
between Windows and IANA time zones, e.g. using the TimeZoneConverter micro-library.
Working of off the previous answer, we can avoid the expensive try/catch by checking which OS we're running on:
using System;
using System.Runtime.InteropServices;
TimeZoneInfo easternStandardTime;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
easternStandardTime = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
}
Can you please try this?
TimeZoneInfo easternZone;
try
{
easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
}
catch (TimeZoneNotFoundException)
{
easternZone = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
}
You can review the list of IANA time zones here https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
If you want to try a Windows time zone and then fallback on a IANA one if the Windows one doesn't exist:
var tzi = TimeZoneInfo.GetSystemTimeZones().Any(x => x.Id == "Eastern Standard Time") ?
TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time") :
TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
Starting with .NET 6, it is finally possible to work with time zones in a cross-platform manner.
The TimeZoneInfo.FindSystemTimeZoneById(string) method automatically accepts either Windows or IANA time zones on either platform and convert them if needed.
// Both of these will now work on any supported OS where ICU and time zone data are available.
TimeZoneInfo tzi1 = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
TimeZoneInfo tzi2 = TimeZoneInfo.FindSystemTimeZoneById("Australia/Sydney");
Note that, as specified on the link, the .NET Core Alpine Linux-based Docker images do not have the necessary tzdata installed by default, so it must be installed in your Dockerfile for this to work correctly.
I was able to support this use-case in my development docker image by doing the following:
cp /usr/share/zoneinfo/America/Los_Angeles "/usr/share/zoneinfo/Pacific Standard Time"
Obviously, I don't think that would be a good idea for production deployments. But it might help in some scenarios.
Quick and dirty solution: serialize your TimeZoneInfo with ToSerializedString in a dummy app on Windows, save the output, then deserialize with FromSerializedString where you need it.
On Windows:
Console.WriteLine(TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time").ToSerializedString());
Output:
Eastern Standard Time;-300;(UTC-05:00) Eastern Time (US & Canada);Eastern Standard Time;Eastern Daylight Time;[01:01:0001;12:31:2006;60;[0;02:00:00;4;1;0;];[0;02:00:00;10;5;0;];][01:01:2007;12:31:9999;60;[0;02:00:00;3;2;0;];[0;02:00:00;11;1;0;];];
Then:
// TimeZoneInfo is immutable
public static readonly TimeZoneInfo EST = TimeZoneInfo.FromSerializedString(
"Eastern Standard Time;-300;(UTC-05:00) Eastern Time (US & Canada);Eastern Standard Time;Eastern Daylight Time;[01:01:0001;12:31:2006;60;[0;02:00:00;4;1;0;];[0;02:00:00;10;5;0;];][01:01:2007;12:31:9999;60;[0;02:00:00;3;2;0;];[0;02:00:00;11;1;0;];];");
I ended up writing a small helper function:
public static TimeZoneInfo GetTimeZone(string unixId, string windowsId)
{
foreach (TimeZoneInfo timezone in TimeZoneInfo.GetSystemTimeZones())
{
if (timezone.Id == windowsId|| timezone.Id == unixId)
{
return timezone;
}
}
return null;
}

How to set Default Time zone for C# Desktop Application?

I have a c# desktop application that consumes an API. My Client is from a different time zone. So when we both consume the same API, we get different date time even the date is the same in the database. How can I set the default time zone for my application in c# code so that when I access it from the development environment, I can set my timezone and when I deploy it in production then I can set my client's time zone? I already debugged and found .NET automatically converts the time as soon as it gets the response from the API, so I can not do anything in the response stream.
if the dateTime is changing for you and your client, it means that there is an offset value attached to the dateTime when it is retrieved from the API.
So, do a check for development environment in your application and fetch the UTC DateTime using "UtcDateTime" property of DateTimeOffset type and display it in the UI so that it is the same for both you and your client. In case of the production environment, just keep the usual flowing going.
if(IsDevEnvironment)
DateTimeToDisplay = ApiResponse.DateTimeInDB.UtcDateTime; // assuming DateTimeInDB is of DateTimeOffset type
else
DateTimeToDisplay = ApiResponse.DateTimeInDB
Here is a way to set a timezone, example eastern timezone.
TimeZoneInfo easternZone;
try { easternZone = TimeZoneInfo.FindSystemTimeZoneById("E. Africa Standard Time"); }
catch (TimeZoneNotFoundException) { easternZone = TimeZoneInfo.FindSystemTimeZoneById("Africa/Nairobi"); }
var timestamp = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, easternZone);
try that ;
HAVING (Time BETWEEN DATEADD(d, - 1, GETUTCDATE()) AND GETUTCDATE())
it is helpful for me.
example
ELECT Time, username, COUNT(username) AS CountOfusername
FROM dbo.tabl
GROUP BY Time, username
HAVING (Time BETWEEN DATEADD(d, - 1, GETUTCDATE()) AND GETUTCDATE())
edit
DateTime hwTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.UtcNow, "Arab Standard Time");
//DateTime hwTime = new DateTime();
try
{
TimeZoneInfo hwZone = TimeZoneInfo.FindSystemTimeZoneById("Arab Standard Time");
Console.WriteLine("{0} {1} is {2} local time.",
hwTime,
hwZone.IsDaylightSavingTime(hwTime) ? hwZone.DaylightName : hwZone.StandardName,
TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local));
}
catch (TimeZoneNotFoundException)
{
Console.WriteLine("The registry does not define the Arab Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
Console.WriteLine("Registry data on the Arab Standard Time zone has been corrupted.");
}
us this code in your application

Displaying the time for the right time zone

I have a .NET Core 2.2 web app running inside a docker-compose app. I'm saving different UTC time stamps to a database, like this:
//set asked state on question
Question questionInDb = c.Questions.Single(x => x.Id == id);
questionInDb.Asked = true;
questionInDb.AskTime = DateTime.UtcNow;
c.SaveChanges();
In the apppsettings.json I have a section for my app's settings, containing the locale the application is supposed to run on. I set the CultureInfo.CurrentCulture like so:
//get locale from settings, defaulting to de-DE
string locale = "de-DE";
locale = Configuration.GetValue<string>("AppSettings:Locale");
var ci = new CultureInfo(locale, false);
//actually setting locale
CultureInfo.CurrentCulture = ci;
I set up my Entity Framework to set all DateTimes to DateTimeKind.Utc, so the app knows the DateTimes it gets are all UTC.
Now, when displaying the time on a view, it's not the right hour. In the view.cshtml I'm using #q.AskTime.ToString("HH:mm:ss dd.MM.yy"), but it always returns the exact value from the database. It's supposed to show one hour more.
I even tried setting the container's timezone to CET (Centran Euopean Time) using ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone (in my docker-compose I set the environment variable TZ to Europe/Berlin).
I'm out of ideas.
Cultures (also known as locales) are used for displaying and formatting data and is a different concept than timezones. You can find and create a specific TimeZoneInfo from a timezone name and convert an UTC date and time using the ConvertTimeFromUtc() method.
Keep in mind that different operating systems use different timezone names. For example you can use Europe/Berlin for Linux and Central Europe Standard Time for Windows.
Example:
TimeZoneInfo tz;
try
{
// Linux
tz = TimeZoneInfo.FindSystemTimeZoneById("Europe/Berlin");
}
catch (TimeZoneNotFoundException)
{
try
{
// Windows
tz = TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time");
}
catch (TimeZoneNotFoundException)
{
// Fallback to UTC
tz = TimeZoneInfo.Utc;
}
}
var converted = tz.ConvertTimeFromUtc(DateTime.UtcNow);

Setting different time zone in IIS or web.config

I am logging time in many places
If Request.DynamicSettings.AirlineSettings.AirlineGeneralSettings.TimeLogEnabled Then
StartTime = DateTime.Now
LogTime(Reflection.MethodBase.GetCurrentMethod.DeclaringType.FullName, Reflection.MethodBase.GetCurrentMethod.Name, StartTime, DateTime.Now, "AB-SCR(I)", 0,)
End If
all places i have used
DateTime.Now
I am facing an issue now,
I am currently hosting this in a gulf server, GMT +4:00
I need to host this same project for another country at Gmt +3Gmt
for this hosting i need time to be logged using that country's local time.
Is there any way to do this, without having to modify each and every line of my code.
i have seen this article timzone with asp.net but as my service is already up i have a lot of codes to change, i am looking for a simpler solution.
thanks.
A few things:
You cannot change the time zone in the IIS configuration or web.config. This is not an IIS problem, but rather a problem in your application code.
DateTime.Now should never be used in a server side application, such as an ASP.Net web application. Read The case against DateTime.Now.
If you are just timing how long something takes to run, don't use DateTime at all. Instead, use System.Diagnostics.Stopwatch.
Stopwatch sw = Stopwatch.StartNew();
// ...do some work ...
sw.Stop();
TimeSpan elapsed = sw.Elapsed; // how long it took will be in the Elapsed property
If you actually want the current time in a specific time zone, then you need to know the time zone identifier. (GMT+4 and GMT+3 are not time zones, but rather time zone offsets see "Time Zone != Offset" in the timezone tag wiki.) You can see a list of Windows time zones by using TimeZoneInfo.GetSystemTimeZones(), or by calling tzutil /l on the command line.
Then in your application:
string tz = "Arabian Standard Time";
DateTime now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tz);
You should probably refactor your code such that this is done inside your LogTime method. Then you will have only one place to set the time zone for your application.

Can I get the Original Install Date of the Windows using C#?

How can I get the Original Install Date of the Windows using C#?
From this website, using the registry rather than WMI (untested):
public static DateTime GetWindowsInstallationDateTime(string computerName)
{
Microsoft.Win32.RegistryKey key = Microsoft.Win32.RegistryKey.OpenRemoteBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, computerName);
key = key.OpenSubKey(#"SOFTWARE\Microsoft\Windows NT\CurrentVersion", false);
if (key != null)
{
DateTime installDate =
DateTime.FromFileTimeUtc(
Convert.ToInt64(
key.GetValue("InstallDate").ToString()));
return installDate;
}
return DateTime.MinValue;
}
The HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\InstallDate is the Windows InstallDate using a Unix timestamp, but technically it's the wrong date.
Let me explain;
The definition of UNIX timestamp is time zone independent. The UNIX timestamp is defined as the number of seconds that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970 and not counting leap seconds.
In other words, if you have installed you computer in Seattle, WA and moved to New York,NY the HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\InstallDate will give you the date in NY timezone, not in Seattle timezone where Windows was original installed. It's the wrong date, it doesn't store timezone where the computer was initially installed.
Solution
Change you computer time zone (right-click on you clock->Adjust date/time->Adjust time zone) to the time zone where windows was installed, or first turned on. Then run systeminfo.exe find /i "Original Install Date"
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\InstallDate but you have add the time zone where windows was installed, or first turned on.

Categories

Resources