Java Grails中的时区转换会导致错误的日期

Java Grails中的时区转换会导致错误的日期,java,grails,calendar,timezone,Java,Grails,Calendar,Timezone,我将在Grails(Java)中讨论时区。这里使用Java 7和Grails 2.3.7 我有一个WebApp,每个用户都被分配了一个时区ID。如果用户输入日期,则该日期仅由日、月和年组成。我想自动设置时间 用户输入的日期(例如2018年10月1日,德语格式)应以UTC格式保存在DB(MySQL)中。 当向用户显示日期时,它将根据用户的时区进行格式化 很多TimeZoneId可以很好地使用我的代码(欧洲/柏林、香港等),但美国/纽约就不行,我不明白为什么 解析和保存日期的代码如下: //endD

我将在Grails(Java)中讨论时区。这里使用Java 7和Grails 2.3.7

我有一个WebApp,每个用户都被分配了一个时区ID。如果用户输入日期,则该日期仅由日、月和年组成。我想自动设置时间

用户输入的日期(例如2018年10月1日,德语格式)应以UTC格式保存在DB(MySQL)中。 当向用户显示日期时,它将根据用户的时区进行格式化

很多TimeZoneId可以很好地使用我的代码(欧洲/柏林、香港等),但美国/纽约就不行,我不明白为什么

解析和保存日期的代码如下:

//endDate is 31.10.2018
def format = messageService.getMessage(code: 'default.date.short.format')

//--> dd.MM.yyyy for DE and MM/dd/yy for EN
println("Use format: " + format)

SimpleDateFormat sdf = new SimpleDateFormat(format);

//set timezone (America/New_York)
sdf.setTimeZone(TimeZone.getTimeZone(user.timeZoneID))

//parse endDate
Date parsedEndDate = sdf.parse(endDate)

//create a calendar instance (e.g. America/New_York)
Calendar calendarEnd = Calendar.getInstance(TimeZone.getTimeZone(user.timeZoneID));

//set time
calendarEnd.setTime(parsedEndDate);

//set hour/minute automatically
calendarEnd.set(Calendar.HOUR_OF_DAY, 23)
calendarEnd.set(Calendar.MINUTE, 59)

//at this point it should be 31.10.2018, 23:59 (german format, timezone America/New_York)

//Convert to UTC before saving date in DB (MySQL)
calendarEnd.setTimeZone(TimeZone.getTimeZone('UTC'))

//save the date
def obj = new Foo(date:calendarEnd).save(flush:true)
<g:formatDate
        timeZone="${user.timeZoneID}"
        date="${fooInstance?.calendarEnd}"
        format="${message(code: 'default.date.format', default: 'MM/dd/yyyy, hh:mm a')}"/>
我的视图(gsp)中显示日期的代码如下:

//endDate is 31.10.2018
def format = messageService.getMessage(code: 'default.date.short.format')

//--> dd.MM.yyyy for DE and MM/dd/yy for EN
println("Use format: " + format)

SimpleDateFormat sdf = new SimpleDateFormat(format);

//set timezone (America/New_York)
sdf.setTimeZone(TimeZone.getTimeZone(user.timeZoneID))

//parse endDate
Date parsedEndDate = sdf.parse(endDate)

//create a calendar instance (e.g. America/New_York)
Calendar calendarEnd = Calendar.getInstance(TimeZone.getTimeZone(user.timeZoneID));

//set time
calendarEnd.setTime(parsedEndDate);

//set hour/minute automatically
calendarEnd.set(Calendar.HOUR_OF_DAY, 23)
calendarEnd.set(Calendar.MINUTE, 59)

//at this point it should be 31.10.2018, 23:59 (german format, timezone America/New_York)

//Convert to UTC before saving date in DB (MySQL)
calendarEnd.setTimeZone(TimeZone.getTimeZone('UTC'))

//save the date
def obj = new Foo(date:calendarEnd).save(flush:true)
<g:formatDate
        timeZone="${user.timeZoneID}"
        date="${fooInstance?.calendarEnd}"
        format="${message(code: 'default.date.format', default: 'MM/dd/yyyy, hh:mm a')}"/>

在DB内部我得到2018-11-01 00:59:00 在我看来(普惠制),结果是2018年10月31日19:59,而不是2018年10月31日23:59


非常感谢您的帮助。

问题在转换步骤中:

//Convert to UTC before saving date in DB (MySQL)
calendarEnd.setTimeZone(TimeZone.getTimeZone('UTC'))
因为您只是在更改时区,所以它使用给定的时间和日期,就好像它是UTC时区一样

Java 1.7和之前的版本在时间API方面有些笨拙,所以很多人使用Joda Time

否则,您可以使用以下建议:

calendarEnd.add(Calendar.MILLISECOND, TimeZone.getTimeZone('UTC').getOffset(parsedEndDate.getTime())

这没有经过测试,可能是错误的,因为偏移计算可能不同

非常感谢您的回答。我认为时区不仅可以设定,而且可以转换。那么,如果仅设置时区,如何转换为UTC呢?好的,上面的代码在某些情况下可以工作,但它不能完全解决问题。我已经将joda时间插件集成到我的Grails应用程序中。由于域类中的属性属于Calendar类型,因此我将实现一个计算Joda时间段时区的服务。也就是说,在域类中,我仍然有日历。但是,在逻辑时间内。日历对象以UTC格式存储在数据库中。问题是(就应用程序设计和进一步实现而言)这是否是一个好主意?还是有必要重新编写我的应用程序?我也处理了这个问题,我刚刚编写了一个日历到/从日期时间转换器,应用于需要的地方。Fyi,非常麻烦的旧日期时间类,如和
java.text.SimpleDateFormat
,现在被java 8和更高版本中内置的类所取代。看,谢谢。我改用乔达时间。不幸的是,java 8没有选择Joda Time项目现在处于维护模式,接收更新和错误修复,但没有新功能工作。该项目的负责人Stephen Colebourne还负责Three Ten Backport项目,该项目使用几乎相同的API将大部分java.time功能引入java 6和7。