GMT UTC CST ISO 时间戳等的含义、区别及在Java中的处理

详情见两篇文章:

GMT UTC CST ISO 夏令时 时间戳,都是些什么鬼?

彻底弄透Java处理GMT/UTC日期时间

更多:日期时间系列

另外,关于世界时UT(GMT)、国际原子时TAI、协调世界时UTC、授时中心、时间服务器及时间同步、墙上时间、单调时间 等的科普可参阅文章:计算机时间到底是怎么来的

 

文章简单总结如下

 

GMT时间(或称UT时间):

概念:格林尼治时间(Greenwich Mean Time,GMTT)、世界标准时间(Universal Time,UT),是指位于英国伦敦郊区的【皇家格林尼治天文台】的标准时间,是本初子午线上的地方时,是0时区的区时。

表示:GMT本地时间 = 0时区时间(即GMT标准时间) + 时区差,如:若现在GMT时间为 15:00,则北京时间(东八区)为同日的 23:00、纽约时间(西五区)为同日的 10:00。

其他:所有HTTP日期/时间戳都必须用格林威治标准时间(GMT)表示,没有例外。对于HTTP来说,GMT完全等于UTC(协调世界时)。

 

UTC时间:

概念:世界协调时间(Universal Time Coordinated,UTC)。它是以国际原子时(International Atomic Time,TAI,来自法国名字temps atomique International)作为计量单位的时间,计算结果极其严谨和精密。它比GMT时间更来得精准,误差值必须保持在0.9秒以内,倘若大于0.9秒就会通过闰秒来“解决”。1979年12月初内瓦举行的世界无线电行政大会通过决议,确定用“世界协调时间(UTC时间)”取代“格林威治时间(GMT时间)”,作为无线电通信领域内的国际标准时间

表示:UTC本地时间 = UTC标准时间 拼上 时间偏移量,偏移量有 ±[hh]:[mm]、±[hh][mm]、±[hh] 三种格式,如:若现在UTC时间是 10:30z(z表示偏移量=0,不可省略),则北京时间为 10:30 +0800、纽约时间为 10:30 -0500,分别表示同日下午6点半、同日上午五点半。

其他:

UTC时间里没有时区的概念,只有偏移量的概念,时间日期联盟组织对世界上主要的国家/地区定义了偏移量并给各偏移量取了对应的Time zone name(列表见:Time Zones)。

从效果上看,UTC标准时间恰好与GMT标准时间一样;

GMT本地时间是由时区换算得到的、UCT本地时间是由附上偏移量得到的,两者有很大的相似性,但由于时区只有24个,因此GMT本地时间相比于GMT标准时间有24种情况、而UTC本地时间中偏移量有无数个故有无数种情况。

由于有的国家在一年中会采用夏令时、冬令时两种计时制,故一个国家可能在不同的日期时有不同的偏移量,因此在使用 Java 中日期时间处理的JDK时最好通过zone name(类名为 java.name.ZoneId,值如 "Asia/Shanghai")得到偏移量而非写死偏移量值,前者内部会自动处理有不同偏移量值的情况(java.time.zone.ZoneRules)、在当前日期得到对应的正确偏移值。详情参阅上述第二篇文章。

 

日期/时间模板:

格式化的模式由指定的字符串组成,未加引号的大写/小写字母(A-Z a-z)代表特定模式,用来表示模式含义,若想原样输出可以用单引号''包起来,除了英文字母其它均不解释原样输出/匹配。

 

 

