Java将字符串转换为日期,即使提供了浏览器时区,也会减少一天
我正在将Angular应用程序中的日期作为字符串发送到服务器,并将其转换为javaJava将字符串转换为日期,即使提供了浏览器时区,也会减少一天,java,timezone,date-parsing,date,Java,Timezone,Date Parsing,Date,我正在将Angular应用程序中的日期作为字符串发送到服务器,并将其转换为javadate对象以存储在数据库中 还从UI发送timeZoneOffset,以在转换时使用客户端的时区。(在谷歌搜索之后,我发现这种方法可以根据用户的位置获得正确的结果) 编写了以下代码以进行转换: public static void main(String args[]) throws ParseException { String inputDate = "04/05/2018"; // This dat
date
对象以存储在数据库中
还从UI发送timeZoneOffset
,以在转换时使用客户端的时区。(在谷歌搜索之后,我发现这种方法可以根据用户的位置获得正确的结果)
编写了以下代码以进行转换:
public static void main(String args[]) throws ParseException {
String inputDate = "04/05/2018"; // This date coming from UI
int timeZoneOffset = -330; // This offset coming from UI
// (new Date().getTimeZoneOffset())
getDate(inputDate, timeZoneOffset);
}
public static Date getDate(String inputDate, int timeZoneOffset)
throws ParseException {
SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(-timeZoneOffset * 60);
System.out.println("Default time zone: " + TimeZone.getDefault().getID());
TimeZone timeZone = TimeZone.getTimeZone(zoneOffset);
System.out.println("Time zone from offset: " + timeZone.getID());
dateFormat.setTimeZone(timeZone);
Date date = dateFormat.parse(inputDate);
System.out.println("Converted date: " + date);
return date;
}
预期产出:
默认时区:美国/纽约来自偏移的时区:GMT+05:30
转换日期:2018年4月5日星期四00:00:00 服务器中的实际结果: 默认时区:美国/纽约
来自偏移的时区:GMT+05:30
转换日期:2018年4月4日星期三美国东部夏令时14:30:00 为什么即使我设置了用户时区,日期也会减少到一天?我是新的日期和时间相关的概念,我谷歌了几次没有找到答案,请有人在这方面提供帮助
提前感谢它并没有减少一天,而是减少了11.5小时。这恰好是GMT+05:30和“美国/纽约”之间的时差,即GMT-04:30或GMT-05:30(取决于一年中的时间) GMT+05:30在印度的某个地方,我想,因为那是唯一一个使用30分钟而不是一个小时的偏移量的地方。当印度是4月5日时,纽约仍然是4月4日
问题可能是你没有从客户那里得到时间,所以它将假定为午夜。如果您正在进行时区转换,最好包括实际时间。它不是减少一天,而是减少11.5小时。这恰好是GMT+05:30和“美国/纽约”之间的时差,即GMT-04:30或GMT-05:30(取决于一年中的时间) GMT+05:30在印度的某个地方,我想,因为那是唯一一个使用30分钟而不是一个小时的偏移量的地方。当印度是4月5日时,纽约仍然是4月4日 问题可能是你没有从客户那里得到时间,所以它将假定为午夜。如果要进行时区转换,最好包含实际时间。正确 tl;博士 2018-04-05T00:00+05:30[亚洲/加尔各答] 对于数据库中的存储,请使用UTC 当新的一天在印度开始时,UTC的日期仍然是“昨天”,因此是4月4日而不是4月5日。同一时刻,时间线上的同一点,不同的挂钟时间
LocalDate.parse(
"04/05/2018" ,
DateTimeFormatter.ofPattern( "MM/dd/uuuu" )
)
.atStartOfDay(
ZoneId.of( "Asia/Kolkata" )
)
.toInstant()
2018-04-04T18:30:00Z
java.time
您正在使用糟糕的旧日期时间类,这些类被证明是设计糟糕、令人困惑和麻烦的。它们现在被java.time类取代
完全避免遗留日期时间类
您将现代类(ZoneOffset
)与麻烦的遗留类(TimeZone
)混合在一起不要将现代类与传统类混用。忘记所有旧类,包括Date
、Calendar
和SimpleDateFormat
。time类被设计为完全取代遗留类
使用ZoneId
(和ZoneOffset
)代替TimeZone
LocalDate
将输入字符串解析为LocalDate
。该类表示一个仅限日期的值,不包含一天中的时间和时区
String input = "04/05/2018" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uuuu" ) ;
LocalDate ld = LocalDate.parse( input , f ) ;
偏移量与时区
int timeZoneOffset=-330
时间不是时区。偏移量只是从UTC偏移的小时数、分钟数和秒数。您选择的变量名表明在这一点上可能存在混淆
ZoneOffset offset = ZoneOffset.of( -3 , 30 ) ;
A是特定地区人民使用的过去、现在和未来抵消变化的历史。因此,时区总是比偏移更可取
以大陆/地区
的格式指定,例如,或太平洋/奥克兰
。切勿使用3-4个字母的缩写,如EST
或IST
,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)
一天中的第一刻
你的目标似乎是在那个区域约会的第一刻。让java.time确定一天中的第一个时刻。不要假设时间是00:00:00。在某些日期的某些区域中,一天可能在其他时间开始,例如01:00:00
ZonedDateTime zdt = ld.atStartOfDay( z ) ; // Determine the first moment of the day on this date in this zone. Not always 00:00:00.
作为一个为什么应该使用时区而不仅仅是从UTC偏移的示例,请查看您的示例数据-330
,我很容易将其误解为比UTC晚三个半小时。该偏移量目前仅在美国/圣约翰地区使用,并且仅在一年中的部分时间使用。因此,如果对一年中错误部分的日期应用-03:30的偏移量,则结果将无效,但未被检测到
使用偏移(不推荐)
但是您的示例缺少时区,所以让我们使用UTC的偏移量,而不是时区
使用int
整数表示与UTC的偏移量是一种糟糕的类型选择。首先,它是模棱两可的。那次-330
可能被解释为是在-03:30
比预定时间晚三个半小时的情况下进行的笨拙尝试。其次,它使解析比需要的更复杂。第三,作为分钟数,它忽略了以秒为偏移量的可能性。第四,您使用负数表示UTC之前的偏移量(显然),尽管常用用法和标准用法正好相反。最后,它忽略了为将偏移表示为文本而设置的清晰标准:±HH:MM:SS
(和变体)。顺便说一句,在标准中填充零是可选的,但我建议始终包含零,因为各种库和协议都需要它
您的意图似乎是整数指定的分钟数
long seconds =( TimeUnit.MINUTES.toSeconds( - 330 ) * -1 ); // Multiply by negative one to flip the sign to standard ISO 8601 usage, where `+` means “ahead* of UTC and `-` means *behind* UTC.
秒:19800
offset.toString():+05:30
最后的
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ; // India time zone. Currently uses offset of +05:30 (five and a half hours ahead of UTC).
ZonedDateTime zdt = ld.atStartOfDay( z ) ; // Determine the first moment of the day on this date in this zone. Not always 00:00:00.
long seconds =( TimeUnit.MINUTES.toSeconds( - 330 ) * -1 ); // Multiply by negative one to flip the sign to standard ISO 8601 usage, where `+` means “ahead* of UTC and `-` means *behind* UTC.
ZoneOffset offset = ZoneOffset.ofTotalSeconds( ( int ) seconds );
OffsetDateTime odt = ld.atStartOfDay( offset ).toOffsetDateTime();
Instant instant = zdt.toInstant() ;