在c#的特定时区创建一个DateTime

时间:2021-01-06 11:15:00

I'm trying to create a unit test to test the case for when the timezone changes on a machine because it has been incorrectly set and then corrected.

我正在尝试创建一个单元测试,以测试当机器上的时区发生变化时的情况,因为它被错误地设置然后被纠正。

In the test I need to be able to create DateTime objects in a none local time zone to ensure that people running the test can do so successfully irrespective of where they are located.

在测试中,我需要能够在一个非本地时区中创建DateTime对象,以确保运行测试的人员能够成功地创建这些对象,而不管它们位于何处。

From what I can see from the DateTime constructor I can set the TimeZone to be either the local timezone, the UTC timezone or not specified.

从DateTime构造函数中可以看到,我可以将时区设置为本地时区、UTC时区或未指定时区。

How do I create a DateTime with a specific timezone like PST?

如何创建具有特定时区(如PST)的DateTime ?

6 个解决方案

#1


167  

Jon's answer talks about TimeZone, but I'd suggest using TimeZoneInfo instead.

Jon的回答是关于时区的,但是我建议使用TimeZoneInfo。

Personally I like keeping things in UTC where possible, so I'd suggest a structure like this:

就我个人而言,我喜欢把东西放在UTC,所以我建议这样的结构:

public struct DateTimeWithZone
{
    private readonly DateTime utcDateTime;
    private readonly TimeZoneInfo timeZone;

    public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone)
    {
        var dateTimeUnspec = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
        utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTimeUnspec, timeZone); 
        this.timeZone = timeZone;
    }

    public DateTime UniversalTime { get { return utcDateTime; } }

    public TimeZoneInfo TimeZone { get { return timeZone; } }

    public DateTime LocalTime
    { 
        get 
        { 
            return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); 
        }
    }        
}

You may wish to change the "TimeZone" names to "TimeZoneInfo" to make things clearer - I prefer the briefer names myself.

您可能希望将“时区”名称改为“TimeZoneInfo”,以使事情更清楚——我更喜欢简短的名字。

#2


42  

The DateTimeOffset structure was created for exactly this type of use.

DateTimeOffset结构正是为这种类型的使用而创建的。

See: http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx

参见:http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx

Here's an example of creating a DateTimeOffset object with a specific time zone:

这里有一个使用特定时区创建DateTimeOffset对象的示例:

DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));

DateTimeOffset do1 =新的DateTimeOffset(2008、8、22、1、0、0、新TimeSpan(- 5,0,0));

#3


29  

The other answers here are useful but they don't cover how to access Pacific specifically - here you go:

这里的其他答案是有用的,但它们并没有涵盖如何具体地访问太平洋——在这里你可以:

public static DateTime GmtToPacific(DateTime dateTime)
{
    return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
        TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
}

Oddly enough, although "Pacific Standard Time" normally means something different from "Pacific Daily Time," in this case it refers to Pacific time in general. In fact, if you use FindSystemTimeZoneById to fetch it, one of the properties available is a bool telling you whether that timezone is currently in daylight savings or not.

奇怪的是,尽管“太平洋标准时间”通常指的是与“太平洋日”不同的东西,在这里指的是太平洋时间。事实上,如果您使用FindSystemTimeZoneById获取它,一个可用的属性是bool,它告诉您该时区当前是否处于夏令时。

You can see more generalized examples of this in a library I ended up throwing together to deal with DateTimes I need in different TimeZones based on where the user is asking from, etc:

你可以在一个库中看到更一般的例子,这个库是我根据用户的要求处理不同时区所需的数据时间,等等:

https://github.com/b9chris/TimeZoneInfoLib.Net

https://github.com/b9chris/TimeZoneInfoLib.Net

This won't work outside of Windows (for example Mono on Linux) since the list of times comes from the Windows Registry: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

这在Windows之外是行不通的(例如Linux上的Mono),因为时间列表来自Windows注册表:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\时区)

Underneath that you'll find keys (folder icons in Registry Editor); the names of those keys are what you pass to FindSystemTimeZoneById. On Linux you have to use a separate Linux-standard set of timezone definitions, which I've not adequately explored.

