关于datetime:是否可以从表示当地午夜的UTC时间计算本地日期?

Is it possible to calculate a local date from a UTC time representing a local midnight?

想象一下你在某个时区(例如America / New_York)采取当地日期,比如2016-12-28,并将该日期的开头转换为UTC(在本例中为2016-12-28T05:00:00Z)。

那么从那个UTC时间开始可以在不知道时区的情况下回到原始的本地日期吗? 所有你知道的是UTC时间代表当地的一些午夜/一天的开始。

我想在某些情况下这是可能的,例如 当偏移量相当小时,但我不确定时区接近日期线时是否会有两个可能的答案,即当两个时区具有相同的时间但是日期/偏移不同时(-10) 和+14)。

(此问题最初是在数据库中遇到的,其中本地日期错误地存储在UTC中,并且原始时区数据难以再次检索。)


在某些约束下,可以识别时区偏移(UTC-05:00),但不能识别原始时区(America/New_York)。霍华德在答案中表示,你只能列出当时偏移可能属于的可能时区。还有其他边缘情况使这个问题变得困难:

  • 您给出了一个非常明确的案例,说明如何无法确定国际日期变更线附近的抵消日期。

    • 例如,考虑2016-12-31T10:00:00Z。那可能是2016-12-31T00:00:00-10:00(可能是Pacific/Honolulu),或者可能是2017-01-01T00:00:00+14:00(可能是Pacific/Tongatapu)。

    • -10/+14-11/+13两种配对都是可能的,但地球上没有居住的地方实际上使用-12。因此,如果您的价值恰好在正午时间,那么它们可能+12,除非您正在与海上船舶打交道。

  • 您期望的时区中可能不存在本地午夜值。

    • 例如,2016-10-16T03:00:00ZAmerica/Sao_PauloAmerica/Bahia(都在巴西)的一天的开始。但是,America/Sao_Paulo的本地时间01:00,而不是00:00。由于他们的DST春季前进过渡,当天没有午夜。
  • 本地午夜值可能在您期望的时区中存在两次。

    • 例如,在America/Havana中,由于它们的DST回退转换,2016-11-06T04:00:00Z2016-11-06T05:00:00Z都具有00:00的本地时间。

因此,在一般情况下,您可以将其中大部分恢复到原始偏移量,但对于具有-10-11+13+14偏移的时区,您会有歧义,并且对于在午夜(春季)或凌晨1:00(秋季)进行夏令时转换的时区。 (请记住,北半球/南半球的春/秋季不同。)


使用这个免费的开源C ++库,我可以计算出这个问题的可能时区列表。

更新我已经重写了此代码的驱动程序,以便真正探索一整天的结果,并将其与Matt优秀答案中的具体示例进行比较。

这是代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <vector>

template <class Duration>
std::vector<date::zoned_time<std::common_type_t<Duration, std::chrono::seconds>>>
find_by_offset(date::sys_time<Duration> tp, const std::chrono::seconds& offset)
{
    using namespace std::chrono;
    using namespace date;
    std::vector<zoned_time<std::common_type_t<Duration, std::chrono::seconds>>> results;
    auto& db = get_tzdb();
    for (auto& z : db.zones)
    {
        if (z.get_info(tp).offset == offset)
            results.push_back(make_zoned(&z, tp));
    }
    return results;
}

