我有一个mysql数据库,它存储一个datetime值,比如2020-10-11 12:00:00(yyyy-mm-dd hh:mm:ss格式)
这个日期的类型(在mysql中)是datetime
当我在我的控制器中检索这个数据时,它的java7类型是“date”。但它增加了一个时区,因为我怀疑我的地区。在这里我已经发现混淆,当显示这个日期,这是不应该有时区附加它实际上有。。。调试器说是“2020-10-11 12:00:00 cest”。
我的问题是日期没有存储在cest时区。例如,它与美国/纽约的一个存储在一起。编辑:我这行的意思是,日期是从纽约用纽约的时区存储的。所以,那里确实是12:00:00,但在马德里是18:00:00。我需要18:00。
所以在纽约,当时有人做了一个插页。这意味着欧洲的时代不同了。我需要计算一下在欧洲的时间是什么时候,在美国是12点。但是我的电脑在我取回它的时候一直把日期设置为cest,所以我所有的解析尝试都失败了。。。这是我的主意:
Date testingDate // This date is initialized fetching the "2020-10-11 12:00:00" from mySql
Calendar calendar = new GregorianCalendar()
calendar.setTime(testingDate)
calendar.setTimeZone(TimeZone.getTimeZone("America/New_York")
SimpleDateFormat localDateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
TimeZone localTimeZone = TimeZone.getTimeZone("Europe/Madrid")
localDateFormatter.setTimeZone(localTimeZone)
String localStringDate = localDateFormatter.format(calendar.getTime())
Date newDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(localStringDate)
在这里我的想法是:我创建一个全新的日历,把它的时间,我在美国,我也说,嘿,这个日历应该有美国时区。所以当我使用欧洲的格式化程序得到时间时,它应该加上相应的时间。这在我的头脑中是很有意义的,但它在代码d中不起作用:我真的不想自己计算时差,加上或减去小时数,因为在我看来,这看起来非常硬编码。
有谁能告诉我一些我理解错误的地方,或者我应该如何更好地解决这个问题?
重要提示:我使用的是Java7和Grails2.3.6。
2条答案
按热度按时间qnyhuwrf1#
我的问题是日期没有存储在cest时区。例如,它与美国/纽约的一个存储在一起。
据我所知,这是不可能的。
Calendar calendar = new GregorianCalendar()
不,不要。日历api是一场灾难。使用java.time
,这是java中唯一一个真正有效的时间api,并且没有完全损坏/设计得非常糟糕。如果不能(Java7已经非常过时和不安全,您必须升级!),这是jsr310后端口。添加依赖项并使用它。让我先解释一下如何理解时间,否则,这个问题的任何答案都无法正确理解:
是时候了!
有3个完全不同的概念,它们通常都被简化为“时间”的意思,但你不应该简化它们——这3个不同的概念其实并不相关,如果你把它们混淆了,问题总会出现。你不能在这三个概念之间转换,除非你故意这样做!
“太阳光时间”:这些描述的时刻作为一个普遍的全球概念,某件事发生或将要发生的时间太阳耀斑是在“x”时观测到的,这是一个“太阳耀斑”时间。最好的存储方式是millis-since-epoch。
“预约时间”:这些描述了一个特定的时刻,因为它是或将是在某个地方,但在全球范围内可以理解的方式我们下周二5点有一个zoom会议就是其中之一。它实际上并不是常数,因为地区可以决定采用新的时区,或者例如移动夏时制的“切换日期”。例如,如果您在“2021年11月5日17:00”与牙医预约,并且您想知道距预约开始还有多少小时,那么该值不应仅因为您飞往另一个时区并从那里查看该数字而更改。但是,如果您预约的国家决定取消夏令时,则应该有所改变。这就是这个和“日光灯”的区别。这一点仍然可以改变由于政治决定。
“唤醒警报时间”:这些描述了一个更易变的概念:人类指代时间的某种方式,它不指任何特定的瞬间,甚至试图指代。想想“我喜欢在8点起床”,因此,如果你要穿越时区旅行,那么下次闹钟响之前的时间是不断变化的。
现在,回答你的问题:
我有一个mysql数据库,它存储一个datetime值,比如2020-10-11 12:00:00(yyyy-mm-dd hh:mm:ss格式)
别那么快。那一栏的确切类型是什么?你的房间里有什么
CREATE TABLE
声明?这里要弄清楚的关键是磁盘上实际存储了什么?是日光浴、约会还是闹钟?有DATE
,DATETIME
以及TIMESTAMP
多年来,mysql已经显著改变了这些东西的存储方式。我相信,假设您使用的是现代的takes on storage(因此,新的mysql,没有显式模拟旧行为的设置),例如
DATETIME
商店标志,年,日,时,分,秒在引擎盖下,这意味着它是唤醒警报样式:没有时区信息在这,因此,实际的时刻在时间上根本没有设置,并取决于谁是问。与存储为utc epoch秒的时区不同,它是solarflares时间,并且它根本不包括任何时区。你得分开存放。据我所知,3种时间表示法(约会时间)中最有用的在mysql中并不是什么东西。那很烦人;mysql往往是,所以可能是标准的课程。
在java中,所有3个概念都存在:
阳光灿烂的时光
java.time.Instant
.java.util.Date
,java.sql.Timestamp
,System.currentTimeMillis()
也是阳光灿烂的时光。那个“日期”是solarflares的时间戳是疯狂的,但还有一个原因就是api被替换了。预约时间是
java.time.ZonedDateTime
唤醒警报时间为java.time.LocalDateTime
.当我在我的控制器中检索这个数据时,它的java7类型是“date”。
正确的。所以,阳光灿烂的时光。
关键是:
如果mysql中存储的时间类型与java端的时间类型不匹配,就会发生痛苦。
这听起来确实像你在磁盘上有唤醒警报时间,它最终在java端作为SolarFlaresTime。这意味着有人涉及时区转换。可能发生在mysql内部,可能发生在mysql和jdbc驱动程序之间的飞行中(mysql将其“在线”转换),或者jdbc驱动程序这样做是为了匹配java.sql.timestamp。
最好的解决方案是根本不进行转换,唯一真正的方法是更改mysql表def以匹配java,所以,要做到这一点
CREATE TABLE (foo TIMESTAMP)
,因为timestamp也是solarflares time,或者在jdbc级别使用,而不是:因为它返回太阳光时间,但是:
问题是:您的jdbc驱动程序可能不支持这一点。如果没有,它就是一个蹩脚的jdbc驱动程序,但这种情况有时会发生。
这仍然是最好的计划——a计划。因此,除非没有其他办法,否则不要继续执行糟糕的b计划。
方案b:
承认转换发生了,这是非常烦人和容易出错。因此,请确保您仔细而明确地管理它:确保设置了正确的set调用,以便mysql能够识别我们所处的时区。如果您真的需要预约时间,可以考虑添加将时区存储为表中的一列。等等。
of1yzvn42#
多亏了@rzwitserloot,我才找到了解决办法。
首先我要从数据库中获取数据。我将通过将driver/mysql添加的时区转换为localdatetime来消除它。然后,我将使用在数据库中存储数据时使用的时区创建一个新的zoneddatetime。
一旦我有了一个ZoneDateTime,就是时候用我当前的时区来转换它了。我将在适当的时间获取一个新的ZoneDateTime对象。
然后我再添加几行,将其转换回我的主“日期”类:
我已经按照建议使用了“三个十”后端口。
datemysql:“2020-10-11 10:00:00”//cest由于我的司机
时区:“美国/纽约”
期望日期:“2020-10-11 19:00:00”//cest yay!