在它下面你会找到键(注册表编辑器中的文件夹图标);这些键的名称是您传递给FindSystemTimeZoneById的。在Linux上,您必须使用一个单独的Linux标准的时区定义集,这是我没有充分研究过的。

#4


6  

I altered Jon Skeet answer a bit for the web with extension method. It also works on azure like a charm.

我修改了Jon Skeet对web使用扩展方法的回答。它在azure上也很有魅力。

public static class DateTimeWithZone
{

private static readonly TimeZoneInfo timeZone;

static DateTimeWithZone()
{
//I added web.config <add key="CurrentTimeZoneId" value="Central Europe Standard Time" />
//You can add value directly into function.
    timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["CurrentTimeZoneId"]);
}


public static DateTime LocalTime(this DateTime t)
{
     return TimeZoneInfo.ConvertTime(t, timeZone);   
}
}

#5


2  

You'll have to create a custom object for that. Your custom object will contain two values:

您必须为此创建一个自定义对象。您的自定义对象将包含两个值:

  • a DateTime value
  • 一个DateTime值
  • a TimeZone object
  • 一个时区对象

Not sure if there already is a CLR-provided data type that has that, but at least the TimeZone component is already available.

不确定是否已经有clr提供的数据类型具有该类型,但至少时区组件已经可用。

#6


2  

I like Jon Skeet's answer, but would like to add one thing. I'm not sure if Jon was expecting the ctor to always be passed in the Local timezone. But I want to use it for cases where it's something other then local.

我喜欢Jon Skeet的回答,但是我想补充一点。我不确定Jon是否期望ctor总是在当地时区通过。但是我想把它用在一些非本地的情况下。

I'm reading values from a database, and I know what timezone that database is in. So in the ctor, I'll pass in the timezone of the database. But then I would like the value in local time. Jon's LocalTime does not return the original date converted into a local timezone date. It returns the date converted into the original timezone (whatever you had passed into the ctor).

我正在从数据库中读取值,并且我知道数据库所在的时区。在ctor中,我将传入数据库的时区。然后我想要当地时间的值。Jon的LocalTime不返回转换为本地时区日期的原始日期。它返回转换为原始时区的日期(无论您传递给ctor的是什么)。

I think these property names clear it up...

我认为这些财产名称澄清了……

public DateTime TimeInOriginalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } }
public DateTime TimeInLocalZone    { get { return TimeZoneInfo.ConvertTime(utcDateTime, TimeZoneInfo.Local); } }
public DateTime TimeInSpecificZone(TimeZoneInfo tz)
{
    return TimeZoneInfo.ConvertTime(utcDateTime, tz);
}

#1


167  

Jon's answer talks about TimeZone, but I'd suggest using TimeZoneInfo instead.

Jon的回答是关于时区的,但是我建议使用TimeZoneInfo。

Personally I like keeping things in UTC where possible, so I'd suggest a structure like this:

就我个人而言,我喜欢把东西放在UTC,所以我建议这样的结构:

public struct DateTimeWithZone
{
    private readonly DateTime utcDateTime;
    private readonly TimeZoneInfo timeZone;

    public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone)
    {
        var dateTimeUnspec = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
        utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTimeUnspec, timeZone); 
        this.timeZone = timeZone;
    }

    public DateTime UniversalTime { get { return utcDateTime; } }

    public TimeZoneInfo TimeZone { get { return timeZone; } }

    public DateTime LocalTime
    { 
        get 
        { 
            return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); 
        }
    }        
}

You may wish to change the "TimeZone" names to "TimeZoneInfo" to make things clearer - I prefer the briefer names myself.

您可能希望将“时区”名称改为“TimeZoneInfo”,以使事情更清楚——我更喜欢简短的名字。

#2


42  

The DateTimeOffset structure was created for exactly this type of use.

DateTimeOffset结构正是为这种类型的使用而创建的。

See: http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx

参见:http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx

Here's an example of creating a DateTimeOffset object with a specific time zone:

这里有一个使用特定时区创建DateTimeOffset对象的示例:

DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));

DateTimeOffset do1 =新的DateTimeOffset(2008、8、22、1、0、0、新TimeSpan(- 5,0,0));

#3


29  

The other answers here are useful but they don't cover how to access Pacific specifically - here you go:

