我应该在法国使用哪个时区来支持新旧夏令时调整?

时间:2019-07-15 16:28:03

标签: c# windows datetime timezone

上下文

我们有一个处理时间的C#程序。

我们在法国有客户,因此我们将时间与法国时区之间进行转换。

在C#代码中:我们使用Central European Standard Time作为法国的时区。

它描述了一个时区,它遵循DST更改:

  • 3月的最后一个星期日(凌晨3点),时钟向夏令时的时间向前进1h
  • 在10月的最后一个星期日(凌晨3点),时钟切换到冬季时间,并向后移动1h

我们的情况

问题是:法国于1996年与CEST保持一致;
在该日期之前,法国将在9月的最后一个星期日从夏季更改为冬季。

Window的CEST时区(准确地)描述了CEST,在1995年10月之前的日期恰好不等于法国的时区。

当测试IANA database(在Windows子系统中,用于Linux)时,事实证明欧洲/巴黎时区在9月底准确切换了<1995年的日期。

问题

有没有:

  • Window的标准时区列表中Europe/Paris时区的表示形式?
  • 使用C#中的IANA数据库(和欧洲/巴黎)的一种方法?

我们用于将时间转换为UTC的示例代码:

using System;
using System.Globalization;

namespace TestingApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var tz = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
            string[] times = {
                // In 1995 :
                //  last sunday in september was  sept. 24th
                //  last sunday in october   was   oct. 29th
                "1995/09/23 12:00:00", "1995/09/24 12:00:00",
                "1995/10/28 12:00:00", "1995/10/29 12:00:00",
            };

            foreach (var t in times) {
                var utc = DateTime.ParseExact(t, "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None);
                utc = TimeZoneInfo.ConvertTime(utc, tz, TimeZoneInfo.Utc);

                Console.WriteLine(String.Format("Paris: {0} -> UTC: {1}", t, utc.ToString()));
            }
        }
    }
}

// Output :
//  Paris: 1995/09/23 12:00:00 -> UTC: 23/09/1995 10:00:00
//  Paris: 1995/09/24 12:00:00 -> UTC: 24/09/1995 10:00:00  <- instead of 11:00:00 UTC
//  Paris: 1995/10/28 12:00:00 -> UTC: 28/10/1995 10:00:00  <- instead of 11:00:00 UTC
//  Paris: 1995/10/29 12:00:00 -> UTC: 29/10/1995 11:00:00    

2 个答案:

答案 0 :(得分:5)

  

是否可以使用C#使用IANA数据库(和欧洲/巴黎)?

是的-使用Noda Time项目-我是主要贡献者,因此对我有偏见,但是使用该项目的主要原因之一是支持IANA(又名TZDB)时区。

>

这里有一些示例代码可以与您问题中的代码匹配:

using NodaTime;
using System;
using System.Linq;

namespace TestingApp
{
    class Program
    {
        static void Main(string[] args)
        {            
            var tz = DateTimeZoneProviders.Tzdb["Europe/Paris"];

            var localDates = new[]
            {
                new LocalDate(1995, 9, 23),
                new LocalDate(1995, 9, 24),
                new LocalDate(1995, 10, 28),
                new LocalDate(1995, 10, 29)
            };
            var midday = new LocalTime(12, 0, 0);
            var localDateTimes = localDates.Select(date => date.At(midday));

            foreach (var localDateTime in localDateTimes)
            {
                var utc = localDateTime.InZoneStrictly(tz).WithZone(DateTimeZone.Utc);
                Console.WriteLine($"Paris: {localDateTime:yyyy/MM/dd HH:mm:ss} -> UTC: {utc:yyyy/MM/dd HH:mm:ss}");
            }
        }
    }
}

答案 1 :(得分:1)

请参阅@JonSkeet解决方案。它比这简单得多。我不会删除更复杂的答案,因为这种解释对于某人了解标准的.NET TimeZone会发生什么很有用。

这有点复杂,但是可能。

.NET框架使用TimeZoneInfo定义时间更改规则。此类具有嵌套的TimeZoneInfo.AdjustmentRule,该嵌套的目的是定义小时的变化时间。

我住在西班牙(欧洲),所以我的Windows已安装欧洲时区信息。您可以使用方法TimeZoneInfo.GetSystemTimeZones()获取系统的所有时区信息。

唯一提到法国的是:

{(UTC+01:00) Bruselas, Copenhague, Madrid, París}

如果您进行检查,只会发现一个TimeZoneInfo.AdjustmentRule来定义当前的小时更改,而不是您需要使用的旧的更改:

+ DateStart {01/01/0001 0:00:00} System.DateTime
+ DateEnd   {31/12/9999 0:00:00} System.DateTime
+ DaylightDelta {01:00:00}       System.TimeSpan

- DaylightTransitionStart {System.TimeZoneInfo.TransitionTime} System.TimeZoneInfo.TransitionTime
  Day             1      int
  DayOfWeek       Sunday System.DayOfWeek
  IsFixedDateRule false  bool
  Month           3      int
  + TimeOfDay {01/01/0001 2:00:00} System.DateTime
    Week 5 int

- DaylightTransitionEnd {System.TimeZoneInfo.TransitionTime} System.TimeZoneInfo.TransitionTime
 Day             1      int
 DayOfWeek       Sunday System.DayOfWeek
 IsFixedDateRule false  bool
 Month           10     int
 + TimeOfDay {01/01/0001 3:00:00} System.DateTime
   Week 5 int

因此,至少在西班牙语Windows(我怀疑在所有欧洲Windows)上,法国对小时更改的旧规则没有定义。

我认为唯一的解决方案是创建自己的自定义时区并在应用程序TimeZoneInfo.CreateCustomTimeZone Method中使用它

创建此自定义时区信息时,可以包括旧的调整规则:  -为旧规则和新规则指定有效的DateStart,DateEnd  -为每个属性指定其余属性:DaylightDelta, DaylightTransitionEnd, Day, DayOfweek...,依此类推,以此类推。

我不知道是否可以在任何地方找到此规则,但是创建自定义规则可以解决您的问题。