Java 将1小时添加到13位时间戳

Java 将1小时添加到13位时间戳,java,collections,timestamp,Java,Collections,Timestamp,我尝试了下面的代码 Timestamp timestampDate = scheduled.getInterviewDateAndTime(); //from DB Map<String, Object> map = new HashMap(); map.put("eventTitle", "interview with"); map.put("startDateTime", timestampDate); System.out.println("startDateTime

我尝试了下面的代码

Timestamp timestampDate = scheduled.getInterviewDateAndTime(); //from DB
Map<String, Object> map = new HashMap();    
map.put("eventTitle", "interview with");
map.put("startDateTime", timestampDate);
System.out.println("startDateTime : " + timestampDate);

long addTime = 1*60*60*1000;
timestampDate.setTime(timestampDate.getTime() + TimeUnit.HOURS.toMillis(addTime));
map.put("endDateTime", timestampDate);
System.out.println("endDateTime : " + timestampDate);

如何获得正确的输出?

这里有几个问题:

  • java.sql.Timestamp
    (我假设它就是这样)是一个可变类,因此在它上面设置时间会更改时间戳状态。即使println语句不明显,事后调试映射也会在心跳中显示出来
  • 你计算小时数的逻辑是错误的(你在那里乘了两倍)
  • 第一次使用
    addTime
    变量时
  • 第二次使用
    TimeUnit.toMillis()
当然,有几种方法可以解决这个问题:

我更喜欢的方式(但是,它需要Java8或ThreeTen库):

它利用将时间戳转换为
java.time.Instant
对象(或ThreeTen的等效版本)的能力,然后是一个工厂构造函数,它将获取
Instant
并从中生成
Timestamp
(这是java 8版本,ThreeTen将在其他类中具有类似的工厂,而不是在时间戳上)。与来自JDK的旧datetime/calendar类相比,它还利用了
java.time
中添加的更干净的时间计算逻辑

第二种变体大致相同,没有使用所有的花哨内容,但因此(对我来说)可读性也差得多:

正如您所看到的,第二个变量几乎就是您所拥有的,但没有不必要的计算


请不要手动计算这些值;我们都知道,一小时应该是60分钟,一分钟是60秒,等等,但是到处读这篇文章很快就会让眼睛模糊。您自己也看到了,首先手动计算,然后仍然使用时间单位1。当你需要增加一天的时候,情况就更糟了,因为考虑到夏令时和历史时区的变化,millis不允许你只增加一天,而不在某个特定时间点提取大量关于一天长度的信息。不是每分钟都是60秒,你知道,也有一些补偿措施。

我给你的建议是停止使用过时的时间戳类。如果可以的话,要么完全使用,要么至少尽量减少使用。我将向您展示这两个选项的代码。和他一起工作要好得多。更重要的是,当涉及到时间算术时,比如在约会时间上加一个小时

java.time
更改
getInterviewDateAndTime()
以返回
即时消息
Instant
是来自
java.time
的类,它自然地取代了旧的
Timestamp
类。同时更改
地图的接收器
以接受包含
即时
对象的地图。JDBC、JPA等的现代版本很乐意从数据库中检索
Instant
对象,并将
Instant
存储回数据库中

    Instant instantStart = scheduled.getInterviewDateAndTime(); //from DB
    Map<String, Object> map = new HashMap<>();    
    map.put("eventTitle", "interview with");
    map.put("startDateTime", instantStart);
    System.out.println("startDateTime : " + instantStart);

    Instant instantEnd = instantStart.plus(1, ChronoUnit.HOURS);
    map.put("endDateTime", instantEnd);
    System.out.println("endDateTime : " + instantEnd);
时间以UTC为单位

编辑:正如Basil Bourque在一篇评论中指出的,增加一小时也可以这样做:

    Instant instantEnd = instantStart.plus(Duration.ofHours(1));
结果是一样的