Java中处理时间、日期:(提倡弃用老旧的 Date,拥抱JSR 310的实现 java.time

java.util.Date及其子类java.sql.Date历史最久、被使用最广,但其有诸多缺点(见上述第二篇文章):

定义并不一致,在java.util和java.sql包中都有Date类,且对它进行格式化/解析类又跑到 java.text.SimpleDateFormat 去了;
java.util.Date 等类在建模日期的设计上行为不一致,缺陷明显。包括易变性、糟糕的偏移值、默认值、命名等等;
java.util.Date 同时包含日期和时间,而其子类 java.sql.Date 却仅包含日期;
国际化支持得并不是好,比如跨时区操作、夏令时等等;

从JDK 8开始引入了全新的JSR 310日期时间库(JSR-310源于库 joda-time 打造)解决了上面提到的所有问题,JSR 310日期/时间 所有的 API都在java.time这个包内:

 关键概念/类ZoneId、ZoneOffset、Instant、LocalDateTime、OffsetDateTime、ZonedDateTime、DateTimeFormatter 等,具体参阅上述第二篇文章。使用示例如下:

 1         // 获取ZoneId
 2         System.out.println(ZoneId.getAvailableZoneIds());// [Asia/Aden, America/Cuiaba, ..., Europe/Monaco]
 3         System.out.println(ZoneId.systemDefault());// Asia/Shanghai
 4         System.out.println(ZoneId.of("Asia/Shanghai"));// Asia/Shanghai
 5 //        System.out.println(ZoneId.of("Asia/xxx"));// 报错:java.time.zone.ZoneRulesException: Unknown time-zone ID: Asia/xxx
 6         System.out.println(ZoneId.ofOffset("UTC", ZoneOffset.of("+8")));// UTC+08:00
 7         System.out.println(ZoneId.ofOffset("UTC", ZoneOffset.of("Z")));// UTC
 8 
 9         System.out.println(ZoneId.from(ZonedDateTime.now()));// Asia/Shanghai
10         System.out.println(ZoneId.from(ZoneOffset.of("+8")));// +08:00
11 
12 //        System.out.println(ZoneId.from(LocalDateTime.now()));// 只接受带时区的类型,LocalXXX不行,故报错:java.time.DateTimeException: Unable to obtain ZoneId from TemporalAccessor:
13 //        System.out.println(ZoneId.from(LocalDate.now()));// 只接受带时区的类型,LocalXXX不行,故报错:java.time.DateTimeException: Unable to obtain ZoneId from TemporalAccessor:
14         System.out.println();
15 
16         // 获取ZoneOffset
17         System.out.println(ZoneOffset.MIN);// -18:00
18         System.out.println(ZoneOffset.MAX);// +18:00
19         System.out.println(ZoneOffset.UTC);// Z
20 //        System.out.println(ZoneOffset.of("+20"));//报错:java.time.DateTimeException: Zone offset hours not in valid range: value 20 is not in the range -18 to 18
21 
22         System.out.println(ZoneOffset.ofHours(8));// +08:00
23         System.out.println(ZoneOffset.ofHoursMinutes(8, 8));// +08:08
24         System.out.println(ZoneOffset.ofHoursMinutesSeconds(8, 8, 8));// +08:08:08
25         System.out.println(ZoneOffset.ofHours(-5));// -05:00
26         System.out.println(ZoneOffset.ofTotalSeconds(8 * 60 * 60));// +08:00
27         System.out.println();
28 
29         // 获取本地日期/时间,不带时区。LocalTime
30         System.out.println(LocalDate.now());// 2021-03-01
31         System.out.println(LocalTime.now());// 18:03:24.174
32         System.out.println(LocalDateTime.now());// 2021-03-01T18:03:24.174
33         System.out.println();
34 
35         // 获取本地日期/时间,带时区。ZonedDateTime、OffsetDateTime
36         System.out.println(ZonedDateTime.now()); // 2021-03-01T18:03:24.175+08:00[Asia/Shanghai]
37         System.out.println(ZonedDateTime.now(ZoneId.of("America/New_York"))); // 2021-03-01T05:03:24.203-05:00[America/New_York]
38         System.out.println(ZonedDateTime.now(Clock.systemUTC())); // 2021-03-01T10:03:24.206Z
39 
40         System.out.println(OffsetDateTime.now()); // 2021-03-01T18:03:24.208+08:00
41         System.out.println(OffsetDateTime.now(ZoneId.of("America/New_York"))); // 2021-03-01T05:03:24.208-05:00
42         System.out.println(OffsetDateTime.now(Clock.systemUTC())); // 2021-03-01T10:03:24.208Z
43         System.out.println();
44 
45         // 解析字符串日期或时间,分为带时区与不带时间的两种。LocalTime、ZonedDateTime、OffsetDateTime
46         System.out.println(LocalDateTime.parse("2021-05-05T18:00"));// 2021-05-05T18:00
47         System.out.println(LocalDateTime.parse("2021-05-05T18:00").atOffset(ZoneOffset.ofHours(8)));// 2021-05-05T18:00+08:00
48 
49         System.out.println(OffsetDateTime.parse("2021-05-05T18:00-04:00"));// 2021-05-05T18:00-04:00
50         System.out.println(ZonedDateTime.parse("2021-05-05T18:00-05:00[America/New_York]"));// 2021-05-05T18:00-04:00[America/New_York]
51         System.out.println();
52 
53         // JSR310对日期时间的格式化/解析。java.time.format.DateTimeFormatter,线程安全
54         System.out.println(DateTimeFormatter.ISO_LOCAL_DATE.format(LocalDate.now()));// 2021-03-01
55         System.out.println(DateTimeFormatter.ISO_LOCAL_TIME.format(LocalTime.now()));// 18:17:15.614
56         System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now()));// 2021-03-01T18:17:15.618
57 
58         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("第Q季度 yyyy-MM-dd HH:mm:ss", Locale.US);
59         System.out.println(formatter.format(LocalDateTime.now()));// 第1季度 2021-03-01 18:19:19
60         System.out.println(formatter.parse("第1季度 2021-03-01 18:19:19", LocalDateTime::from));// 2021-03-01T18:19:19
61         System.out.println(LocalDateTime.parse("第1季度 2021-03-01 18:19:19", formatter));// 2021-03-01T18:19:19
JSR310 API Demo

