函数使用国家/城市而不是时区代码在时间之间进行转换

本文关键字:时间 代码 之间 转换 时区 国家 城市 函数 | 更新日期: 2023-09-27 18:13:02

我正在用c#编写一个程序来转换来自不同国家的时间(类似于这样)。在浏览了Stack Overflow之后,大多数人似乎都对使用时区代码进行转换感兴趣(例如从GMT到EDT或从EST到BST)。这让我觉得有点奇怪,因为你需要通过另一个障碍来考虑DST的复杂性。

更简单(也更实用,至少对我来说)的方法是简单地指定你想要转换时间的国家/城市/州。如果我们现在只关注本地时间,我已经创建了这两个函数来从本地时间转换为FileTime(本质上是UTC),然后再转换回来。

// Example use: convert_LocalToFile("1/11/2011 00:00:00") = 129645792000000000
long convert_LocalToFile(string time)
{
    DateTime dt = DateTime.Parse(time);
    return dt.ToFileTime();
}
// Example use: convert_FileToLocal(129645792000000000) = "1/11/2011 00:00:00"
string convert_FileToLocal(long time)
{
    return DateTime.FromFileTime(time).ToString();
}

然而,如果我们一劳永逸地解决了这个问题,并拥有允许您指定国家/城市的功能,那将是非常棒的。规范如下:

// Example use 1: convert_AnyToFile("1/11/2011 00:00:00", "England") = 129645792000000000
// Example use 2: convert_AnyToFile("1/11/2011 00:00:00","New York") = 129645936000000000
long convert_AnyToFile(string time, string location) {
    ...
}
// Example use 1: convert_FileToAny(129645792000000000, "England") = "1/11/2011 00:00:00"
// Example use 2: convert_FileToAny(129645936000000000,"New York") = "1/11/2011 00:00:00"
string convert_FileToAny(long time, string location) {
    ...
}

所以我的问题是双重的:有人可以"填写"上面两个空函数使它们工作,并提供一种方法让c#列出所有允许作为参数的国家和城市吗?

------------------------编辑:而不是国家或城市,我也会用晦涩的(反正对我来说)TZ代码从这个页面显示:http://en.wikipedia.org/wiki/List_of_tz_database_time_zones

如前所述,我需要找到一个数据文件,将tz数据库代码映射到国家/城市/地区。在本例中,将上述两个函数模板中的"string location"替换为"string code"。'code'表示tz数据库时区代码(tz),而不是典型的时区代码(如EST或GMT)。

函数使用国家/城市而不是时区代码在时间之间进行转换

根据注释的一些指示:

有关转换代码,请参阅c# fx 3.5和http://www.jarloo.com/c-convert-timezones/中在特定时区创建DateTime。

有关tz_database(也称为Olson…)中处理时区的代码,请参阅http://www.twinsun.com/tz/tz-link.htm和http://www.codeproject.com/KB/dotnet/Using_time_zones_in_NET.aspx。

MSDN对相关类/方法等的引用:

  • http://msdn.microsoft.com/en-us/library/system.datetime.aspx
  • http://msdn.microsoft.com/en-us/library/bb384267.aspx
  • http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx
  • http://msdn.microsoft.com/en-us/library/system.timezoneinfo.getsystemtimezones.aspx

在阅读了NodaTime(甚至不知道它的存在)之后,我强烈建议使用它-参见Jon Skeet的答案。

正如在一个类似的问题中指出的那样,人们需要小心,因为Windows使用了非常误导人的名称(例如:奇怪的欧洲/巴黎的"浪漫标准时间"或"东部标准时间",它奇怪地起着ET的作用,使用夏令时,而官方定义则相反。更不用说美国东部标准时间了。

关于从Windows的时区映射城市/州/国家,我还没有找到任何数据文件,但我会继续寻找。我猜人们可能需要找到从Windows时区名称转换到奥尔森时区的数据,然后从那里转换到单个城市/州/国家名称。这个链接将有助于前者:http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/zone_tzid.html

考虑到这一点,我已经填入了主问题中的空函数(感谢Jon和Yahia提供的指针)。第一个是主函数,对大多数人来说都是有用的。其他两个是第一个函数使用的次要函数。

我已经检查过了,它们适用于夏令时,尽管我打赌Jon Skeet和其他人能够找到一些"小"缺陷。例如,大约1601年之前的日期将不工作,因为Windows的文件时间不支持。当然,还建议在try/catch语句中包装对这些函数的调用,以捕获错误的日期输入等。

// Master conversion function
// Example use 1: convertTimezone("1/11/2011 00:00:00", "GMT Standard Time", "Eastern Standard Time") = "31/10/2011 20:00:00"
// Example use 2: convertTimezone("1/11/2011 00:00:00", "Eastern Standard Time", "GMT Standard Time") = "01/11/2011 04:00:00"
// Example use 3: convertTimezone("1/10/2011 00:00:00", "Eastern Standard Time", "GMT Standard Time") = "01/10/2011 05:00:00"
string convertTimezone(string time, string oldlocation, string newlocation)
{
    long l = convertTime_AnyToFile(time, oldlocation);
    string newtime = convertTime_FileToAny(l, newlocation);
    return newtime;
}
// Example use 1: convertTime_AnyToFile("1/11/2011 00:00:00", "GMT Standard Time") =    129645792000000000
// Example use 2: convertTime_AnyToFile("1/11/2011 00:00:00","Eastern Standard Time") = 129645936000000000
long convertTime_AnyToFile(string time, string location)
{
    DateTime a = DateTime.Parse(time  );
    DateTime b = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(a, location, "UTC");
    return b.ToFileTime();
}
// Example use 1: convertTime_FileToAny(129645792000000000, "GMT Standard Time") = "1/11/2011 00:00:00"
// Example use 2: convertTime_FileToAny(129645936000000000,"Eastern Standard Time") = "1/11/2011 00:00:00"
string convertTime_FileToAny(long time, string location)
{
    DateTime a = DateTime.FromFileTimeUtc(time);
    DateTime b = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(a, location);
    return b.ToString();
}

虽然它看起来工作得很好(在我所做的有限测试下),在我"勾选"我自己的答案之前,我可能会先等待一些反馈,因为也许有人可以改进上面的代码。

如果您满足于使用zoneinfo/Olson名称(例如;"欧洲/伦敦","美国/洛杉矶"等等)你可以看看我开始的项目,野田时间。它通常是Joda Time日历引擎的一个移植,但是有一个新的API,更加以。net为中心。

由于缺少一些功能,它还没有达到v1,但是那里的工作应该足够好了。请注意,它解决了DateTime的许多缺陷,特别是区分"本地日期/时间"answers"分区日期/时间"(并且还处理时间或日期)。当然,如果您想要使用Noda Time进行时区转换,则可以进行与DateTime之间的转换—尽管我建议如果可能的话,在代码中广泛使用它。(如果它没有提供你想要的所有功能,请让我们知道,以便我们可以添加它们!)

请注意,当将本地时间视为特定时区时,您需要意识到它可能是不明确的或从未存在过的可能性。例如,周日英国的时钟恢复,所以凌晨1:30出现了两次。在春天,凌晨1点30分根本不会发生,因为时钟从凌晨1点到凌晨2点。当然,野田时间提供了不同的选项来处理这个问题,但是你需要弄清楚在每种情况下你想做什么:)