与遗留API一起使用 假设您无法更改
getInterviewDateAndTime()
的返回类型和/或地图的接收者绝对需要
Timestamp
对象。实现这种限制的标准方法是在自己的代码中仍然使用现代API。一旦收到
时间戳
,就将其转换为
即时
。当您需要将
时间戳
传递给遗留代码时,您只能在最后一刻转换
即时

    Timestamp timestampStart = scheduled.getInterviewDateAndTime(); //from DB
    Instant instantStart = timestampStart.toInstant();
    Map<String, Object> map = new HashMap<>();    
    map.put("eventTitle", "interview with");
    map.put("startDateTime", timestampStart);
    System.out.println("startDateTime : " + timestampStart);

    Instant instantEnd = instantStart.plus(1, ChronoUnit.HOURS);
    Timestamp timestampEnd = Timestamp.from(instantEnd);
    map.put("endDateTime", timestampEnd);
    System.out.println("endDateTime : " + timestampEnd);
时间与上面相同,但在我的本地时区,因为
Timestamp.toString()
以这种方式呈现时间(这让很多人感到困惑)

问题:我可以在Java版本中使用现代API吗? 如果至少使用Java6,则可以

  • 在Java8和更高版本中,新的API是内置的
  • 在Java6和7GET中,新类的后端口(Three-Ten for)。
    Timestamp
    Instant
    之间的转换稍有不同,需要通过名为
    DateTimeUtils
    的类进行转换,但并不复杂。其余的都一样
  • 在Android上,使用Android版的ThreeTen Backport。它叫ThreeTenABP,我认为这里面有一个很好的解释

请按
ctr+k
设置代码格式。是否正确-您检查了吗?该
地图的定义是什么?为什么你先输入
,然后再输入
?(第一行很奇怪)map.put(“startDateTime”,timestadeDate);和map.put(“endDateTime”,timestadate);正在引用同一对象。你需要为endDateTime创建一个新对象。想知道你是否有可能摆脱过时的
Timestamp
类?现代的Java日期和时间API非常好用。
Instant
类是
Timestamp
的自然替代品。即使您被绑定到
时间戳
,您仍将受益于使用
即时
计算“时间戳加1小时”。感谢您的回答。此答案是正确的。从数据库中提取
java.time.Instant
对象,而不是过时的
java.sql.Timestamp
对象。增加一小时的另一种方法是使用
Duration
class
myResultSet.getObject(…,Instant.class).plus(Duration.ofHours(1))
@BasilBourque,虽然我们通常应该避免在新代码中使用
Timestamp
,但OP代码可能在已发布的遗留API上下文中工作,迁移到
java.time
类可能是不可能的。
    Instant instantStart = scheduled.getInterviewDateAndTime(); //from DB
    Map<String, Object> map = new HashMap<>();    
    map.put("eventTitle", "interview with");
    map.put("startDateTime", instantStart);
    System.out.println("startDateTime : " + instantStart);

    Instant instantEnd = instantStart.plus(1, ChronoUnit.HOURS);
    map.put("endDateTime", instantEnd);
    System.out.println("endDateTime : " + instantEnd);
startDateTime : 2017-11-29T09:15:00Z
endDateTime : 2017-11-29T10:15:00Z
    Instant instantEnd = instantStart.plus(Duration.ofHours(1));
    Timestamp timestampStart = scheduled.getInterviewDateAndTime(); //from DB
    Instant instantStart = timestampStart.toInstant();
    Map<String, Object> map = new HashMap<>();    
    map.put("eventTitle", "interview with");
    map.put("startDateTime", timestampStart);
    System.out.println("startDateTime : " + timestampStart);

    Instant instantEnd = instantStart.plus(1, ChronoUnit.HOURS);
    Timestamp timestampEnd = Timestamp.from(instantEnd);
    map.put("endDateTime", timestampEnd);
    System.out.println("endDateTime : " + timestampEnd);
startDateTime : 2017-11-29 10:15:00.0
endDateTime : 2017-11-29 11:15:00.0