我有一个java应用程序,我希望在UTC中的时间。目前,该代码使用java.util.Date
和java.sql.Timestamp
的混合。为了得到UTC的时间,我之前的程序员使用了:
日期:
Date.from(ZonedDateTime.now(ZoneOffset.UTC)).toInstant();
对于时间戳:
Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
但是我自己使用此代码运行了多个测试,这两行都返回当前日期/时间(在我当前的时区)。从我读过的所有内容出现日期/时间戳没有zoneOffset值,但我找不到具体的声明。
有没有将timeZone(UTC)保留在Date或Timestamp对象中,还是需要进行一些重构并在整个应用程序中使用实际的ZonedDateTime对象?此ZonedDateTime对象是否也与sql的当前Timestamp对象兼容?
示例:
public static void main (String args[])
{
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
Timestamp timestamp = Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
Date date = Date.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
System.out.println("ZonedDateTime: " + zonedDateTime);
System.out.println("Timestamp: " + timestamp);
System.out.println("Date: " + date);
}
输出:
ZonedDateTime: 2017-04-06T15:46:33.099Z
Timestamp: 2017-04-06 10:46:33.109
Date: Thu Apr 06 10:46:33 CDT 2017
答案 0 :(得分:29)
Instant.now() // Capture the current moment in UTC with a resolution up to nanoseconds.
仅使用 java.time 类。避免在Java 8之前添加麻烦的旧的旧日期时间类。
在您使用新的现代java.time类之前,程序员现在已经取代了Date
,Calendar
,Timestamp
这些臭名昭着的旧版旧日期时间类。
Instant
Instant
类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。以UTC格式获取当前时刻非常简单:Instant.now
。
Instant instant = Instant.now();
您应该坚持使用java.time类,并避免遗留类。但是如果绝对必要,例如与尚未针对java.time更新的旧代码接口,则可以转换为/从java.time。查看旧类的新方法。遗留类java.util.Date
等效于Instant
。
java.util.Date d = java.util.Date.from( myInstant); // To legacy from modern.
Instant instant = myJavaUtilDate.toInstant(); // To modern from legacy.
避免使用旧版日期时间类。请改用java.time类。
您的JDBC 4.2兼容driver可以通过调用PreparedStatement::setObject
和ResultSet::getObject
直接解决java.time类型问题。
myPreparedStatement.setObject( … , instant ) ;
......和......
Instant instant = myResultSet.getObject( … , Instant.class ) ;
如果没有,请回到使用java.sql类型,但尽可能简短。使用添加到旧类的新转换方法。
myPreparedStatement.setTimestamp( … , java.sql.Timestamp.from( instant ) ) ;
......和......
Instant instant = myResultSet.getTimestamp( … ).toInstant() ;
ZonedDateTime
请注意,我们不需要您提到的ZonedDateTime
,因为您说您只对UTC感兴趣。 Instant
个对象始终为UTC。这意味着您引用的原始代码:
Date.from(ZonedDateTime.now(ZoneOffset.UTC)).toInstant();
......可以简单地缩短为:
Date.from( Instant.now() ) ;
请注意,java.util.Date
也始终为UTC。但是,遗憾的是,toString
在生成String时会隐式应用JVM的当前默认时区。通过搜索Stack Overflow,您可以看到这种反特征不会产生混淆。
如果您希望通过区域wall-clock time的镜头查看Instant
对象的UTC值,请指定时区ZoneId
以获得ZoneDateTime
。
以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用诸如CDT
或EST
或IST
之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的( !)。
ZoneId z = ZoneId.of( "America/Chicago" );
ZonedDateTime zdt = instant.atZone( z );
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 1 :(得分:5)
在Java中,Date
代表一个时间点。它与时间戳无关。当您调用toString()
对象的Date
方法时,它会将该时间转换为平台的默认时间戳,例如以下将以UTC格式打印日期/时间(因为它将默认时区设置为UTC):
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
Timestamp timestamp = Timestamp.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
Date date = Date.from(ZonedDateTime.now(ZoneOffset.UTC).toInstant());
System.out.println("ZonedDateTime: " + zonedDateTime);
System.out.println("Timestamp: " + timestamp);
System.out.println("Date: " + date);
答案 2 :(得分:0)
我创建了如下所示的SimpleJdbcUpdate类:
public class SimpleJdbcUpdate {
private final JdbcTemplate jdbcTemplate;
private DataSource dataSource;
private String tableName;
private final TableMetaDataContext tableMetaDataContext = new TableMetaDataContext();
Map<String, ColumnInfo> propertyToColumnMap = new HashMap<>();
private boolean compiled;
public SimpleJdbcUpdate(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
this.dataSource = dataSource;
}
private List<String> getColumnNames() {
return Collections.emptyList();
}
private String[] getGeneratedKeyNames() {
return new String[0];
}
public SimpleJdbcUpdate withTableName(String tableName) {
this.tableName = tableName;
return this;
}
public int execute(BeanPropertySqlParameterSource parameterSource, String[] keys) {
if (!compiled) {
compile();
}
return doExecute(parameterSource, keys);
}
private int doExecute(BeanPropertySqlParameterSource parameterSource, String[] keys) {
String[] propertyNames = parameterSource.getParameterNames();
List<Object> values = new ArrayList<>();
String updateSql = updateSql(parameterSource, propertyNames, values);
String wherePart = wherePart(parameterSource, keys, values);
String updateSqlWithWhere = updateSql + wherePart;
return jdbcTemplate.update(updateSqlWithWhere, values.toArray());
}
private String updateSql(BeanPropertySqlParameterSource parameterSource, String[] propertyNames, List<Object> values) {
StringBuilder updateSqlBuilder = new StringBuilder("update " + tableName + " set ");
boolean first = true;
for (String propertyName : propertyNames) {
ColumnInfo columnInfo = propertyToColumnMap.get(propertyName);
if (columnInfo == null) {
continue;
}
addValue(parameterSource, values, propertyName);
if (!first) {
updateSqlBuilder.append(", ");
}
updateSqlBuilder.append(columnInfo.columnName + " = ?");
first = false;
}
return updateSqlBuilder.toString();
}
private String wherePart(BeanPropertySqlParameterSource parameterSource, String[] keys, List<Object> values) {
StringBuilder wherePartBuilder = new StringBuilder();
boolean first = true;
for (String key : keys) {
ColumnInfo columnInfo = propertyToColumnMap.get(key);
if (columnInfo == null) {
continue;
}
addValue(parameterSource, values, key);
if (first) {
wherePartBuilder.append(" WHERE ");
} else {
wherePartBuilder.append(" AND ");
}
wherePartBuilder.append(columnInfo.columnName + " = ?");
first = false;
}
return wherePartBuilder.toString();
}
private void addValue(BeanPropertySqlParameterSource parameterSource, List<Object> values, String propertyName) {
if (parameterSource.hasValue(propertyName)) {
Object typedValue = SqlParameterSourceUtils.getTypedValue(parameterSource, propertyName);
if (typedValue.getClass().isEnum()) {
typedValue = new SqlParameterValue(Types.VARCHAR, ((Enum) typedValue).name());
}
values.add(typedValue);
}
}
private void compile() {
tableMetaDataContext.setTableName(tableName);
this.tableMetaDataContext.processMetaData(dataSource, getColumnNames(), getGeneratedKeyNames());
List<String> tableColumns = tableMetaDataContext.getTableColumns();
for (int i = 0; i < tableColumns.size(); i++) {
String column = tableColumns.get(i);
String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(column);
propertyToColumnMap.put(propertyName, new ColumnInfo(column, i));
}
compiled = true;
}
private static class ColumnInfo {
String columnName;
Integer index;
public ColumnInfo(String columnName, Integer index) {
this.columnName = columnName;
this.index = index;
}
}
}