我有 2 个 Web 应用程序,其中 1 个在云上是“主”,我需要将第二个 Web 应用程序“子”中的日期与之匹配。
Master(第一个网络应用程序,云)在 IST、亚洲/加尔各答显示日期,它从位于 EST 时区的 sql 机器读取。
child (第二个网络应用程序)从 Elasticsearch 读取它的数据,其中 java 馈送器获取 sql 数据并将其按原样推送到 Elasticsearch,无需任何转换。
当我尝试在我的网络应用程序(子)中读取此 Elasticsearch 数据时
...
{
"_index": "log_event_2016-05-05",
"_type": "log_event",
"_id": "65708004",
"_score": null,
"_source": {
"task_name": "kn_cvs_test",
"task_start_time": "2016-05-05T19:05:05.000-07:00",
"task_end_time": "2016-05-05T19:05:06.000-07:00",
"started_by": "Schedule \"10Minutes\"",
"log_datetime": 1462475106000,
"dw_insert_dt": "2016-05-05T16:40:54.000-07:00"
},
"sort": [
1462475106000
]
}, {
"_index": "log_event_2016-05-05",
"_type": "log_event",
"_id": "65708005",
"_score": null,
"_source": {
"task_name": "kn_cvs_test",
"task_start_time": "2016-05-05T18:55:08.000-07:00",
"task_end_time": "2016-05-05T18:55:11.000-07:00",
"started_by": "Schedule \"10Minutes\"",
"log_datetime": 1462474511000,
"dw_insert_dt": "2016-05-05T16:40:54.000-07:00"
},
"sort": [
1462474511000
]
}
...
我的 webapp 和云中的日期不匹配。如果我错了,请纠正我。由于 Sql 在 EST“America/New_York”中存储日期,Momentjs 应该首先读取 EST 中的 data = 1462475106000
,然后应用用户时区,即 IST,“Asia/Kolkata”。这是正确的吗?
//Timestamp column in table
//data = 1462475106000
$scope.getMeData = function(data) {
var dFormat = "YYYY-MM-DD hh:mm:ss A";
moment.tz.setDefault("America/New_York");
return moment.tz(data, "Asia/Kolkata").format(dFormat);
}
注意:1462475106000 是两个表中的第一个条目
我正在张贴 plunker here . 请帮我弄清楚可能出了什么问题,以及如何在两个网络应用程序中匹配日期(以云为引用)。
更新
Java feeder 运行一个 sql 查询来获取所有需要的列。以下是 log_datetime
的获取方式。这是正确的获取方式吗?
(task_end_time - to_date('1-1-1970 00:00:00','MM-DD-YYYY HH24:Mi:SS'))*24*3600*1000 AS "log_datetime"
所以我假设当它获取数据时不考虑夏令时信息,我也错过了这个信息。所以在 UI 方面,我将检查 isDST()并根据它执行 +5:00 小时或 +4:00 小时,因为 sql 中的日期存储在 America/New_York
中。 Plunker with UI fix
最佳答案
在任何时间任何地方都只有一个 Epoch 时间。这是一个绝对值。
A value that approximates the number of seconds that have elapsed since the Epoch. A Coordinated Universal Time name (specified in terms of seconds (tm_sec), minutes (tm_min), hours (tm_hour), days since January 1 of the year (tm_yday), and calendar year minus 1900 (tm_year)) is related to a time represented as seconds since the Epoch, according to the expression below.
引用 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_15
纪元时间是从 01-01-1970 00:00:00 UTC
开始计算的。这是一个绝对的瞬间,它与时区无关,因为时区 UTC
是在纪元的定义中。
每当您看到一个日期数字(例如您的示例 1462475106000
)时,都应该假设它是 UTC/GMT
。这不是时区特定值。由于时间是基于 Unix 的数字,根据纪元定义,它是自纪元以来耗时(UTC),使其成为绝对时间。
(01-01-1970 00:00:00 UTC)(epoch) + 1462475106000 = Time in UTC
字符串中的日期完全是另一回事。它应该包括带有日期部分的时区偏移量。日期部分将被视为时区特定值。向其添加时区偏移量会将其转换为 UTC 中的绝对值。没有时区信息,字符串日期没有绝对值(时间点)。
2016-05-05T18:55:08.000-07:00 = (2016-05-05T18:55:08.000) + (07:00 hrs) UTC
or
date + timezone offset = date - offset hrs UTC
数据库不在任何时区中存储日期。它们存储绝对 Unix 时间值。设置数据库中的时区设置,以便以该时区格式显示字符串查询的输出。此设置仅指定输出日期格式而不是值。由于该值是绝对值,因此与时区无关。
此设置还有助于数据库确定用户在错过时区偏移量时插入的日期值的时区。如果用户尝试在没有时区的日期列中插入字符串,数据库将尝试将该字符串默认为数据库时区设置。
所以 1462475106000
是 UTC
中的值,因为它是 Unix 时间。它不在 EST
中。
如果您需要使用 EST
格式的日期,则使用字符串格式的日期而不是数字格式,因为数字格式始终是 UTC
。
moment.tz.setDefault("America/New_York");//sets the output date format in EST
上面的代码不会有任何效果,因为它被 moment.tz(data, "Asia/Kolkata")
覆盖了
现在考虑第一个屏幕截图中的第一个条目。
2016-05-06T04:35:06.000+5:30 (IST) = 2016-05-05T11:05:06.000-00:00 (UTC)
与第二张截图相比,由于两者之间的时差为 4 小时,如果两者的绝对时间值相同,则第二张应该在 +01:30
时区。
2016-05-06T12:35:06.000+1:30 = 2016-05-05T11:05:06.000-00:00 (UTC)
但是在 child 身上的值(value)是
2016-05-05T19:05:06.000-07:00 = 2016-05-06T02:05:06.000-00:00 (UTC)
这与上面两个值不同。有趣的是,当添加 IST
偏移量 +05:30
时,只有子项中的日期部分 2016-05-05T19:05:06.000
会变成第二张截图中的日期部分。
2016-05-06T12:35:06.00 - 2016-05-05T19:05:06.000 = 5:30 (IST offset)
将您的 Java 馈线代码留给 ElasticSearch
可能是这里的罪魁祸首。
它没有将正确的日期-时区组合写入 ElasticSearch。尝试使用重载方法 getDate()
getDate(int columnIndex, Calendar cal)
在 JDBC 中。
有时 JDBC 驱动程序会丢失时区信息,导致日期存储在默认数据库时区中,使用 Calendar
可以解决这个问题。
写日期也是如此。
void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException
关于javascript - 需要读取某个时区的纪元时间,然后将其转换为用户时区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37067136/