需要注意的是,OffsetDateTime、ZonedDateTime的输出中时间是本地时间(即 ISO8601 时间格式,如 2021-03-01T18:03:24.208+08:00)而不是前面说的UTC时间的表示格式(UTC标准时间 + 偏移量),也就是说这里的18:03是加了偏移量后的时间而非0时区的时间。实际上,从它们的toString方法就可以看出:

  1 package com.marchon.learning.pice;
  2 
  3 import java.time.Clock;
  4 import java.time.Duration;
  5 import java.time.LocalDate;
  6 import java.time.LocalDateTime;
  7 import java.time.LocalTime;
  8 import java.time.OffsetDateTime;
  9 import java.time.Period;
 10 import java.time.ZoneId;
 11 import java.time.ZoneOffset;
 12 import java.time.ZonedDateTime;
 13 import java.time.format.DateTimeFormatter;
 14 import java.util.Locale;
 15 
 16 public class JSR310_TimeAPI {
 17 
 18     static String zoneIdShanghai = "Asia/Shanghai";
 19     static String zoneIdNewyork = "America/New_York";
 20 
 21     public static void main(String[] args) {
 22 
 23         // 1 获取ZoneId
 24         System.err.println("== 获取ZoneId ==");
 25         System.out.println(ZoneId.getAvailableZoneIds());// [Asia/Aden, America/Cuiaba, ..., Europe/Monaco]
 26         System.out.println(ZoneId.systemDefault());// Asia/Shanghai
 27         System.out.println(ZoneId.of(zoneIdShanghai));// Asia/Shanghai
 28 //    System.out.println(ZoneId.of("Asia/xxx"));// 报错:java.time.zone.ZoneRulesException: Unknown time-zone ID: Asia/xxx
 29         System.out.println(ZoneId.ofOffset("UTC", ZoneOffset.of("+8")));// UTC+08:00
 30         System.out.println(ZoneId.ofOffset("UTC", ZoneOffset.of("Z")));// UTC
 31 
 32         System.out.println(ZoneId.from(ZonedDateTime.now()));// Asia/Shanghai
 33         System.out.println(ZoneId.from(ZoneOffset.of("+8")));// +08:00
 34 
 35 //    System.out.println(ZoneId.from(LocalDateTime.now()));// 只接受带时区的类型,LocalXXX不行,故报错:java.time.DateTimeException: Unable to obtain ZoneId from TemporalAccessor:
 36 //    System.out.println(ZoneId.from(LocalDate.now()));// 只接受带时区的类型,LocalXXX不行,故报错:java.time.DateTimeException: Unable to obtain ZoneId from TemporalAccessor:
 37         System.out.println();
 38 
 39         // 2 获取ZoneOffset
 40         System.err.println("== 获取ZoneOffset ==");
 41         System.out.println(ZoneOffset.MIN);// -18:00
 42         System.out.println(ZoneOffset.MAX);// +18:00
 43         System.out.println(ZoneOffset.UTC);// Z
 44 //    System.out.println(ZoneOffset.of("+20"));//报错:java.time.DateTimeException: Zone offset hours not in valid range: value 20 is not in the range -18 to 18
 45 
 46         System.out.println(ZoneOffset.ofHours(8));// +08:00
 47         System.out.println(ZoneOffset.ofHoursMinutes(8, 8));// +08:08
 48         System.out.println(ZoneOffset.ofHoursMinutesSeconds(8, 8, 8));// +08:08:08
 49         System.out.println(ZoneOffset.ofHours(-5));// -05:00
 50         System.out.println(ZoneOffset.ofTotalSeconds(8 * 60 * 60));// +08:00
 51         System.out.println();
 52 
 53         // 3 获取本地日期/时间,不带时区,会默认采用系统时区。LocalDate、LocalTime、LocalDateTime
 54         System.err.println("== 获取本地日期/时间,不带时区 ==");
 55         System.out.println(LocalDate.now());// 2021-03-01
 56         System.out.println(LocalTime.now());// 18:03:24.174
 57         System.out.println(LocalDateTime.now());// 2021-03-01T18:03:24.174
 58         System.out.println(LocalDateTime.of(2021, 3, 1, 10, 20));// 2021-03-01T10:20
 59         System.out.println(LocalDateTime.of(2021, 3, 1, 10, 20, 1));// 2021-03-01T10:20:01
 60         System.out.println();
 61 
 62         // 4 获取本地日期/时间,带时区。ZonedDateTime、OffsetDateTime
 63         System.err.println("== 获取本地日期/时间,带时区 ==");
 64         System.out.println(ZonedDateTime.now()); // 2021-03-01T18:03:24.175+08:00[Asia/Shanghai]
 65         System.out.println(ZonedDateTime.now(ZoneId.of(zoneIdNewyork))); // 2021-03-01T05:03:24.203-05:00[America/New_York]
 66         System.out.println(ZonedDateTime.now(Clock.systemUTC())); // 2021-03-01T10:03:24.206Z
 67         System.out.println(ZonedDateTime.of(2021, 3, 1, 10, 20, 1, 0, ZoneId.of(zoneIdNewyork)));// 2021-03-01T10:20:01-05:00[America/New_York]
 68 
 69         System.out.println(OffsetDateTime.now()); // 2021-03-01T18:03:24.208+08:00
 70         System.out.println(OffsetDateTime.now(ZoneId.of(zoneIdNewyork))); // 2021-03-01T05:03:24.208-05:00
 71         System.out.println(OffsetDateTime.now(Clock.systemUTC())); // 2021-03-01T10:03:24.208Z
 72         System.out.println(OffsetDateTime.of(2021, 3, 1, 10, 20, 1, 0, ZoneOffset.ofHours(8)));// 2021-03-01T10:20:01+08:00
 73 
 74         System.out.println();
 75 
 76         // 5 解析字符串日期或时间,分为带时区与不带时间的两种。LocalTime、ZonedDateTime、OffsetDateTime
 77         System.err.println("== 解析字符串日期或时间,分为带时区与不带时间的两种 ==");
 78         System.out.println(LocalDateTime.parse("2021-05-05T18:00"));// 2021-05-05T18:00
 79         System.out.println(LocalDateTime.parse("2021-05-05T18:00").atOffset(ZoneOffset.ofHours(8)));// 2021-05-05T18:00+08:00
 80 
 81         System.out.println(OffsetDateTime.parse("2021-05-05T18:00-04:00"));// 2021-05-05T18:00-04:00
 82         System.out.println(ZonedDateTime.parse("2021-05-05T18:00-05:00[America/New_York]"));// 2021-05-05T18:00-04:00[America/New_York]
 83         System.out.println();
 84 
 85         // 6 JSR310对日期时间的格式化/解析。java.time.format.DateTimeFormatter,线程安全
 86         System.err.println("== JSR310对日期时间的格式化/解析 ==");
 87         System.out.println(DateTimeFormatter.ISO_LOCAL_DATE.format(LocalDate.now()));// 2021-03-01
 88         System.out.println(DateTimeFormatter.ISO_LOCAL_TIME.format(LocalTime.now()));// 18:17:15.614
 89         System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now()));// 2021-03-01T18:17:15.618
 90 
 91         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("第Q季度 yyyy-MM-dd HH:mm:ss", Locale.US);
 92         System.out.println(formatter.format(LocalDateTime.now()));// 第1季度 2021-03-01 18:19:19
 93         System.out.println(formatter.parse("第1季度 2021-03-01 18:19:19", LocalDateTime::from));// 2021-03-01T18:19:19
 94         System.out.println(LocalDateTime.parse("第1季度 2021-03-01 18:19:19", formatter));// 2021-03-01T18:19:19
 95 
 96         System.out.println();
 97 
 98         // 7 计算相差的日期或时间长。Period、Duration
 99         System.err.println("== 计算相差的日期或时间长 ==");
