使用客户端的时区将字符串日期转换为Java对象(不含语言环境)

时间:2023-02-09 15:24:32

I need to create a 24hours window for a date passed by user to search result in database. The user could be in any TimeZone, the server is in PST and the database uses mongodb (UTC).

我需要为用户在数据库中搜索结果的日期创建一个24小时窗口。用户可以在任何TimeZone中,服务器在PST中,数据库使用mongodb(UTC)。

Looking for something like if user sends Wed Dec 21 2016 00:07:11 GMT+0530 (IST) then server creates a new DateTime() having same date and time (not gets converted by default to JVM's timezone)

寻找像用户发送Wed Dec 21 2016 00:07:11 GMT + 0530(IST)之类的东西,然后服务器创建一个具有相同日期和时间的新DateTime()(默认情况下不会转换为JVM的时区)

One work around I thought of is to create a Date in user's Timezone withTimeAtStartOfDay and addDays plus 1 for window.

我想到的一个解决方法是在用户的时区中使用TimeAtStartOfDay创建一个日期,并为窗口添加addDays加1。

Eg: String date = "Wed Dec 21 2016 00:07:11 GMT+0530 (IST)" convert to "2016-12-21 00:00:00.000Z" NOTE : Server is in PST, so simple date object won't work.

例如:字符串日期=“2016年12月21日星期三00:07:11 GMT + 0530(IST)”转换为“2016-12-21 00:00:00.000Z”注意:服务器在PST中,因此简单的日期对象赢了工作。

How can I create a Date object in Java with Timezone of user (i.e String date user passes to BE).

如何在Java中使用用户的时区创建Date对象(即字符串日期用户传递给BE)。

1 个解决方案

#1


1  

The server’s JVM’s current default time zone should be irrelevant to your programming. Always pass your desired/expected time zone in the optional arguments to various method calls. IMHO, those time zone arguments should be required rather than optional.

服务器的JVM当前默认时区应该与您的编程无关。始终将可选参数中的所需/预期时区传递给各种方法调用。恕我直言,那些时区参数应该是必需的而不是可选的。

I do not know or use MongoDB, but this page says you the native type for a date-time value is a a 64-bit integer that represents the number of milliseconds since the Unix epoch (Jan 1, 1970) in UTC.

我不知道或不使用MongoDB,但是这个页面说明了日期时间值的本机类型是一个64位整数,它表示自UTC时代(1970年1月1日)以来的UTC时间内的毫秒数。

A date-only value is ambiguous, having no real meaning without the context of a time zone. For any given moment, the date varies around the globe by zone. A few minutes after midnight is a new day in Paris France while still “yesterday” in Montréal Canada.

仅日期值是不明确的,没有时区的上下文没有实际意义。对于任何给定的时刻,日期在全球范围内因地区而异。午夜过后几分钟是巴黎法国新的一天,而加拿大蒙特利尔仍然是“昨天”。

So if a time zone is required, where do we get one? Ultimately, the only safe sure way is to ask the user. Prompt the user for the proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

因此,如果需要时区,我们在哪里获得一个?最终,唯一安全可靠的方法是询问用户。提示用户输入大陆/地区格式的正确时区名称,例如America / Montreal,Africa / Casablanca或Pacific / Auckland。切勿使用3-4字母缩写,例如EST或IST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

Without asking the user, you can only assume or guess. There are ways to detect via JavaScript the web-app client browser for its current default time zone. Discussed many times already on Stack Overflow, so search. But you do not know for sure that the browser zone is intended by the user making the query to you. You could assume a time zone or assume UTC, if your users are properly trained to work that way.

在不询问用户的情况下,您只能假设或猜测。有一些方法可以通过JavaScript检测Web应用程序客户端浏览器的当前默认时区。已经多次讨论Stack Overflow,所以搜索。但是您不确定浏览器区域是由用户进行查询的。如果您的用户经过适当的培训,可以采用这种方式,您可以假设时区或假设UTC。

Locale has nothing to do with time zone, only presentation when generating a String representation. Locale determines (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, and such. You can have a Asia/Kolkata time zone with Locale.CANADA_FRENCH presentation, or a Pacific/Auckland time zone with a Locale.ITALY presentation. So, locale is irrelevant to this Question.

Locale与时区无关,只与生成String表示时的表示有关。 Locale确定(a)用于翻译日期名称,月份名称等的人类语言,以及(b)决定缩写,大小写,标点符号等问题的文化规范。您可以在Locale.CANADA_FRENCH演示文稿中使用亚洲/加尔各答时区,或在Locale.ITALY演示文稿中使用太平洋/奥克兰时区。因此,语言环境与此问题无关。

Use LocalDate for the date-only portion.

将LocalDate用于仅限日期的部分。

LocalDate ld = LocalDate.of( 2016 , Month.MARCH , 23 );

Provide the time zone.

提供时区。

ZoneId z = ZoneId.of( "America/Montreal" );

Get the start of day, the first moment. Let java.time determine this, as the first moment is not always the time-of-day 00:00:00. Anomalies such as Daylight Saving Time (DST) may cause a different start time.

第一时刻开始新的一天。让java.time确定这一点,因为第一个时刻并不总是00:00:00的时间。夏令时(DST)等异常可能会导致不同的开始时间。

ZonedDateTime zdtStart = ld.atStartOfDay( z );

We need a ending time for the search query. Usually in date-time handling we use the Half-Open approach where the beginning is inclusive while the ending is exclusive. So we want the query for a single day to run up to, but not include, the first moment of the following day.

我们需要搜索查询的结束时间。通常在日期时间处理中,我们使用半开放方法,其中开头是包含性的,而结尾是独占的。因此,我们希望查询一天可以运行,但不包括第二天的第一个时刻。

ZonedDateTime zdtStop = ld.plusDays( 1 ).atStartOfDay( z );  // Or, zdtStart.plusDays( 1 )

Apparently, MondoDB needs us to translate this to a count of milliseconds since the epoch in UTC. For that, extract an Instant.

显然,MondoDB需要我们将其转换为自UTC时代以来的毫秒数。为此,提取瞬发。

Instant instantStart = zdtStart.toInstant();
Instant instantStop = zdtStop.toInstant();

From those, extract the epoch-count. This may mean data-loss! The java.time classes tracks values with a resolution of nanoseconds. Going to milliseconds may mean truncating a fine fraction of a second.

从那些,提取epoch计数。这可能意味着数据丢失! java.time类跟踪分辨率为纳秒的值。达到毫秒可能意味着截断一小段时间。

long millisStart = instantStart.toEpochMilli(); // WARNING: possible data loss.
long millisStop = instantStop.toEpochMilli(); // WARNING: possible data loss.

#1


1  

The server’s JVM’s current default time zone should be irrelevant to your programming. Always pass your desired/expected time zone in the optional arguments to various method calls. IMHO, those time zone arguments should be required rather than optional.

服务器的JVM当前默认时区应该与您的编程无关。始终将可选参数中的所需/预期时区传递给各种方法调用。恕我直言,那些时区参数应该是必需的而不是可选的。

I do not know or use MongoDB, but this page says you the native type for a date-time value is a a 64-bit integer that represents the number of milliseconds since the Unix epoch (Jan 1, 1970) in UTC.

我不知道或不使用MongoDB,但是这个页面说明了日期时间值的本机类型是一个64位整数,它表示自UTC时代(1970年1月1日)以来的UTC时间内的毫秒数。

A date-only value is ambiguous, having no real meaning without the context of a time zone. For any given moment, the date varies around the globe by zone. A few minutes after midnight is a new day in Paris France while still “yesterday” in Montréal Canada.

仅日期值是不明确的,没有时区的上下文没有实际意义。对于任何给定的时刻,日期在全球范围内因地区而异。午夜过后几分钟是巴黎法国新的一天,而加拿大蒙特利尔仍然是“昨天”。

So if a time zone is required, where do we get one? Ultimately, the only safe sure way is to ask the user. Prompt the user for the proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

因此,如果需要时区,我们在哪里获得一个?最终,唯一安全可靠的方法是询问用户。提示用户输入大陆/地区格式的正确时区名称,例如America / Montreal,Africa / Casablanca或Pacific / Auckland。切勿使用3-4字母缩写,例如EST或IST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

Without asking the user, you can only assume or guess. There are ways to detect via JavaScript the web-app client browser for its current default time zone. Discussed many times already on Stack Overflow, so search. But you do not know for sure that the browser zone is intended by the user making the query to you. You could assume a time zone or assume UTC, if your users are properly trained to work that way.

在不询问用户的情况下,您只能假设或猜测。有一些方法可以通过JavaScript检测Web应用程序客户端浏览器的当前默认时区。已经多次讨论Stack Overflow,所以搜索。但是您不确定浏览器区域是由用户进行查询的。如果您的用户经过适当的培训,可以采用这种方式,您可以假设时区或假设UTC。

Locale has nothing to do with time zone, only presentation when generating a String representation. Locale determines (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, and such. You can have a Asia/Kolkata time zone with Locale.CANADA_FRENCH presentation, or a Pacific/Auckland time zone with a Locale.ITALY presentation. So, locale is irrelevant to this Question.

Locale与时区无关,只与生成String表示时的表示有关。 Locale确定(a)用于翻译日期名称,月份名称等的人类语言,以及(b)决定缩写,大小写,标点符号等问题的文化规范。您可以在Locale.CANADA_FRENCH演示文稿中使用亚洲/加尔各答时区,或在Locale.ITALY演示文稿中使用太平洋/奥克兰时区。因此,语言环境与此问题无关。

Use LocalDate for the date-only portion.

将LocalDate用于仅限日期的部分。

LocalDate ld = LocalDate.of( 2016 , Month.MARCH , 23 );

Provide the time zone.

提供时区。

ZoneId z = ZoneId.of( "America/Montreal" );

Get the start of day, the first moment. Let java.time determine this, as the first moment is not always the time-of-day 00:00:00. Anomalies such as Daylight Saving Time (DST) may cause a different start time.

第一时刻开始新的一天。让java.time确定这一点,因为第一个时刻并不总是00:00:00的时间。夏令时(DST)等异常可能会导致不同的开始时间。

ZonedDateTime zdtStart = ld.atStartOfDay( z );

We need a ending time for the search query. Usually in date-time handling we use the Half-Open approach where the beginning is inclusive while the ending is exclusive. So we want the query for a single day to run up to, but not include, the first moment of the following day.

我们需要搜索查询的结束时间。通常在日期时间处理中,我们使用半开放方法,其中开头是包含性的,而结尾是独占的。因此,我们希望查询一天可以运行,但不包括第二天的第一个时刻。

ZonedDateTime zdtStop = ld.plusDays( 1 ).atStartOfDay( z );  // Or, zdtStart.plusDays( 1 )

Apparently, MondoDB needs us to translate this to a count of milliseconds since the epoch in UTC. For that, extract an Instant.

显然,MondoDB需要我们将其转换为自UTC时代以来的毫秒数。为此,提取瞬发。

Instant instantStart = zdtStart.toInstant();
Instant instantStop = zdtStop.toInstant();

From those, extract the epoch-count. This may mean data-loss! The java.time classes tracks values with a resolution of nanoseconds. Going to milliseconds may mean truncating a fine fraction of a second.

从那些,提取epoch计数。这可能意味着数据丢失! java.time类跟踪分辨率为纳秒的值。达到毫秒可能意味着截断一小段时间。

long millisStart = instantStart.toEpochMilli(); // WARNING: possible data loss.
long millisStop = instantStop.toEpochMilli(); // WARNING: possible data loss.