【问题标题】:Java - date saved as the day beforeJava - 保存为前一天的日期
【发布时间】:2012-10-27 08:11:15
【问题描述】:

我在数据库中保存日期时遇到了一种非常奇怪的行为。在我的(Linux centOS 6.2)服务器上,我使用 glassfish 应用程序服务器(3.1.1 - build 12)和 Java(1.7.0_09),该应用程序是用 Java + GWT 开发的,它使用 PostgreSQL 服务器(9.2.1)。在应用程序内部,有几个日期字段保存在数据库中。日期字段使用 datepicker (http://code.google.com/p/gwt-datepicker, r30)。

db 关系的日期属性是日期类型(不是时间戳)。一些日期前一天保存在数据库中。该问题仅发生在间隔之间的日期,例如在 31.03.1968 和 27.10.1968 之间,这让我想到了某种夏令时问题。但由于它不会发生在 1969 年,例如,我不能很好地隔离问题。我试图找到问题发生的其他日期间隔。 例如,如果我在应用程序中选择 19.05.1968,则保存到数据库后,日期将保存为 18.05.1968。

奇怪的是,我在另一台服务器上有同一个应用程序的另一个实例,并且在相同的日期它们被正确保存。 这让我认为问题可能取决于:

  • glassfish 配置;
  • java(java.util.Date 实现?);
  • 我缺少某种服务器配置

我尝试将我的服务器的所有可能配置都设置为欧洲/罗马(我的时区),但没有。任何想法?我该如何解决或调查这个问题?

更新: 1968年是闰年。这个问题也发生在 1972 年,又是闰年。总结:“date-saved-one-day-before”问题发生在闰年的夏令时日期间隔中。

创建日期对象的代码部分是:

Date d = dateField.getSelectedDate();
if (d != null) {
    txtVal = DateTimeFormat.getFormat("dd/MM/yyyy").format(d);
}

其中 dateField 声明为:

transient private DatePicker dateField;

包是org.zenika.widget.client.datePicker.DatePicker(前面提到过gwt-datepicker-r30),DateTimeFormat指的是com.google.gwt.i18n.shared.DateTimeFormat

接受答案后更新:

我使用了这个解决方法:创建日期时,我使用以下代码:

final long hours12 = 12L * 60L * 60L * 1000L;
Date d = new Date(d1.getTime() + hours12);

【问题讨论】:

  • 你在用什么jre r?如果是 1.4 或更早版本,那么您可能会遇到问题
  • java 版本“1.7.0_09”Java(TM) SE 运行时环境(内部版本 1.7.0_09-b05)Java HotSpot(TM) 64 位服务器 VM(内部版本 23.5-b02,混合模式)
  • @lorenzo.marcon 也许昨天对你来说基本上是太长的一天;)。但无论如何,这是一个有趣的问题,如果您找到解决方案,请告诉我们。
  • 我从问题中删除了更新,因为我错了,即使今天早上我仍然遇到问题.. :/
  • 你有代码来操作日期吗?如果是这样,你可以发布它吗? (我见过许多日期计算在夏令时更改发生时会中断。)

标签: java postgresql gwt date glassfish


【解决方案1】:

您使用的是 java.util.date 还是 java.sql。日期(后者是正确的)?我在 SQL Server 上遇到了类似的问题,即使它是正常的,是的,与夏季有关。

基本上,您将 Java 日期存储为特定日期的午夜。如果是夏令时,日期会移到前一天的 23:00,然后时间会被截断!如果您发送带有“随机”时间戳的日期,您将在夏季 24 次中遇到此问题。

我不记得确切的解决方案(它不会直接帮助您,因为它指的是不同的 DBMS),但在 dB 中有一个设置说“存储您收到的日期”。您可以通过将 dbcolumn 更改为时间戳并查看时间的存储方式来测试是否是这种情况。

我做了一些研究 - 似乎 gwt-datepicker 有很多问题! http://code.google.com/p/google-apps-script-issues/issues/detail?id=2022http://code.google.com/p/google-apps-script-issues/issues/detail?id=2001

如果他们的计算在闰年有错误,我不会感到惊讶。此外,完全有可能只是您正在做的事情与您认为自己正在做的事情之间不匹配 - 使用 Dates 是一件非常困难的事情

要检查,请尝试:

final java.util.Date ud = dateField.getSelectedDate();;
final java.sql.Date sd = new java.sql.Date(ud.getTime());
System.out.println(ud);// this is what you pick from the DatePicker
System.out.println(sd);// this is what will be stored on the database

看看它们在闰年的夏季是否匹配。如果是 GWT 错误,http://code.google.com/p/google-apps-script-issues/ 是报告它的正确位置

【讨论】:

  • 感谢您的回答,我在代码的不同部分都使用了它们。奇怪的是,这个问题只发生在闰年和夏季时间日期间隔。我使用postgreSQL:我试图记录所有查询,当它到达数据库时日期已经错误,所以问题出在其他地方。今天我将尝试尽可能简化代码,以隔离导致问题的代码部分。
【解决方案2】:

只需将日期时间设置为 12:00(而不是默认的 0:00)就可以了。问题是 GWT 时区库不包括 1990 年之前的所有闰年,因此您将在服务器上得到错误的时间(因为该值是以时间戳的形式发送的,并且间隔一小时)。

顺便说一句:GWT 有一个内置的日期选择器,在http://gwt.google.com/samples/Showcase/Showcase.html#!CwDatePicker 上查看它的演示

【讨论】:

  • 似乎是一个可行的解决方案,我今晚会检查一下,谢谢。您从哪里找到有关 GWT 中 1990 年之前缺少闰年的信息?
  • 嗯,不确定是 1990 年,但您必须更多地了解 GWT 时区的内部工作原理。它们在以下文件中定义为转换:code.google.com/searchframe#T04cSGC7sWI/trunk/user/src/com/… 这些转换的格式为 。由于小时数是从 1970 年开始计算的,因此在 1970 年之前不能有任何转换。
  • 查看文件似乎定义了 1970 年及以后的所有转换(直到 2037 年)。
  • 好吧..这对我有用。这并不是真正的修复,但解决方法对我的目的很有效,谢谢。
  • @lorenzo.marcon 是什么原因? 1970 年之前缺失的过渡?
【解决方案3】:

针对出生日期实时面对这个问题。

我进行了以下修复,因此不是在上午 12 点保存日期,而是在服务器工作时间之前的上午 6 点保存日期。即使扣除一个小时,也不影响dob。

Calendar now = Calendar.getInstance();
now.setTime(YOUR_DATE);
now.set(Calendar.HOUR_OF_DAY, 6);
YOUR_DATE = now.getTime();

迈克的回答很好。但是,如果我们用 12 点保存,如果用户在 12 点之前的营业时间内输入日期,则日期比较可能会出错。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-19
    • 2019-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多