100         LocalDateTime localDateTime = LocalDateTime.of(2021, 3, 10, 10, 20);
101         System.out.println(localDateTime);// 2021-03-10T10:20
102 
103         LocalDateTime afterLocalDateTime = localDateTime.plusMonths(1).plusDays(-3).minusHours(3);
104         System.out.println(afterLocalDateTime);// 2021-04-07T07:20
105 
106         Period period = Period.between(localDateTime.toLocalDate(), afterLocalDateTime.toLocalDate());
107         System.out.println(period.getMonths());// 0
108         System.out.println(period.getDays());// 28
109 
110         Duration duration = Duration.between(localDateTime.toLocalTime(), afterLocalDateTime.toLocalTime());
111         System.out.println(duration.toHours());// -3
112 
113         System.out.println();
114 
115         // 8日期或时间转换。LocalDateTime、OffsetDateTime、ZonedDateTime 之间
116         System.err.println("== 日期或时间转换 ==");
117 
118         localDateTime = LocalDateTime.of(2021, 3, 1, 18, 0, 0);
119         System.out.println(localDateTime);// 2021-03-01T18:00
120 
121         // 8.1 LocalDateTime to [OffsetDateTime、ZonedDateTime]
122         OffsetDateTime offsetDateTime1 = localDateTime.atOffset(ZoneOffset.ofHours(8));
123         OffsetDateTime offsetDateTime2 = OffsetDateTime.ofInstant(offsetDateTime1.toInstant(), ZoneOffset.ofHours(-5));
124         System.out.println(offsetDateTime1);// 2021-03-01T18:00+08:00
125         System.out.println(offsetDateTime2);// 2021-03-01T05:00-05:00
126 
127         ZonedDateTime zonedDateTime1 = localDateTime.atZone(ZoneId.of(zoneIdShanghai));
128         ZonedDateTime zonedDateTime2 = ZonedDateTime.ofInstant(zonedDateTime1.toInstant(), ZoneId.of(zoneIdNewyork));
129         System.out.println(zonedDateTime1);// 2021-03-01T18:00+08:00[Asia/Shanghai]
130         System.out.println(zonedDateTime2);// 2021-03-01T05:00-05:00[America/New_York]
131 
132         // 8.2 OffsetDateTime、ZonedDateTime间转换
133         System.out.println(offsetDateTime1.toZonedDateTime());// 2021-03-01T18:00+08:00
134         System.out.println(offsetDateTime1.atZoneSameInstant(ZoneId.of(zoneIdNewyork)));// 2021-03-01T05:00-05:00[America/New_York]
135         System.out.println(offsetDateTime1.atZoneSimilarLocal(ZoneId.of(zoneIdNewyork)));// 2021-03-01T18:00-05:00[America/New_York]
136 
137         System.out.println(zonedDateTime1.toOffsetDateTime());// 2021-03-01T18:00+08:00
138 
139         // 8.3 [LocalDateTime, ZonedDateTime] to LocalDateTime
140         System.out.println(offsetDateTime1.toLocalDateTime());// 2021-03-01T18:00
141         System.out.println(zonedDateTime1.toLocalDateTime());// 2021-03-01T18:00
142 
143         // 8.4 不同zone间转换
144         System.out.println(zonedDateTime1.withZoneSameInstant(ZoneId.of(zoneIdNewyork)));// 2021-03-01T05:00-05:00[America/New_York]
145         System.out.println(zonedDateTime1.withZoneSameLocal(ZoneId.of(zoneIdNewyork)));// 2021-03-01T18:00-05:00[America/New_York]
146  
147 
148     }
149 
150     public static ZoneOffset getOffsetByBjtime(LocalDateTime bjTime, String zoneIdStr) {
151 
152         ZonedDateTime bjZonedDateTime = bjTime.atZone(ZoneId.of(zoneIdShanghai));
153 
154         ZonedDateTime tarZonedDateTime = bjZonedDateTime.withZoneSameInstant(ZoneId.of(zoneIdStr));
155         System.err.println(tarZonedDateTime.toLocalDateTime());
156         System.err.println(tarZonedDateTime.toOffsetDateTime());
157         return tarZonedDateTime.getOffset();
158 //        LocalDateTime.ofInstant(LocalDateTime.now().to, ZoneId.of(zoneIdShanghai));
159 
160     }
161 }
View Code

 

