假设我有时间戳值。
修改
Calendar curCal = new GregorianCalendar(TimeZone.getDefault());
curCal.setTimeInMillis(System.currentTimeMillis());
TimeZone fromTz = TimeZone.getDefault();
curCal.setTimeZone(fromTz);
TimeZone gmtTZ = TimeZone.getTimeZone("GMT");
Calendar toCal = new GregorianCalendar(gmtTZ);
toCal.setTimeInMillis(curCal.getTimeInMillis());
Date dd = toCal.getTime();
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss a",Locale.US);
format.setTimeZone(gmtTZ);
String ff = format.format(dd);
java.sql.Timestamp curTimeInGMT = new java.sql.Timestamp(dateInLong(ff, "dd/MM/yyyy hh:mm:ss a"));
现在我使用getTime()
;
Long l = t.getTime();
根据Java文档定义getTime()方法
Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Timestamp object.
因此,根据我通过测试多次理解,getTime()
将给出给定时间与1970年1月1日00:00:00 GMT之间的毫秒差异。
要让getTime()
从1970年1月1日00:00:00 GMT获得差异,需要另一个GMT时间。
所以它需要将给定时间转换为GMT时间。对于该转换,它需要给定时间的时区。
它将给定时间的时区视为 SYSTEM TIME ZONE ,它将获得相应的GMT时间,然后它将找到两个GMT时间之间的差异,它将返回差异。
我的理解是否正确?
答案 0 :(得分:1)
我无法真正评估你的理解,但这是我的:
Timestamp类继承自Date。日期是 - 与您从Javadoc引用的内容一致 - 只是一个长值的包装器。会发生什么情况是String被转换(不知何故 - 如果你想共享你的机制,请更新代码片段)到时间值。这隐式或显式地使用时区,但生成的长值与时区无关,它与在给定时间转换中使用的时区中调用System.currentTimeMillis()
的时间相同。如果要控制用于转换的时区,可以使用SimpleDateFormat
并按如下方式设置时区:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
simpleDateFormat.parse("2016-01-08 08:03:52.0");
} catch (ParseException e) {
// handle the error here
}
在编辑之后(缺少函数dateInLong的定义),我创建了以下测试类,其中添加了一些控制台输出:
public class test {
@Test
public void test() throws ParseException {
Calendar curCal = new GregorianCalendar(TimeZone.getDefault());
curCal.setTimeInMillis(System.currentTimeMillis());
System.out.println("curCal 1: " + curCal.getTimeInMillis());
TimeZone fromTz = TimeZone.getDefault();
curCal.setTimeZone(fromTz);
System.out.println("curCal 2: " + curCal.getTimeInMillis());
TimeZone gmtTZ = TimeZone.getTimeZone("GMT");
Calendar toCal = new GregorianCalendar(gmtTZ);
toCal.setTimeInMillis(curCal.getTimeInMillis());
Date dd = toCal.getTime();
System.out.println("dd: " + dd.getTime());
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss a", Locale.US);
format.setTimeZone(gmtTZ);
String ff = format.format(dd);
long time = dateInLong(ff, "dd/MM/yyyy hh:mm:ss a");
System.out.println("time: " + time);
java.sql.Timestamp curTimeInGMT = new java.sql.Timestamp(time);
System.out.println("curTimeGMT: " + curTimeInGMT.getTime());
}
private long dateInLong(String dateString, String formatStr) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat(formatStr);
return format.parse(dateString).getTime();
}
}
它产生以下输出:
curCal 1: 1452603245943
curCal 2: 1452603245943
dd: 1452603245943
time: 1452599645000
curTimeGMT: 1452599645000
正如你所看到的,内部long值改变的唯一场合是当日期转换为String和从String转换时(即在调用dateInLong之后),即由于使用两个不同的时区(到String:GMT,来自字符串:默认 - 此处为CET)。只要你传递内部long值,那个时刻就会保持不变 - 无论它是由Calendar
还是Date
的后代包裹。
答案 1 :(得分:0)
两点将使这项工作变得更加容易:
首先,我们必须指定一个格式化程序来解析输入字符串,或者更改它以满足java.time中默认使用的ISO 8601标准。 ISO 8601格式接近SQL格式,用T
替换中间的空格。
String input = "2016-01-08 08:03:52.0";
String inputIso8601 = input.replace ( " ", "T" );
将该字符串解析为本地日期时间,这意味着任何位置。输入字符串缺少任何时区或偏离UTC信息,因此我们从本地开始,然后将应用假定的时区。
LocalDateTime localDateTime = LocalDateTime.parse ( inputIso8601 );
让我们应用假定的时区。我随意选择蒙特利尔,但显然你需要知道并使用任何时区用于该字符串输入。如果您确定字符串表示UTC,请使用ZoneOffset.UTC
。
ZoneId zoneId = ZoneId.of ( "America/Montreal" ); // Or perhaps ZoneOffset.UTC constant.
ZonedDateTime zdt = ZonedDateTime.of ( localDateTime, zoneId );
现在我们已准备好转换为java.sql.Timestamp
对象,以便发送到数据库。旧类有一个新方法,用于转换为/从java.time对象转换。转换需要一个Instant
对象,这是UTC时间轴上的一个时刻。我们可以从Instant
中提取ZonedDateTime
。
Instant instant = zdt.toInstant ( );
java.sql.Timestamp ts = java.sql.Timestamp.from ( instant );
转储到控制台。
System.out.println ( "input: " + input + " in ISO 8601: " + inputIso8601 + " is localDateTime: " + localDateTime + " in zoneId: " + zoneId + " is zdt: " + zdt + " gives instant: " + instant + " which converts to java.sql.Timestamp ts: " + ts );
输入:2016-01-08 08:03:52.0 in ISO 8601:2016-01-08T08:03:52.0 is localDateTime:2016-01-08T08:03:52 in zoneId:America / Montreal is zdt:2016 -01-08T08:03:52-05:00 [美国/蒙特利尔]即时:2016-01-08T13:03:52Z转换为java.sql.Timestamp ts:2016-01-08 05:03:52.0 < / p>
仔细阅读该控制台输出。请注意ts
上的时间。这显示了java.sql.Timestamp
方法toString
在生成日期时间值的文本表示时静默应用JVM的当前默认时区的不幸行为。我的JVM在这里有一个默认时区America/Los_Angeles
。因此调整了时间(令人困惑)。
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和&amp; SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
如果JDBC driver符合JDBC 4.2或更高版本,您可以直接与数据库交换 java.time 对象。不需要字符串或java.sql。* classes。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。