这里的其他答案是有用的,但它们并没有涵盖如何具体地访问太平洋——在这里你可以:

public static DateTime GmtToPacific(DateTime dateTime)
{
    return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
        TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
}

Oddly enough, although "Pacific Standard Time" normally means something different from "Pacific Daily Time," in this case it refers to Pacific time in general. In fact, if you use FindSystemTimeZoneById to fetch it, one of the properties available is a bool telling you whether that timezone is currently in daylight savings or not.

奇怪的是,尽管“太平洋标准时间”通常指的是与“太平洋日”不同的东西,在这里指的是太平洋时间。事实上,如果您使用FindSystemTimeZoneById获取它,一个可用的属性是bool,它告诉您该时区当前是否处于夏令时。

You can see more generalized examples of this in a library I ended up throwing together to deal with DateTimes I need in different TimeZones based on where the user is asking from, etc:

你可以在一个库中看到更一般的例子,这个库是我根据用户的要求处理不同时区所需的数据时间,等等:

https://github.com/b9chris/TimeZoneInfoLib.Net

https://github.com/b9chris/TimeZoneInfoLib.Net

This won't work outside of Windows (for example Mono on Linux) since the list of times comes from the Windows Registry: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

这在Windows之外是行不通的(例如Linux上的Mono),因为时间列表来自Windows注册表:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\时区)

Underneath that you'll find keys (folder icons in Registry Editor); the names of those keys are what you pass to FindSystemTimeZoneById. On Linux you have to use a separate Linux-standard set of timezone definitions, which I've not adequately explored.

在它下面你会找到键(注册表编辑器中的文件夹图标);这些键的名称是您传递给FindSystemTimeZoneById的。在Linux上,您必须使用一个单独的Linux标准的时区定义集,这是我没有充分研究过的。

#4


6  

I altered Jon Skeet answer a bit for the web with extension method. It also works on azure like a charm.

我修改了Jon Skeet对web使用扩展方法的回答。它在azure上也很有魅力。

public static class DateTimeWithZone
{

private static readonly TimeZoneInfo timeZone;

static DateTimeWithZone()
{
//I added web.config <add key="CurrentTimeZoneId" value="Central Europe Standard Time" />
//You can add value directly into function.
    timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["CurrentTimeZoneId"]);
}


public static DateTime LocalTime(this DateTime t)
{
     return TimeZoneInfo.ConvertTime(t, timeZone);   
}
}

#5


2  

You'll have to create a custom object for that. Your custom object will contain two values:

您必须为此创建一个自定义对象。您的自定义对象将包含两个值:

  • a DateTime value
  • 一个DateTime值
  • a TimeZone object
  • 一个时区对象

Not sure if there already is a CLR-provided data type that has that, but at least the TimeZone component is already available.

不确定是否已经有clr提供的数据类型具有该类型,但至少时区组件已经可用。

#6


2  

I like Jon Skeet's answer, but would like to add one thing. I'm not sure if Jon was expecting the ctor to always be passed in the Local timezone. But I want to use it for cases where it's something other then local.

我喜欢Jon Skeet的回答,但是我想补充一点。我不确定Jon是否期望ctor总是在当地时区通过。但是我想把它用在一些非本地的情况下。

I'm reading values from a database, and I know what timezone that database is in. So in the ctor, I'll pass in the timezone of the database. But then I would like the value in local time. Jon's LocalTime does not return the original date converted into a local timezone date. It returns the date converted into the original timezone (whatever you had passed into the ctor).

我正在从数据库中读取值,并且我知道数据库所在的时区。在ctor中,我将传入数据库的时区。然后我想要当地时间的值。Jon的LocalTime不返回转换为本地时区日期的原始日期。它返回转换为原始时区的日期(无论您传递给ctor的是什么)。

I think these property names clear it up...

我认为这些财产名称澄清了……

public DateTime TimeInOriginalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } }
public DateTime TimeInLocalZone    { get { return TimeZoneInfo.ConvertTime(utcDateTime, TimeZoneInfo.Local); } }
public DateTime TimeInSpecificZone(TimeZoneInfo tz)
{
    return TimeZoneInfo.ConvertTime(utcDateTime, tz);
}