几个概念间的关系:

某个瞬时值或某个时刻由 LocalDateTime + ZoneOffset 唯一确定。

OffsetDateTime、ZonedDateTime、Instant 三者都能在时间线上以纳秒精度存储一个瞬间(也可理解为某个时刻),LocalDateTime则不行;

OffsetDateTime、Instant 可用于模型的字段类型,因为它们都表示瞬间值且值是确定不可变的,所以适合网络传输或者数据库持久化。而ZonedDateTime不适合网络传输/持久化,因为同一个ZoneId在不同时候对应的ZoneOffset可能不同,因此可能表示两个瞬时值 ZonedDateTime也可,因为也带了偏移量;LocalDateTime也不可,因为其不带时区或偏移量信息从而无法表示一个确定的时刻。

LocalDateTime、OffsetDateTime、ZonedDateTime三者间的相互转换,可参阅: LocalDateTime、OffsetDateTime、ZonedDateTime相互转换 。

从效果上看,转成OffsetDateTime、ZonedDateTime类型时,结果有两种,具体示例可参阅前面的代码:

一种是:转换前后的两个时间值从字面上看是一样的但在时间流上并不是同一个时刻。如北京时间、纽约时间都是 2020-3-1 18:00:00,但两者并不是同一时刻。如 LocalDateTime#atOffset()/atZone() 等方法。

