以下是我要解决的问题:从数据库A读取字符串,将字符串转换为Date对象,将Date对象存储到数据库B中。
EX)数据库A:读入日期字符串" 2015-03-08 02:00:00"从数据库A转换为Date对象,存储回数据库B.
此处出现的问题是因为凌晨2点是美国中部时间夏令时的开始,因此数据对象将凌晨2点直接转换为凌晨3点,这意味着凌晨3点将存储到数据库B 。
有没有办法纠正这个?如果有必要,我不反对使用Joda Time。
我正在努力关注上述日期,2015-03-08 02:00:00
这是我正在使用的代码:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = "2015-03-08 02:00:00.0";
try
{
d = sdf.parse(date);
sdf.format(d);
//Insert into database here
// ---
//
}
catch (ParseException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
答案 0 :(得分:1)
你有多个问题交织在一起。
您不应该从数据库中读取日期时间值的字符串,您应该阅读日期时间对象。 StackOverflow上有关于从/向数据库读取/写入日期时间值的许多问题,因此无需在此重复。
如果您有字符串,例如“2015-03-08 02:00:00”,请注意缺少时区或偏移的任何指示。如果您想假设该字符串表示美国中部时间特定的时间,那么您必须接受没有这样的日期时间这一事实,因为夏令时(DST)将其定义为凌晨3点。在凌晨2点,时间标记跳到凌晨2点。因此,试图获得这样一个不存在的日期时间是没有意义的。
日期工作的重要提示:避免将时区视为“中央时间”和3-4个字母代码,如“CST”。这些不是标准化的,也不是唯一的(许多重复的),并且进一步混淆了夏令时的混乱。以“continent / majorCityOrRegion”模式使用proper time zone。
也许你的意思是我们称之为“当地时间”,其中日期时间并非特定于任何一个时区。例如,“圣诞节从2015年12月25日午夜开始”。这意味着每个特定时区的不同时刻。例如,圣诞节早在巴黎就比蒙特利尔晚了。
让我们在Joda-Time中将该字符串解释为LocalDateTime
。首先,为方便起见,我们用“T”替换SPACE,以利用Joda-Time的ISO 8601格式的内置解析器。
String input = "2015-03-08 02:00:00";
String inputStandardized = input.replace( " ", "T" ); // For convenience, convert input text to comply with ISO 8601 standard’s canonical format. Replace SPACE between date & time portions with "T".
接下来我们解析该标准化字符串。
LocalDateTime localDateTime = LocalDateTime.parse( inputStandardized );
转储到控制台。
System.out.println( "inputStandardized: " + inputStandardized );
System.out.println( "localDateTime: " + localDateTime );
跑步时。
inputStandardized: 2015-03-08T02:00:00
localDateTime: 2015-03-08T02:00:00.000
可以使用SQL type TIMESTAMP WITHOUT TIME ZONE
将本地日期时间存储在SQL数据库中。此类型表示不会在获取(SELECT)或放入(INSERT / UPDATE)数据库值中对UTC时区进行调整。有关这些SQL类型的详细信息,请参阅Postgres doc。
如果您想表示特定时区(例如America/Chicago
)中的特定时刻,则需要指定该时区。对于此类特定于时区的值,您可以在数据库中使用数据类型TIMESTAMP WITH TIME ZONE
。该类型名称具有误导性 - 它意味着尊重时区,因为它将输入数据调整为UTC。然后,数据的原始时区将丢失。
不幸的是,这是Joda-Time让我们失望的少数情况之一。而不是做一个调整,Joda-Time拒绝,抛出异常。 ☹
亲自看看......让我们将以下代码添加到上面的示例代码中。
DateTimeZone zone = DateTimeZone.forID( "America/Chicago" );
DateTime dateTimeChicago = localDateTime.toDateTime( zone ); // If the input lacks an offset, then Joda-Time *assigns* the value the specified time zone. If the input has an offset, Joda-Time *adjusts* the value to the specified zone.
转储到控制台。
System.out.println( "zone: " + zone );
System.out.println( "dateTime: " + dateTimeChicago );
跑步时。
Exception in thread "main" org.joda.time.IllegalInstantException: Illegal instant due to time zone offset transition (daylight savings time 'gap'): 2015-03-08T02:00:00.000 (America/Chicago
…
似乎没有好的通用解决方法,只是黑客攻击。基本上,如果您期望某个时区,您可以自己进行调整。查看this,this,this和the Joda-Time FAQ等讨论。
在Java 8及更高版本中,我们在java.time package(Tutorial)中有了新的内置日期时间框架。这个框架的灵感来自于Joda-Time,并且比Joda-Time有一些优势。其中一个优点是处理这个DST不存在的价值问题。
String input = "2015-03-08 02:00:00";
String inputStandardized = input.replace( " ", "T" );
LocalDateTime localDateTime = LocalDateTime.parse( inputStandardized );
让我们调整本地日期时间以指定特定时区。 java.time框架检测不存在的日期时间并自动滑动时间向前以尊重DST转换。
ZoneId zone = ZoneId.of( "America/Chicago" );
ZonedDateTime zdt = ZonedDateTime.of( localDateTime, zone );
转储到控制台。
System.out.println("inputStandardized: " + inputStandardized );
System.out.println("localDateTime: " + localDateTime );
System.out.println("zone: " + zone );
System.out.println("zdt: " + zdt );
跑步时。
inputStandardized: 2015-03-08T02:00:00
localDateTime: 2015-03-08T02:00
zone: America/Chicago
zdt: 2015-03-08T03:00-05:00[America/Chicago]
如上所述,您可以搜索StackOveflow以获取有关获取和退出数据库的日期时间的大量信息。
理想情况下,使用java.time,您可以直接将LocalDateTime
或ZonedDateTime
提供给JDBC驱动程序。但是大多数驱动程序尚未更新以处理java.time类型。在您的驱动程序更新之前,请回到java.sql.* classes。可以在与Java捆绑的新旧类中找到方便的转换方法。
java.sql.Timestamp ts = java.sql.Timestamp.valueOf( localDateTime );
...或...
Instant instant = zdt.toInstant();
java.sql.Timestamp ts = java.sql.Timestamp.from( instant );
答案 1 :(得分:0)
通常最好将日期存储为自纪元以来的毫秒数。这样,您可以使用long来存储数据库中的数字,当您需要格式化日期时,您可以使用Joda Time的DateTime(long)
构造函数,也可以只使用内置的Date(long)
构造函数。