整个地球分为二十四时区,每个时区都有自己的本地时间。在国际无线电通信场合,为了统一起见,使用一个统一的时间,称为通用协调时(UTC, Universal Time Coordinated)。UTC与格林尼治平均时(GMT, Greenwich Mean Time)一样,都与英国伦敦的本地时相同。在本文中,UTC与GMT含义完全相同。
北京时区是东八区,领先UTC八个小时,在电子邮件信头的Date域记为+0800。如果在电子邮件的信头中有这么一行:
Date: Fri, 08 Nov 2002 09:42:22 +0800
说明信件的发送地的地方时间是二○○二年十一月八号,星期五,早上九点四十二分(二十二秒),这个地方的本地时领先UTC八个小时(+0800, 就是东八区时间)。电子邮件信头的Date域使用二十四小时的时钟,而不使用AM和PM来标记上下午。
以这个电子邮件的发送时间为例,如果要把这个时间转化为UTC,可以使用一下公式:
UTC + 时区差 = 本地时间
时区差东为正,西为负。在此,把东八区时区差记为 +0800,
UTC + (+0800) = 本地(北京)时间 (1)
那么,UTC = 本地时间(北京时间))- 0800 (2)
0942 - 0800 = 0142
即UTC是当天凌晨一点四十二分二十二秒。如果结果是负数就意味着是UTC前一天,把这个负数加上2400就是UTC在前一天的时间。例如,本地 (北京)时间是 0432 (凌晨四点三十二分),那么,UTC就是 0432 - 0800 = -0368,负号意味着是前一天, -0368 + 2400 = 2032,既前一天的晚上八点三十二分。
纽约的时区是西五区,比UTC落后五个小时,记为 -0500:
UTC + (-0500) = 纽约时间 (3)
UTC = 纽约时间 + 0500 (4)
把(2)式 - (4)式相比较,
UTC = 北京时间 - 0800 = 纽约时间 + 0500 (5)
即 北京时间 = 纽约时间 + 1300 (6)
即北京时间领先纽约时间十三个小时,由(6)式,
纽约时间 = 北京时间 - 1300 (7)
在四月下旬,纽约又换用夏令时,又称为日光节约时,比标准纽约时间提前一个小时,实际成为西四区的标准时间,成为 -0400。
UTC + (-0400) = 纽约夏令时,套用以上公式,
北京时间 = 纽约夏令时 + 1200
纽约夏令时 = 北京时间 - 1200
在这些转换中,最重要的公式就是
UTC + 时区差 = 本地时间
时区差东为正,西为负。例如,东八区(北京)是 +0800,西五区(纽约)是-0500,加州是西八区,是-0800,美国中部时区是西六区,-0600,美国山地时区是西七区,-0700,太平洋时 区是西八区,-0800,在夏天使用夏时制,成为-0700。德国时区是东一区,+0100,夏天变为+0200。
多数电子邮件程序,例如Outlook Express,在显示时间时,计算机程序把时间先转换成为本地时间再显示,例如,邮件的Date域为:
Date: Fri, 08 Nov 2002 09:42:22 +0800
Outlook Express在显示时就显示为:
Date: Thur, 07 Nov 2002 08:42:22 pm,把北京时间转换成为了纽约时间,而且把二十四小时格式的时间转换成为了十二小时的格式。当然,为了时间转换正确,发送方和接受方的计算机的时区都要 设置正确,在这里,发送方的时区要正确地设为北京时区东八区,而我的时区要设为西五区。
为了方便起见,我在这里放上纽约,加洲以及北京实时显示的时钟,以省去计算的麻烦。
全球标准时间 (UTC)
全球标准时间指的是由世界时间标准设定的时间。原先也被称为格林威治标准时间或者 GMT。
我们知道,本初子午线被定义从伦敦郊区的皇家格林尼治天文台穿过,那里的时间被定义为全球的标准时间。
中国位于东八区,所以要比这个时间早八个小时,也就是说,全球标准时间是5日0点时,中国是5日的8点,而美国部分地区还处于4日的黄昏。
有些对象、函数中,需要使用 UTC 时间,我们就需要将中国的时间转换成 UTC 时间,使用 toUTCString。
var d = new Date();
document.write("当前的 UTC 时间是:" + d.toUTCString());
toGMTString 与 toUTCString 功能、用法均相同,但我们推荐使用 toUTCString,毕竟 GMT 是以前的称呼。
c#
DateTime 值
DateTime 类型的时间值描述通常使用协调世界时 (UTC) 标准来表达,它是格林尼治标准时间 (GMT) 的国际识别名。协调世界时是在经度零度(即 UTC 原点)测量到的时间。夏时制不适用于 UTC。
本 地时间是相对于特定时区而言。时区与时区偏移量关联,它是时区从 UTC 原点算起的以小时为单位的偏移量。此外,本地时间有可能受夏时制影响,夏时制会对日长增加或减少一小时。因此,本地时间的计算是将时区偏移量加上 UTC,如有必要,再根据夏时制进行调整。UTC 原点的时区偏移量为零。
UTC 时间适合于计算、比较日期和时间,以及将日期和时间存储在文件中。本地时间适合于在桌面应用程序的用户界面中显示。识别时区的应用程序(如许多 Web 应用程序)还需要使用许多其他时区。
如果 DateTime 对象的 Kind 属性为 DateTimeKind..::.Unspecified,则其未指定表示的时间是本地时间、UTC 时间还是某个其他时区中的时间。
DateTime 运算
使用 DateTime 结构的计算(如 Add 或 Subtract)不会修改该结构的值。相反,计算会返回新的 DateTime 结构,其值为计算结果。
说明: |
---|
DateTime 对象的计算和比较仅当这些对象表示同一时区中的时间时才有意义。 |
时区之间(例如,UTC 和本地时间之间,或者一个时区中的时间和本地时间之间)的转换运算会考虑本地时区的夏时制,但是算术和比较运算不考虑。
DateTime 结构本身不太支持从一个时区转换至另一个时区。您可以使用 ToLocalTime 方法将 UTC 转换为本地时间,也可以使用 ToUniversalTime 方法从本地时间转换为 UTC。但是,整套的时区转换方法是在 TimeZoneInfo 类中提供的。使用这些方法,可以将世界上任一时区中的时间转换为 UTC 或者本地时间。
每个 DateTime 成员都隐式使用公历执行其操作,例外是指定日历的构造函数以及使用从 IFormatProvider 派生的参数(如 System.Globalization..::.DateTimeFormatInfo)的方法,该参数隐式指定日历。
DateTime 类型中的成员所执行的运算会考虑闰年和月中天数等细节。
DateTime 与 TimeSpan
DateTime 值类型与 TimeSpan 值类型的差异在于 DateTime 表示时间上的一刻,而 TimeSpan 表示时间间隔。例如,这意味着将 DateTime 的一个实例与另一个实例相减可以获得表示这两个实例之间的时间间隔的 TimeSpan 对象。或者,将一个正 TimeSpan 与当前 DateTime 相加可以获得表示将来日期的 DateTime 值。
可以向 DateTime 对象增加或减少一个时间间隔。时间间隔可为负,也可为正,可以用刻度或秒等为单位表示,也可表示为 TimeSpan 对象。
实现的接口
此类型实现 IComparable、IComparable<(Of <(T>)>)、IEquatable<(Of <(T>)>)、IFormattable 和 IConvertible 接口。使用 Convert 类进行转换,而不是使用此类型的 IConvertible 显式接口成员实现。
下面的代码示例演示如何大致比较等效的 DateTime 值,将它们声明为“相等”时接受很小的差异。
2
3class Example
4{
5
6 static bool RoughlyEquals(DateTime time, DateTime timeWithWindow, int windowInSeconds, int frequencyInSeconds)
7 {
8
9 long delta = (long)((TimeSpan)(timeWithWindow - time)).TotalSeconds % frequencyInSeconds;
10
11 delta = delta > windowInSeconds ? frequencyInSeconds - delta : delta;
12
13 return Math.Abs(delta) < windowInSeconds;
14
15 }
16
17 public static void Demo(System.Windows.Controls.TextBlock outputBlock)
18 {
19 int window = 10;
20 int freq = 60 * 60 * 2; // 2 hours;
21
22 DateTime d1 = DateTime.Now;
23
24 DateTime d2 = d1.AddSeconds(2 * window);
25 DateTime d3 = d1.AddSeconds(-2 * window);
26 DateTime d4 = d1.AddSeconds(window / 2);
27 DateTime d5 = d1.AddSeconds(-window / 2);
28
29 DateTime d6 = (d1.AddHours(2)).AddSeconds(2 * window);
30 DateTime d7 = (d1.AddHours(2)).AddSeconds(-2 * window);
31 DateTime d8 = (d1.AddHours(2)).AddSeconds(window / 2);
32 DateTime d9 = (d1.AddHours(2)).AddSeconds(-window / 2);
33
34 outputBlock.Text += String.Format("d1 ~= d1 [true]: " + RoughlyEquals(d1, d1, window, freq)) + "\n";
35 outputBlock.Text += String.Format("d1 ~= d2 [false]: " + RoughlyEquals(d1, d2, window, freq)) + "\n";
36 outputBlock.Text += String.Format("d1 ~= d3 [false]: " + RoughlyEquals(d1, d3, window, freq)) + "\n";
37 outputBlock.Text += String.Format("d1 ~= d4 [true]: " + RoughlyEquals(d1, d4, window, freq)) + "\n";
38 outputBlock.Text += String.Format("d1 ~= d5 [true]: " + RoughlyEquals(d1, d5, window, freq)) + "\n";
39
40 outputBlock.Text += String.Format("d1 ~= d6 [false]: " + RoughlyEquals(d1, d6, window, freq)) + "\n";
41 outputBlock.Text += String.Format("d1 ~= d7 [false]: " + RoughlyEquals(d1, d7, window, freq)) + "\n";
42 outputBlock.Text += String.Format("d1 ~= d8 [true]: " + RoughlyEquals(d1, d8, window, freq)) + "\n";
43 outputBlock.Text += String.Format("d1 ~= d9 [true]: " + RoughlyEquals(d1, d9, window, freq)) + "\n";
44
45
46 }
47}
48