另一种是:转换前后的字面值不一样了,但在时间流上看是同一个时刻。如北京时间的 2020-3-1 18:00:00 与纽约时间的 2020-3-1 18:00:00 是同一时刻。如 LocalDateTime#ofInstant() 等方法。

上述几个新概念与JDK8之前的几个概念间的关系:可以用Instant代替 Date,LocalDateTime代替 Calendar,DateTimeFormatter 代替 SimpleDateFormat

 

 

 

以下为工作实践经验总结的内容

 =========================================================================

关于“同时”的理解

图中,横向是时间流逝的方向
  1. 斜向上,A1、A2、A3 是历史长河中的同一时刻,只不过在时间字面值表示上不一样,是不同时区下的表示。同理,B、B1、B2,C、C1 分别也是同时的。
  2. 纵向上,B、C、D 不是同时的,虽然它们字面值表示上除时区外一样。可将 B、C 分别转为同时刻下 D 时区的字面值表示,即 B2、C1,显然 B2、C1、D 不是同一时刻。
 

日期或时间的表示,三种方案

三种方案

  1. instant 值(或称 timestamp,时间戳):从 1970 年 1 月 1 日 00:00:00 UTC 开始到现在经过的秒数。是个偏移量。
    1. 例子:1641225600 ,表示北京时间 2022-01-04 00:00:00 或 纽约时间 2022-01-03 11:00:00
    2. 特点:
      1. 字面表示上,字面值是否带时区:否
      2. 含义表示上,字面值是否在不同时区下含义不同:否,字面值无歧义。同一个值,不管在哪个时区都表示历史长河中的同一时间点,也即该值对于不同时区来说是同时的。例如北京的小明和纽约的小红在通电话,此时两地都可用 1641225600 时间戳表示各自的当前时间,但此时北京时间和纽约时间分别为 2022-01-04 00:00:00、2022-01-03 11:00:00
  2. date、time、datetime 值(不带时区的)
    1. 例子: 20220104 、10:00:00、20220104 10:00:00。计算机中可以用字符串表示,对于 date 还可用整数表示
    2. 特点:
      1. 字面表示上,字面值是否带时区:否
      2. 含义表示上,字面值是否在不同时区下含义不同:是,字面值有歧义。同一个值,放在不同时区下对应历史长河中的不同时间点,也即该值对于不同时区来说不是同时的。
  3. date、time、datetime 值(带时区的)
    1. 例子:在上面基础上加上时区信息,比如 202230520 16:00:00+0800 表示东八区
    2. 特点:
      1. 字面表示上,字面值是否带时区:是
      2. 含义表示上,字面值是否在不同时区下含义不同:否,字面值无歧义。由于自身在表示上带了时区,故字面值不会被解释为其他时区。
 