int
main()
{
    using namespace date;
    using namespace std::chrono;
    for (auto offset = -15h; offset <= 13h; offset += 1h)
    {
        auto tp = sys_days{2016_y/12/28} + offset;
        std::cout <<"These are all the timezones it is midnight at" << format("%F %T %Z
", tp);
        auto d0 = round<days>(tp);
        auto dm1 = d0 - days{1};
        auto dp1 = d0 + days{1};
        auto v = find_by_offset(tp, dm1 - tp);
        for (auto const& zt : v)
            std::cout << format("%F %T %Z %z", zt) << zt.get_time_zone()->name() << '
';
        v = find_by_offset(tp, d0 - tp);
        for (auto const& zt : v)
            std::cout << format("%F %T %Z %z", zt) << zt.get_time_zone()->name() << '
';
        v = find_by_offset(tp, dp1 - tp);
        for (auto const& zt : v)
            std::cout << format("%F %T %Z %z", zt) << zt.get_time_zone()->name() << '
';
        std::cout << '
';
    }
}

该代码创建一个UTC时间戳和偏移对,并将其提供给find_by_offset,它遍历所有时区,并在每个时区查询该时间戳的偏移量。如果时区的偏移量与所需的偏移量匹配,则会在结果中添加zoned_time(zoned_time是时区与时间戳的配对)。

以下是2016-12-28日期可能有午夜的所有结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
These are all the timezones it is midnight at 2016-12-27 09:00:00 UTC
2016-12-27 00:00:00 AKST -0900 America/Anchorage
2016-12-27 00:00:00 AKST -0900 America/Juneau
2016-12-27 00:00:00 AKST -0900 America/Metlakatla
2016-12-27 00:00:00 AKST -0900 America/Nome
2016-12-27 00:00:00 AKST -0900 America/Sitka
2016-12-27 00:00:00 AKST -0900 America/Yakutat
2016-12-27 00:00:00 -09 -0900 Etc/GMT+9
2016-12-27 00:00:00 GAMT -0900 Pacific/Gambier

These are all the timezones it is midnight at 2016-12-27 10:00:00 UTC
2016-12-27 00:00:00 HST -1000 America/Adak
2016-12-27 00:00:00 -10 -1000 Etc/GMT+10
2016-12-27 00:00:00 HST -1000 HST
2016-12-27 00:00:00 HST -1000 Pacific/Honolulu
2016-12-27 00:00:00 CKT -1000 Pacific/Rarotonga
2016-12-27 00:00:00 TAHT -1000 Pacific/Tahiti
2016-12-28 00:00:00 +14 +1400 Etc/GMT-14
2016-12-28 00:00:00 WSDT +1400 Pacific/Apia
2016-12-28 00:00:00 LINT +1400 Pacific/Kiritimati
2016-12-28 00:00:00 +14 +1400 Pacific/Tongatapu

These are all the timezones it is midnight at 2016-12-27 11:00:00 UTC
2016-12-27 00:00:00 -11 -1100 Etc/GMT+11
2016-12-27 00:00:00 NUT -1100 Pacific/Niue
2016-12-27 00:00:00 SST -1100 Pacific/Pago_Pago
2016-12-28 00:00:00 +13 +1300 Etc/GMT-13
2016-12-28 00:00:00 NZDT +1300 Pacific/Auckland
2016-12-28 00:00:00 PHOT +1300 Pacific/Enderbury
2016-12-28 00:00:00 TKT +1300 Pacific/Fakaofo
2016-12-28 00:00:00 FJST +1300 Pacific/Fiji

These are all the timezones it is midnight at 2016-12-27 12:00:00 UTC
2016-12-27 00:00:00 -12 -1200 Etc/GMT+12
2016-12-28 00:00:00 +12 +1200 Asia/Anadyr
2016-12-28 00:00:00 +12 +1200 Asia/Kamchatka
2016-12-28 00:00:00 +12 +1200 Etc/GMT-12
2016-12-28 00:00:00 TVT +1200 Pacific/Funafuti
2016-12-28 00:00:00 MHT +1200 Pacific/Kwajalein
2016-12-28 00:00:00 MHT +1200 Pacific/Majuro
2016-12-28 00:00:00 NRT +1200 Pacific/Nauru
2016-12-28 00:00:00 GILT +1200 Pacific/Tarawa
2016-12-28 00:00:00 WAKT +1200 Pacific/Wake
2016-12-28 00:00:00 WFT +1200 Pacific/Wallis

These are all the timezones it is midnight at 2016-12-27 13:00:00 UTC
2016-12-28 00:00:00 +11 +1100 Antarctica/Casey
2016-12-28 00:00:00 MIST +1100 Antarctica/Macquarie
2016-12-28 00:00:00 +11 +1100 Asia/Magadan
2016-12-28 00:00:00 +11 +1100 Asia/Sakhalin
2016-12-28 00:00:00 +11 +1100 Asia/Srednekolymsk
2016-12-28 00:00:00 AEDT +1100 Australia/Currie
2016-12-28 00:00:00 AEDT +1100 Australia/Hobart
2016-12-28 00:00:00 LHDT +1100 Australia/Lord_Howe
2016-12-28 00:00:00 AEDT +1100 Australia/Melbourne
2016-12-28 00:00:00 AEDT +1100 Australia/Sydney
2016-12-28 00:00:00 +11 +1100 Etc/GMT-11
2016-12-28 00:00:00 BST +1100 Pacific/Bougainville
2016-12-28 00:00:00 VUT +1100 Pacific/Efate
2016-12-28 00:00:00 SBT +1100 Pacific/Guadalcanal
2016-12-28 00:00:00 KOST +1100 Pacific/Kosrae
2016-12-28 00:00:00 NFT +1100 Pacific/Norfolk
2016-12-28 00:00:00 NCT +1100 Pacific/Noumea
2016-12-28 00:00:00 PONT +1100 Pacific/Pohnpei

These are all the timezones it is midnight at 2016-12-27 14:00:00 UTC
2016-12-28 00:00:00 +10 +1000 Antarctica/DumontDUrville
2016-12-28 00:00:00 +10 +1000 Asia/Ust-Nera
2016-12-28 00:00:00 +10 +1000 Asia/Vladivostok
2016-12-28 00:00:00 AEST +1000 Australia/Brisbane
2016-12-28 00:00:00 AEST +1000 Australia/Lindeman
2016-12-28 00:00:00 +10 +1000 Etc/GMT-10
2016-12-28 00:00:00 CHUT +1000 Pacific/Chuuk
2016-12-28 00:00:00 ChST +1000 Pacific/Guam
2016-12-28 00:00:00 PGT +1000 Pacific/Port_Moresby

These are all the timezones it is midnight at 2016-12-27 15:00:00 UTC
2016-12-28 00:00:00 +09 +0900 Asia/Chita
2016-12-28 00:00:00 TLT +0900 Asia/Dili
2016-12-28 00:00:00 WIT +0900 Asia/Jayapura
2016-12-28 00:00:00 +09 +0900 Asia/Khandyga
2016-12-28 00:00:00 KST +0900 Asia/Seoul
2016-12-28 00:00:00 JST +0900 Asia/Tokyo
2016-12-28 00:00:00 +09 +0900 Asia/Yakutsk
2016-12-28 00:00:00 +09 +0900 Etc/GMT-9
2016-12-28 00:00:00 PWT +0900 Pacific/Palau

These are all the timezones it is midnight at 2016-12-27 16:00:00 UTC
2016-12-28 00:00:00 BNT +0800 Asia/Brunei
2016-12-28 00:00:00 CHOT +0800 Asia/Choibalsan
2016-12-28 00:00:00 HKT +0800 Asia/Hong_Kong
2016-12-28 00:00:00 +08 +0800 Asia/Irkutsk
2016-12-28 00:00:00 MYT +0800 Asia/Kuala_Lumpur
2016-12-28 00:00:00 MYT +0800 Asia/Kuching
2016-12-28 00:00:00 CST +0800 Asia/Macau
2016-12-28 00:00:00 WITA +0800 Asia/Makassar
2016-12-28 00:00:00 PHT +0800 Asia/Manila
2016-12-28 00:00:00 CST +0800 Asia/Shanghai
2016-12-28 00:00:00 SGT +0800 Asia/Singapore
2016-12-28 00:00:00 CST +0800 Asia/Taipei
2016-12-28 00:00:00 ULAT +0800 Asia/Ulaanbaatar
2016-12-28 00:00:00 AWST +0800 Australia/Perth
2016-12-28 00:00:00 +08 +0800 Etc/GMT-8

These are all the timezones it is midnight at 2016-12-27 17:00:00 UTC
2016-12-28 00:00:00 +07 +0700 Antarctica/Davis
2016-12-28 00:00:00 ICT +0700 Asia/Bangkok
2016-12-28 00:00:00 +07 +0700 Asia/Barnaul
2016-12-28 00:00:00 ICT +0700 Asia/Ho_Chi_Minh
2016-12-28 00:00:00 HOVT +0700 Asia/Hovd
2016-12-28 00:00:00 WIB +0700 Asia/Jakarta
2016-12-28 00:00:00 +07 +0700 Asia/Krasnoyarsk
2016-12-28 00:00:00 +07 +0700 Asia/Novokuznetsk
2016-12-28 00:00:00 +07 +0700 Asia/Novosibirsk
2016-12-28 00:00:00 WIB +0700 Asia/Pontianak
2016-12-28 00:00:00 +07 +0700 Asia/Tomsk
2016-12-28 00:00:00 +07 +0700 Etc/GMT-7
2016-12-28 00:00:00 CXT +0700 Indian/Christmas

These are all the timezones it is midnight at 2016-12-27 18:00:00 UTC
2016-12-28 00:00:00 +06 +0600 Antarctica/Vostok
2016-12-28 00:00:00 +06 +0600 Asia/Almaty
2016-12-28 00:00:00 +06 +0600 Asia/Bishkek
2016-12-28 00:00:00 BDT +0600 Asia/Dhaka
2016-12-28 00:00:00 +06 +0600 Asia/Omsk
2016-12-28 00:00:00 +06 +0600 Asia/Qyzylorda
2016-12-28 00:00:00 BTT +0600 Asia/Thimphu
2016-12-28 00:00:00 XJT +0600 Asia/Urumqi
2016-12-28 00:00:00 +06 +0600 Etc/GMT-6
2016-12-28 00:00:00 IOT +0600 Indian/Chagos

These are all the timezones it is midnight at 2016-12-27 19:00:00 UTC
2016-12-28 00:00:00 +05 +0500 Antarctica/Mawson
2016-12-28 00:00:00 +05 +0500 Asia/Aqtau
2016-12-28 00:00:00 +05 +0500 Asia/Aqtobe
2016-12-28 00:00:00 +05 +0500 Asia/Ashgabat
2016-12-28 00:00:00 +05 +0500 Asia/Atyrau
2016-12-28 00:00:00 +05 +0500 Asia/Dushanbe
2016-12-28 00:00:00 PKT +0500 Asia/Karachi
2016-12-28 00:00:00 +05 +0500 Asia/Oral
2016-12-28 00:00:00 +05 +0500 Asia/Samarkand
2016-12-28 00:00:00 +05 +0500 Asia/Tashkent
2016-12-28 00:00:00 +05 +0500 Asia/Yekaterinburg
2016-12-28 00:00:00 +05 +0500 Etc/GMT-5
2016-12-28 00:00:00 +05 +0500 Indian/Kerguelen
2016-12-28 00:00:00 MVT +0500 Indian/Maldives

These are all the timezones it is midnight at 2016-12-27 20:00:00 UTC
2016-12-28 00:00:00 +04 +0400 Asia/Baku
2016-12-28 00:00:00 GST +0400 Asia/Dubai
2016-12-28 00:00:00 +04 +0400 Asia/Tbilisi
2016-12-28 00:00:00 +04 +0400 Asia/Yerevan
2016-12-28 00:00:00 +04 +0400 Etc/GMT-4
2016-12-28 00:00:00 +04 +0400 Europe/Astrakhan
2016-12-28 00:00:00 +04 +0400 Europe/Samara
2016-12-28 00:00:00 +04 +0400 Europe/Saratov
2016-12-28 00:00:00 +04 +0400 Europe/Ulyanovsk
2016-12-28 00:00:00 SCT +0400 Indian/Mahe
2016-12-28 00:00:00 MUT +0400 Indian/Mauritius
2016-12-28 00:00:00 RET +0400 Indian/Reunion

These are all the timezones it is midnight at 2016-12-27 21:00:00 UTC
2016-12-28 00:00:00 EAT +0300 Africa/Khartoum
2016-12-28 00:00:00 EAT +0300 Africa/Nairobi
2016-12-28 00:00:00 +03 +0300 Antarctica/Syowa
2016-12-28 00:00:00 AST +0300 Asia/Baghdad
2016-12-28 00:00:00 +03 +0300 Asia/Famagusta
2016-12-28 00:00:00 AST +0300 Asia/Qatar
2016-12-28 00:00:00 AST +0300 Asia/Riyadh
2016-12-28 00:00:00 +03 +0300 Etc/GMT-3
2016-12-28 00:00:00 +03 +0300 Europe/Istanbul
2016-12-28 00:00:00 +03 +0300 Europe/Kirov
2016-12-28 00:00:00 +03 +0300 Europe/Minsk
2016-12-28 00:00:00 MSK +0300 Europe/Moscow
2016-12-28 00:00:00 MSK +0300 Europe/Simferopol
2016-12-28 00:00:00 +03 +0300 Europe/Volgograd

These are all the timezones it is midnight at 2016-12-27 22:00:00 UTC
2016-12-28 00:00:00 EET +0200 Africa/Cairo
2016-12-28 00:00:00 SAST +0200 Africa/Johannesburg
2016-12-28 00:00:00 CAT +0200 Africa/Maputo
2016-12-28 00:00:00 EET +0200 Africa/Tripoli
2016-12-28 00:00:00 WAST +0200 Africa/Windhoek
2016-12-28 00:00:00 EET +0200 Asia/Amman
2016-12-28 00:00:00 EET +0200 Asia/Beirut
2016-12-28 00:00:00 EET +0200 Asia/Damascus
2016-12-28 00:00:00 EET +0200 Asia/Gaza
2016-12-28 00:00:00 EET +0200 Asia/Hebron
2016-12-28 00:00:00 IST +0200 Asia/Jerusalem
2016-12-28 00:00:00 EET +0200 Asia/Nicosia
2016-12-28 00:00:00 EET +0200 EET
2016-12-28 00:00:00 +02 +0200 Etc/GMT-2
2016-12-28 00:00:00 EET +0200 Europe/Athens
2016-12-28 00:00:00 EET +0200 Europe/Bucharest
2016-12-28 00:00:00 EET +0200 Europe/Chisinau
2016-12-28 00:00:00 EET +0200 Europe/Helsinki
2016-12-28 00:00:00 EET +0200 Europe/Kaliningrad
2016-12-28 00:00:00 EET +0200 Europe/Kiev
2016-12-28 00:00:00 EET +0200 Europe/Riga
2016-12-28 00:00:00 EET +0200 Europe/Sofia
2016-12-28 00:00:00 EET +0200 Europe/Tallinn
2016-12-28 00:00:00 EET +0200 Europe/Uzhgorod
2016-12-28 00:00:00 EET +0200 Europe/Vilnius
2016-12-28 00:00:00 EET +0200 Europe/Zaporozhye

These are all the timezones it is midnight at 2016-12-27 23:00:00 UTC
2016-12-28 00:00:00 CET +0100 Africa/Algiers
2016-12-28 00:00:00 CET +0100 Africa/Ceuta
2016-12-28 00:00:00 WAT +0100 Africa/Lagos
2016-12-28 00:00:00 WAT +0100 Africa/Ndjamena
2016-12-28 00:00:00 CET +0100 Africa/Tunis
2016-12-28 00:00:00 CET +0100 CET
2016-12-28 00:00:00 +01 +0100 Etc/GMT-1
2016-12-28 00:00:00 CET +0100 Europe/Amsterdam
2016-12-28 00:00:00 CET +0100 Europe/Andorra
2016-12-28 00:00:00 CET +0100 Europe/Belgrade
2016-12-28 00:00:00 CET +0100 Europe/Berlin
2016-12-28 00:00:00 CET +0100 Europe/Brussels
2016-12-28 00:00:00 CET +0100 Europe/Budapest
2016-12-28 00:00:00 CET +0100 Europe/Copenhagen
2016-12-28 00:00:00 CET +0100 Europe/Gibraltar
2016-12-28 00:00:00 CET +0100 Europe/Luxembourg
2016-12-28 00:00:00 CET +0100 Europe/Madrid
2016-12-28 00:00:00 CET +0100 Europe/Malta
2016-12-28 00:00:00 CET +0100 Europe/Monaco
2016-12-28 00:00:00 CET +0100 Europe/Oslo
2016-12-28 00:00:00 CET +0100 Europe/Paris
2016-12-28 00:00:00 CET +0100 Europe/Prague
2016-12-28 00:00:00 CET +0100 Europe/Rome
2016-12-28 00:00:00 CET +0100 Europe/Stockholm
2016-12-28 00:00:00 CET +0100 Europe/Tirane
2016-12-28 00:00:00 CET +0100 Europe/Vienna
2016-12-28 00:00:00 CET +0100 Europe/Warsaw
2016-12-28 00:00:00 CET +0100 Europe/Zurich
2016-12-28 00:00:00 MET +0100 MET

These are all the timezones it is midnight at 2016-12-28 00:00:00 UTC
2016-12-28 00:00:00 GMT +0000 Africa/Abidjan
2016-12-28 00:00:00 GMT +0000 Africa/Accra
2016-12-28 00:00:00 GMT +0000 Africa/Bissau
2016-12-28 00:00:00 WET +0000 Africa/Casablanca
2016-12-28 00:00:00 WET +0000 Africa/El_Aaiun
2016-12-28 00:00:00 GMT +0000 Africa/Monrovia
2016-12-28 00:00:00 GMT +0000 America/Danmarkshavn
2016-12-28 00:00:00 +00 +0000 Antarctica/Troll
2016-12-28 00:00:00 WET +0000 Atlantic/Canary
2016-12-28 00:00:00 WET +0000 Atlantic/Faroe
2016-12-28 00:00:00 WET +0000 Atlantic/Madeira
2016-12-28 00:00:00 GMT +0000 Atlantic/Reykjavik
2016-12-28 00:00:00 GMT +0000 Etc/GMT
2016-12-28 00:00:00 UCT +0000 Etc/UCT
2016-12-28 00:00:00 UTC +0000 Etc/UTC
2016-12-28 00:00:00 GMT +0000 Europe/Dublin
2016-12-28 00:00:00 WET +0000 Europe/Lisbon
2016-12-28 00:00:00 GMT +0000 Europe/London
2016-12-28 00:00:00 WET +0000 WET

These are all the timezones it is midnight at 2016-12-28 01:00:00 UTC
2016-12-28 00:00:00 EGT -0100 America/Scoresbysund
2016-12-28 00:00:00 AZOT -0100 Atlantic/Azores
2016-12-28 00:00:00 CVT -0100 Atlantic/Cape_Verde
2016-12-28 00:00:00 -01 -0100 Etc/GMT+1

These are all the timezones it is midnight at 2016-12-28 02:00:00 UTC
2016-12-28 00:00:00 FNT -0200 America/Noronha
2016-12-28 00:00:00 BRST -0200 America/Sao_Paulo
2016-12-28 00:00:00 GST -0200 Atlantic/South_Georgia
2016-12-28 00:00:00 -02 -0200 Etc/GMT+2

These are all the timezones it is midnight at 2016-12-28 03:00:00 UTC
2016-12-28 00:00:00 BRT -0300 America/Araguaina
2016-12-28 00:00:00 ART -0300 America/Argentina/Buenos_Aires
2016-12-28 00:00:00 ART -0300 America/Argentina/Catamarca
2016-12-28 00:00:00 ART -0300 America/Argentina/Cordoba
2016-12-28 00:00:00 ART -0300 America/Argentina/Jujuy
2016-12-28 00:00:00 ART -0300 America/Argentina/La_Rioja
2016-12-28 00:00:00 ART -0300 America/Argentina/Mendoza
2016-12-28 00:00:00 ART -0300 America/Argentina/Rio_Gallegos
2016-12-28 00:00:00 ART -0300 America/Argentina/Salta
2016-12-28 00:00:00 ART -0300 America/Argentina/San_Juan
2016-12-28 00:00:00 ART -0300 America/Argentina/San_Luis
2016-12-28 00:00:00 ART -0300 America/Argentina/Tucuman
2016-12-28 00:00:00 ART -0300 America/Argentina/Ushuaia
2016-12-28 00:00:00 PYST -0300 America/Asuncion
2016-12-28 00:00:00 BRT -0300 America/Bahia
2016-12-28 00:00:00 BRT -0300 America/Belem
2016-12-28 00:00:00 AMST -0300 America/Campo_Grande
2016-12-28 00:00:00 GFT -0300 America/Cayenne
2016-12-28 00:00:00 AMST -0300 America/Cuiaba
2016-12-28 00:00:00 BRT -0300 America/Fortaleza
2016-12-28 00:00:00 WGT -0300 America/Godthab
2016-12-28 00:00:00 BRT -0300 America/Maceio
2016-12-28 00:00:00 PMST -0300 America/Miquelon
2016-12-28 00:00:00 UYT -0300 America/Montevideo
2016-12-28 00:00:00 SRT -0300 America/Paramaribo
2016-12-28 00:00:00 BRT -0300 America/Recife
2016-12-28 00:00:00 BRT -0300 America/Santarem
2016-12-28 00:00:00 CLST -0300 America/Santiago
2016-12-28 00:00:00 CLST -0300 Antarctica/Palmer
2016-12-28 00:00:00 -03 -0300 Antarctica/Rothera
2016-12-28 00:00:00 FKST -0300 Atlantic/Stanley
2016-12-28 00:00:00 -03 -0300 Etc/GMT+3

These are all the timezones it is midnight at 2016-12-28 04:00:00 UTC
2016-12-28 00:00:00 AST -0400 America/Barbados
2016-12-28 00:00:00 AST -0400 America/Blanc-Sablon
2016-12-28 00:00:00 AMT -0400 America/Boa_Vista
2016-12-28 00:00:00 VET -0400 America/Caracas
2016-12-28 00:00:00 AST -0400 America/Curacao
2016-12-28 00:00:00 AST -0400 America/Glace_Bay
2016-12-28 00:00:00 AST -0400 America/Goose_Bay
2016-12-28 00:00:00 AST -0400 America/Grand_Turk
2016-12-28 00:00:00 GYT -0400 America/Guyana
2016-12-28 00:00:00 AST -0400 America/Halifax
2016-12-28 00:00:00 BOT -0400 America/La_Paz
2016-12-28 00:00:00 AMT -0400 America/Manaus
2016-12-28 00:00:00 AST -0400 America/Martinique
2016-12-28 00:00:00 AST -0400 America/Moncton
2016-12-28 00:00:00 AST -0400 America/Port_of_Spain
2016-12-28 00:00:00 AMT -0400 America/Porto_Velho
2016-12-28 00:00:00 AST -0400 America/Puerto_Rico
2016-12-28 00:00:00 AST -0400 America/Santo_Domingo
2016-12-28 00:00:00 AST -0400 America/Thule
2016-12-28 00:00:00 AST -0400 Atlantic/Bermuda
2016-12-28 00:00:00 -04 -0400 Etc/GMT+4

These are all the timezones it is midnight at 2016-12-28 05:00:00 UTC
2016-12-28 00:00:00 EST -0500 America/Atikokan
2016-12-28 00:00:00 COT -0500 America/Bogota
2016-12-28 00:00:00 EST -0500 America/Cancun
2016-12-28 00:00:00 EST -0500 America/Detroit
2016-12-28 00:00:00 ACT -0500 America/Eirunepe
2016-12-28 00:00:00 ECT -0500 America/Guayaquil
2016-12-28 00:00:00 CST -0500 America/Havana
2016-12-28 00:00:00 EST -0500 America/Indiana/Indianapolis
2016-12-28 00:00:00 EST -0500 America/Indiana/Marengo
2016-12-28 00:00:00 EST -0500 America/Indiana/Petersburg
2016-12-28 00:00:00 EST -0500 America/Indiana/Vevay
2016-12-28 00:00:00 EST -0500 America/Indiana/Vincennes
2016-12-28 00:00:00 EST -0500 America/Indiana/Winamac
2016-12-28 00:00:00 EST -0500 America/Iqaluit
2016-12-28 00:00:00 EST -0500 America/Jamaica
2016-12-28 00:00:00 EST -0500 America/Kentucky/Louisville
2016-12-28 00:00:00 EST -0500 America/Kentucky/Monticello
2016-12-28 00:00:00 PET -0500 America/Lima
2016-12-28 00:00:00 EST -0500 America/Nassau
2016-12-28 00:00:00 EST -0500 America/New_York
2016-12-28 00:00:00 EST -0500 America/Nipigon
2016-12-28 00:00:00 EST -0500 America/Panama
2016-12-28 00:00:00 EST -0500 America/Pangnirtung
2016-12-28 00:00:00 EST -0500 America/Port-au-Prince
2016-12-28 00:00:00 ACT -0500 America/Rio_Branco
2016-12-28 00:00:00 EST -0500 America/Thunder_Bay
2016-12-28 00:00:00 EST -0500 America/Toronto
2016-12-28 00:00:00 EST -0500 EST
2016-12-28 00:00:00 EST -0500 EST5EDT
2016-12-28 00:00:00 -05 -0500 Etc/GMT+5
2016-12-28 00:00:00 EASST -0500 Pacific/Easter

These are all the timezones it is midnight at 2016-12-28 06:00:00 UTC
2016-12-28 00:00:00 CST -0600 America/Bahia_Banderas
2016-12-28 00:00:00 CST -0600 America/Belize
2016-12-28 00:00:00 CST -0600 America/Chicago
2016-12-28 00:00:00 CST -0600 America/Costa_Rica
2016-12-28 00:00:00 CST -0600 America/El_Salvador
2016-12-28 00:00:00 CST -0600 America/Guatemala
2016-12-28 00:00:00 CST -0600 America/Indiana/Knox
2016-12-28 00:00:00 CST -0600 America/Indiana/Tell_City
2016-12-28 00:00:00 CST -0600 America/Managua
2016-12-28 00:00:00 CST -0600 America/Matamoros
2016-12-28 00:00:00 CST -0600 America/Menominee
2016-12-28 00:00:00 CST -0600 America/Merida
2016-12-28 00:00:00 CST -0600 America/Mexico_City
2016-12-28 00:00:00 CST -0600 America/Monterrey
2016-12-28 00:00:00 CST -0600 America/North_Dakota/Beulah
2016-12-28 00:00:00 CST -0600 America/North_Dakota/Center
2016-12-28 00:00:00 CST -0600 America/North_Dakota/New_Salem
2016-12-28 00:00:00 CST -0600 America/Rainy_River
2016-12-28 00:00:00 CST -0600 America/Rankin_Inlet
2016-12-28 00:00:00 CST -0600 America/Regina
2016-12-28 00:00:00 CST -0600 America/Resolute
2016-12-28 00:00:00 CST -0600 America/Swift_Current
2016-12-28 00:00:00 CST -0600 America/Tegucigalpa
2016-12-28 00:00:00 CST -0600 America/Winnipeg
2016-12-28 00:00:00 CST -0600 CST6CDT
2016-12-28 00:00:00 -06 -0600 Etc/GMT+6
2016-12-28 00:00:00 GALT -0600 Pacific/Galapagos

These are all the timezones it is midnight at 2016-12-28 07:00:00 UTC
2016-12-28 00:00:00 MST -0700 America/Boise
2016-12-28 00:00:00 MST -0700 America/Cambridge_Bay
2016-12-28 00:00:00 MST -0700 America/Chihuahua
2016-12-28 00:00:00 MST -0700 America/Creston
2016-12-28 00:00:00 MST -0700 America/Dawson_Creek
2016-12-28 00:00:00 MST -0700 America/Denver
2016-12-28 00:00:00 MST -0700 America/Edmonton
2016-12-28 00:00:00 MST -0700 America/Fort_Nelson
2016-12-28 00:00:00 MST -0700 America/Hermosillo
2016-12-28 00:00:00 MST -0700 America/Inuvik
2016-12-28 00:00:00 MST -0700 America/Mazatlan
2016-12-28 00:00:00 MST -0700 America/Ojinaga
2016-12-28 00:00:00 MST -0700 America/Phoenix
2016-12-28 00:00:00 MST -0700 America/Yellowknife
2016-12-28 00:00:00 -07 -0700 Etc/GMT+7
2016-12-28 00:00:00 MST -0700 MST
2016-12-28 00:00:00 MST -0700 MST7MDT

These are all the timezones it is midnight at 2016-12-28 08:00:00 UTC
2016-12-28 00:00:00 PST -0800 America/Dawson
2016-12-28 00:00:00 PST -0800 America/Los_Angeles
2016-12-28 00:00:00 PST -0800 America/Tijuana
2016-12-28 00:00:00 PST -0800 America/Vancouver
2016-12-28 00:00:00 PST -0800 America/Whitehorse
2016-12-28 00:00:00 -08 -0800 Etc/GMT+8
2016-12-28 00:00:00 PST -0800 PST8PDT
2016-12-28 00:00:00 PST -0800 Pacific/Pitcairn

These are all the timezones it is midnight at 2016-12-28 09:00:00 UTC
2016-12-28 00:00:00 AKST -0900 America/Anchorage
2016-12-28 00:00:00 AKST -0900 America/Juneau
2016-12-28 00:00:00 AKST -0900 America/Metlakatla
2016-12-28 00:00:00 AKST -0900 America/Nome
2016-12-28 00:00:00 AKST -0900 America/Sitka
2016-12-28 00:00:00 AKST -0900 America/Yakutat
2016-12-28 00:00:00 -09 -0900 Etc/GMT+9
2016-12-28 00:00:00 GAMT -0900 Pacific/Gambier

These are all the timezones it is midnight at 2016-12-28 10:00:00 UTC
2016-12-28 00:00:00 HST -1000 America/Adak
2016-12-28 00:00:00 -10 -1000 Etc/GMT+10
2016-12-28 00:00:00 HST -1000 HST
2016-12-28 00:00:00 HST -1000 Pacific/Honolulu
2016-12-28 00:00:00 CKT -1000 Pacific/Rarotonga
2016-12-28 00:00:00 TAHT -1000 Pacific/Tahiti
2016-12-29 00:00:00 +14 +1400 Etc/GMT-14
2016-12-29 00:00:00 WSDT +1400 Pacific/Apia
2016-12-29 00:00:00 LINT +1400 Pacific/Kiritimati
2016-12-29 00:00:00 +14 +1400 Pacific/Tongatapu

These are all the timezones it is midnight at 2016-12-28 11:00:00 UTC
2016-12-28 00:00:00 -11 -1100 Etc/GMT+11
2016-12-28 00:00:00 NUT -1100 Pacific/Niue
2016-12-28 00:00:00 SST -1100 Pacific/Pago_Pago
2016-12-29 00:00:00 +13 +1300 Etc/GMT-13
2016-12-29 00:00:00 NZDT +1300 Pacific/Auckland
2016-12-29 00:00:00 PHOT +1300 Pacific/Enderbury
2016-12-29 00:00:00 TKT +1300 Pacific/Fakaofo
2016-12-29 00:00:00 FJST +1300 Pacific/Fiji

These are all the timezones it is midnight at 2016-12-28 12:00:00 UTC
2016-12-28 00:00:00 -12 -1200 Etc/GMT+12
2016-12-29 00:00:00 +12 +1200 Asia/Anadyr
2016-12-29 00:00:00 +12 +1200 Asia/Kamchatka
2016-12-29 00:00:00 +12 +1200 Etc/GMT-12
2016-12-29 00:00:00 TVT +1200 Pacific/Funafuti
2016-12-29 00:00:00 MHT +1200 Pacific/Kwajalein
2016-12-29 00:00:00 MHT +1200 Pacific/Majuro
2016-12-29 00:00:00 NRT +1200 Pacific/Nauru
2016-12-29 00:00:00 GILT +1200 Pacific/Tarawa
2016-12-29 00:00:00 WAKT +1200 Pacific/Wake
2016-12-29 00:00:00 WFT +1200 Pacific/Wallis

These are all the timezones it is midnight at 2016-12-28 13:00:00 UTC
2016-12-29 00:00:00 +11 +1100 Antarctica/Casey
2016-12-29 00:00:00 MIST +1100 Antarctica/Macquarie
2016-12-29 00:00:00 +11 +1100 Asia/Magadan
2016-12-29 00:00:00 +11 +1100 Asia/Sakhalin
2016-12-29 00:00:00 +11 +1100 Asia/Srednekolymsk
2016-12-29 00:00:00 AEDT +1100 Australia/Currie
2016-12-29 00:00:00 AEDT +1100 Australia/Hobart
2016-12-29 00:00:00 LHDT +1100 Australia/Lord_Howe
2016-12-29 00:00:00 AEDT +1100 Australia/Melbourne
2016-12-29 00:00:00 AEDT +1100 Australia/Sydney
2016-12-29 00:00:00 +11 +1100 Etc/GMT-11
2016-12-29 00:00:00 BST +1100 Pacific/Bougainville
2016-12-29 00:00:00 VUT +1100 Pacific/Efate
2016-12-29 00:00:00 SBT +1100 Pacific/Guadalcanal
2016-12-29 00:00:00 KOST +1100 Pacific/Kosrae
2016-12-29 00:00:00 NFT +1100 Pacific/Norfolk
2016-12-29 00:00:00 NCT +1100 Pacific/Noumea
2016-12-29 00:00:00 PONT +1100 Pacific/Pohnpei

笔记:

  • 2016-12-28 10:00:00 UTC列出了Pacific / Honolulu和Pacific / Tongatapu的结果(以及其他几个)。

  • 这些结果列出了所有的-10/+14-11/+13配对,以及其他一些配对,但是其他几个配对仅涉及"海上"时区,例如"Etc / GMT + 12"。

  • 如果您改变要探索的节目2016-10-16 America/Sao_Paulo从未列出,虽然它列于2016-12-28,因为America/Sao_Paulo在2016-10-16没有午夜。但是你确实在2016-10-16 03:00:00 UTC(偏移-0300)下列出了America/Bahia

  • 更改程序以探索2016-11-06显示America/Havana在2016-11-06 04:00:00 UTC和2016-11-06 05:00:00 UTC下列出。

  • 在这里没有突出显示的例子中,有一个独特的时区,它对于给定的UTC时间点是午夜。可能存在这样的时区,其时区的UTC偏移不是整数小时。

啊,是的,这里有几个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
These are all the timezones it is midnight at 2016-12-27 09:30:00 UTC
2016-12-27 00:00:00 MART -0930 Pacific/Marquesas

These are all the timezones it is midnight at 2016-12-27 10:15:00 UTC
2016-12-28 00:00:00 CHADT +1345 Pacific/Chatham

These are all the timezones it is midnight at 2016-12-27 14:30:00 UTC
2016-12-28 00:00:00 ACST +0930 Australia/Darwin

These are all the timezones it is midnight at 2016-12-27 15:15:00 UTC
2016-12-28 00:00:00 ACWST +0845 Australia/Eucla

These are all the timezones it is midnight at 2016-12-27 15:30:00 UTC
2016-12-28 00:00:00 KST +0830 Asia/Pyongyang

These are all the timezones it is midnight at 2016-12-27 18:15:00 UTC
2016-12-28 00:00:00 NPT +0545 Asia/Kathmandu

These are all the timezones it is midnight at 2016-12-27 19:30:00 UTC
2016-12-28 00:00:00 AFT +0430 Asia/Kabul

These are all the timezones it is midnight at 2016-12-27 20:30:00 UTC
2016-12-28 00:00:00 IRST +0330 Asia/Tehran

These are all the timezones it is midnight at 2016-12-28 03:30:00 UTC
2016-12-28 00:00:00 NST -0330 America/St_Johns


Matt Johnson的回答是正确的。

  • 如果您确定存储在数据库中的那一刻代表某个时区的某一时刻的第一时刻,您可以获得一个日期。
  • 您可以猜测时区,但是当多个区域在此时共享与UTC的偏移时,您无法确定原始时区。

java.time

下面是一些使用现代java.time类的Java代码。

Imagine you take a local date, say 2016-12-28, in a given time zone, say America/New_York, and convert the start of that date into UTC (in this case 2016-12-28T05:00:00Z).

请注意,我们让java.time通过LocalDate::atStartOfDay方法确定一天中的第一个时刻。不要假设这一天从00:00:00开始。夏令时等异常意味着该日可能会在另一个时间开始,例如01:00:00。

1
2
3
LocalDate localDate = LocalDate.parse("2016-12-28" ) ;
ZoneId zNewYork = ZoneId.of("America/New_York" ) ;
ZonedDateTime zdtNewYork = localDate.atStartOfDay( zNewYork ) ;   // First moment of the day in that zone on that date.

通过提取Instant调整为UTC值。根据定义,Instant始终为UTC。

1
Instant instant = zdtNewYork.toInstant() ;

以类似于SQL-standard TIMESTAMP WITH TIME ZONE的类型的列存储在数据库中。

1
myPreparedStatement.setObject( … , instant ) ;

get back to the original local date without knowing the time zone?

检索。

1
Instant instant = myResultSet.getObject( … , Instant.class ) ;

现在试验每个时区。仅供参考,请参阅维基百科的区域名称列表,但该页面可能已过时。

对于每个区域,将我们的Instant(我们的UTC时刻)调整到该区域以获得ZonedDateTime对象。有些时刻,时间轴上的相同点,但不同的挂钟时间。

对于每个ZonedDateTime,仅提取日期,没有时间和没有时区。呈现LocalDate对象。要求LocalDate确定我们所考虑的时区中的当天的第一时刻(可能在00:00:00发生,也可能不发生)。这会产生另一个ZonedDateTime对象。

从第二个ZonedDateTime开始,提取Instant以调整回UTC。将此新Instant对象与原始Instant进行比较。如果他们是相同的,我们有一个打击。我们已经确定了存储在数据库中的那一刻开始一天的时区。因此,我们上面生成的LocalDate与最初在我们的数据库中不恰当地存储的日期相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
List< ZoneId > hits = new ArrayList<>() ;
LocalDate originalLocalDate = null ;
Set< String > zoneIds = ZoneId.getAvailableZoneIds() ;  // Gets the set of available zone IDs.
for( String zoneId : zoneIds ) {
    ZoneId z = ZoneId.of( zoneId ) ;                        // Get zone with that name.
    ZonedDateTime zdt = instant.atZone( z ) ;
    LocalDate ld = zdt.toLocalDate() ;                      // Extract the date-only value, dropping the time-of-day and dropping the time zone.
    ZonedDateTime startOfDay = ld.atStartOfDay( z ) ;       // Determine first moment of the day on that date in that zone.
    Instant instantOfStartOfDay = startOfDay.toInstant() ;  // Adjust back to UTC.
    boolean hit = instant.equals( instantOfStartOfDay ) ;
    if( hit ) {
        originalLocalDate = ld ;
        hits.add( z ) ;  // Collect this time zone as the zone possibly used originally.
    }
}

请参阅IdeOne.com上的此代码。

运行时,我们看到该日期的America/New_York时区的偏移量比UTC晚5个小时。您可以从此列表中看到,还有许多其他时区共享-05:00的相同偏移量。

originalLocalDate.toString(): 2016-12-28

hits.toString(): [America/Panama, America/Indiana/Petersburg, America/Eirunepe, Cuba, Etc/GMT+5, Pacific/Easter, America/Fort_Wayne, America/Havana, America/Porto_Acre, US/Michigan, America/Louisville, America/Guayaquil, America/Indiana/Vevay, America/Indiana/Vincennes, America/Indianapolis, America/Iqaluit, America/Kentucky/Louisville, EST5EDT, America/Nassau, America/Jamaica, America/Atikokan, America/Kentucky/Monticello, America/Coral_Harbour, America/Cayman, Chile/EasterIsland, America/Indiana/Indianapolis, America/Thunder_Bay, America/Indiana/Marengo, America/Bogota, SystemV/EST5, US/Eastern, Canada/Eastern, America/Port-au-Prince, America/Nipigon, Brazil/Acre, US/East-Indiana, America/Cancun, America/Lima, America/Rio_Branco, America/Detroit, Jamaica, America/Pangnirtung, America/Montreal, America/Indiana/Winamac, America/New_York, America/Toronto, SystemV/EST5EDT]

请注意,生成的区域列表可能不明显。某些区域名称是别名,其中一个区域具有多个名称。例如,旧的Asia/Calcutta现在是Asia/Kolkata

关于java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧遗留日期时间类,例如java.util.DateCalendar和&amp; SimpleDateFormat

现在处于维护模式的Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参阅Oracle教程。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。

您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

  • Java SE 8,Java SE 9,Java SE 10及更高版本

    • 内置。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小功能和修复。
  • Java SE 6和Java SE 7

    • 许多java.time功能都被反向移植到Java 6&amp; 7在ThreeTen-Backport。
  • Android的

    • 更高版本的Android捆绑java.time类的实现。
    • 对于早期的Android(<26),ThreeTenABP项目采用ThreeTen-Backport(如上所述)。请参见如何使用ThreeTenABP ....

ThreeTen-Extra项目使用其他类扩展了java.time。该项目是未来可能添加到java.time的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter等。