У меня проблема с итальянским летним временем. Преобразование unix 687481200000 в .NET выглядит непредсказуемо (конечно, я что-то упускаю).
Как вы можете видеть, набрав в консоли браузера:
console.info(new Date(687481200000).toLocaleString('it-IT', {timeZone: 'Europe/Rome', timeZoneName: 'short'}));
значение временной метки unix 687481200000 должно возвращать итальянскую дату 1991-10-15 00:00:00 (в Италии дата вводится 15.10.1991, но мы всегда говорим о 15 октября).
Теперь я хочу, чтобы вы взглянули на этот фрагмент
https://dotnetfiddle.net/jKShoE
Когда я запускаю его в браузере с помощью компилятора: .NET 6, я получаю
Данные e ora Italiane: 15.10.1991 00:00:00
изменение компилятора на .NET 4.7.2
https://dotnetfiddle.net/GV7FYD
я получил
Данные e ora Italiane: 15.10.1991, 1:00:00
И если я скопирую этот код в новый проект .NET 6 в Visual Studio 2022
Данные e ora Italiane: 15.10.1991 01:00:00
Кто-нибудь может объяснить мне, почему? Есть ли способ получить правильный час 00:00:00 без использования внешних библиотек (например, NodaTime)?
Ps: работает на Windows 10.0.19045 сборка 19045, итальянская локализация
Обновлено: вот код из скрипки.
using System;
public class Program
{
public static void Main()
{
long unixMilliseconds = 687481200000;
DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(unixMilliseconds);
TimeZoneInfo italianTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
DateTimeOffset italianDateTimeOffset = TimeZoneInfo.ConvertTime(dateTimeOffset, italianTimeZone);
DateTime italianDateTime = italianDateTimeOffset.DateTime;
Console.WriteLine("Data e ora italiane: " + italianDateTime);
}
}
Редактировать 2: пересмотренный код
Мне пришлось копать глубже и найти больше ответов, когда я искал TimeZoneInfo.AdjustmentRule в stackoverflow.
using System;
using System.Linq;
public class Program
{
public static void Main()
{
// A representation for UTC 14/10/1991 23:00:00 +00:00
long unixMilliseconds = 687481200000;
// Looking at epochconverter.com
// UTC 14/10/1991 23:00:00 +00:00
// corresponds to italian 15 october 1991 00:00:00 GMT+01:00
// Store the UTC time in dateTimeOffset
DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(unixMilliseconds);
Console.WriteLine(dateTimeOffset);
// .NET 6: 10/14/1991 23:00:00 +00:00
// .NET 4.7.2: 10/14/1991 11:00:00 PM +00:00
// Applying the following pattern:
// https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset.fromunixtimemilliseconds?view=net-8.0#remarks
// I was wrong, my current timezone is "W. Europe Standard Time" but the nature of the problem remains unchanged.
// I retrieved my TimeZoneInfo this way:
TimeZoneInfo italianTimeZone = TimeZoneInfo.Local;
Console.WriteLine("TimeZoneInfo.Local.Id: " + TimeZoneInfo.Local.Id); // I got here W. Europe Standard Time
// so retrieving it by ID to make it work on fiddler
italianTimeZone = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
Console.WriteLine("TimeZoneInfo Id: " + italianTimeZone.Id); // Once again to check
Console.WriteLine("TimeZoneInfo: " + italianTimeZone.ToString());
// .NET 6: (UTC+01:00) Central European Time (Berlin)
// .NET 4.7.2: (UTC+01:00) Amsterdam, Berlino, Berna, Roma, Stoccolma, Vienna
Console.WriteLine("Daylight : " + italianTimeZone.IsDaylightSavingTime(dateTimeOffset));
// fiddler .NET 6 : False
// fiddler .NET 4.7 : True
// "my PC" .NET 6 : True
// Now look at this:
Console.WriteLine("Rules count: " + italianTimeZone.GetAdjustmentRules().Length);
// fiddler .NET 6 : 79
// fiddler .NET 4.7 : 1
// "my PC" .NET 6 : 1
// Only in the fiddler .NET 6 the full set of rules is available.
// BONUS
string iso8601 = "1991-10-14T23:00:00Z";
long myDate = DateTimeOffset.Parse(iso8601).ToUnixTimeMilliseconds();
Console.WriteLine("My date: " + myDate); // My date: 687481200000 on every system
}
}
Мне до сих пор неясно, как и кто управляет базой данных часовых поясов, будь то операционная система или платформа .NET, но мне кажется, что эта конфигурация достаточно сложна, чтобы заставить меня выбрать использование NodaTime (я не знаю, Я не хочу вмешиваться в конфигурацию машины, чтобы получить достоверные результаты).
Вы можете увидеть перечень правил дневного света здесь: Показаны времена перехода
Почему вы вообще используете временную метку Unix? И Javascript, и .NET имеют правильные типы дат и поддерживают единственное стандартное представление — ISO8601. Временные метки Unix также всегда указаны в формате UTC. Если вы обнаружите разницу в местном времени, это связано с тем, что было использовано неправильное преобразование часового пояса.
I'm missing something
да. Проблема в коде JavaScript. Как показано в документации конструктора даты , временная метка — это UTC the number of milliseconds since midnight at the beginning of January 1, 1970, UTC
, но конструктор Date рассматривает ее как локальную. The parameter values are all evaluated against the local time zone, rather than UTC. Date.UTC() accepts similar parameters but interprets the components as UTC and returns a timestamp.
Дело в светлом времени:
В .Net 6: https://dotnetfiddle.net/qP1icN
Daylight : False
Data e ora italiane: 10/15/1991 00:00:00
В .Net 4.7.2: https://dotnetfiddle.net/7eBu3y
Daylight : True
Data e ora italiane: 10/15/1991 1:00:00 AM
Людям платят за решение подобных проблем по всему миру...
Не совсем - код JS с самого начала неверен, поскольку временная метка UTC обрабатывается так, как если бы она была локальной.
Действительно, но почему один и тот же код C# дает два разных результата в зависимости от версии .Net?
Потому что код .NET тоже неправильный и ошибочно предполагает, что временная метка является локальной. Для переключения смещений вы используете DateTimeOffset.ToOffset, а не арифметику дат. В вашей скрипке 4.7.2 попробуйте Console.WriteLine(dateTimeOffset);
и посмотрите, как она напечатана 10/14/1991 11:00:00 PM +00:00
. После этого все остальное не так People get paid to handle this kind of problem worldwide...
нет, старшие разработчики раздражаются, когда люди повторно вводят те же ошибки, которые они исправили в прошлом году и позапрошлом году.
Так это связано с локализацией dotnetfiddle? Я не понимаю, почему существует разница между версиями .Net.
Пожалуйста, включите код в сам вопрос, а не просто ссылку на dotnetfiddle.