使用场景的差异

在计算机内部表示上,通常用时间戳(方案 1)表示,因为它与时区无关;在与用户交互(如要给人看或给人用)时通常用另两者(方案 2、3)表示。
 

日期或时间的转换

转换的情形:有三种方案,两两间转换,故共有六种情形。分为两类:
  1. 字面值无歧义的方案间的转换(1->3、3->1),这类转换很简单,只是历史长河中同一时间点的不同字面表示而已。
  2. 字面值有歧义与无歧义方案间的转换(2<->1、2<->3),这类转换,通常要在转换时补上时区信息,在实际的转换中,如果系统中的日期或时间涉及到多种上述表示方案,则为免复杂化,尽可能以方案 1 为基准进行转换,因为它完全与时区无关。

代码示例(Python)

 1 import datetime
 2 import pytz
 3 
 4 def printInfo(date_obj):
 5     print('日期对象:', date_obj)
 6     print('时区:', date_obj.tzname(),"timestamp:", date_obj.timestamp())
 7     # 再将 datetime 对象转换为日期字符串
 8     new_date_str = date_obj.strftime(format_str)
 9     print('日期字符串:', new_date_str)
10 
11 # 定义日期字符串和格式
12 date_str = '2023-06-30 23:59:59'
13 format_str = '%Y-%m-%d %H:%M:%S'
14 print('原始日期字符串:', date_str)
15 
16 print(1 )
17 # 将日期字符串转换为 datetime 对象
18 date_obj = datetime.datetime.strptime(date_str, format_str)
19 printInfo(date_obj)
20 
21 #纵向转换:字面日期和时间值一样,但不是同时的(时间戳不同)
22 print(2 )
23 date_obj =  pytz.timezone('Australia/Sydney').localize(date_obj.replace(tzinfo=None))
24 printInfo(date_obj)
25 print( 3)
26 date_obj =  pytz.timezone('Asia/Shanghai').localize(date_obj.replace(tzinfo=None))
27 printInfo(date_obj)
28 
29 #斜向转换:字面日期和时间值不同,但是同时的(时间戳一样)
30 print(4 )
31 date_obj = date_obj.astimezone(pytz.timezone('Australia/Sydney'))
32 printInfo(date_obj)
33 print(5 )
34 date_obj = date_obj.astimezone(pytz.timezone('Asia/Shanghai'))
35 printInfo(date_obj)
36 
37 #方案 1->3->2
38 print(6)
39 open_time = 1625065200
40 open_time= datetime.datetime.fromtimestamp(open_time) .astimezone(pytz.timezone('Asia/Shanghai')) .strftime('%d/%m/%Y')
41 print(open_time)
42 
43 
44 # 以下是输出
45 原始日期字符串: 2023-06-30 23:59:59
46 1
47 日期对象: 2023-06-30 23:59:59
48 时区: None timestamp: 1688169599.0
49 日期字符串: 2023-06-30 23:59:59
50 2
51 日期对象: 2023-06-30 23:59:59+10:00
52 时区: AEST timestamp: 1688133599.0
53 日期字符串: 2023-06-30 23:59:59
54 3
55 日期对象: 2023-06-30 23:59:59+08:00
56 时区: CST timestamp: 1688140799.0
57 日期字符串: 2023-06-30 23:59:59
58 4
59 日期对象: 2023-07-01 01:59:59+10:00
60 时区: AEST timestamp: 1688140799.0
61 日期字符串: 2023-07-01 01:59:59
62 5
63 日期对象: 2023-06-30 23:59:59+08:00
64 时区: CST timestamp: 1688140799.0
65 日期字符串: 2023-06-30 23:59:59
66 6
67 30/06/2021
View Code

 

posted @ 2021-03-01 16:06  March On  阅读(2117)  评论(0编辑  收藏  举报
top last
Welcome user from
(since 2020.6.1)