Java保留时间的差异(以毫秒为单位)

时间:2018-07-07 00:24:56

标签: java mongodb datetime milliseconds

我正在尝试使用mongodb来获取一些带有日期字段的记录,下面显示了示例记录,并希望将使用jayway jsonpath解析的日期字段转换为java.util.Date长整数。转换后的长整数与原始整数不匹配。请帮忙。

测试人员集合中的样本记录:

{
    "_id" : ObjectId("5b3fe6f91e618afb473dc644"),
    "dateField" : ISODate("2018-07-06T15:46:55.819Z")
}

使用jongo获取记录的Java代码如下:

List<Tester> list=  jongo.runCommand("{aggregate : 'tester',pipeline:[],cursor : {batchSize :10}}")
          .field("cursor")
          .as(Tester.class);

for(Tester t : list)
{
    System.out.println("dateField test: : : : "+t.getDateField()+" : : : : "+t.getDateField().getTime());

    // Output is perfectly fine : dateField test: : : : Fri Jul 06 21:16:55 IST 2018 : : : : 1530892015819


    Gson gson = new Gson();
    String str = gson.toJson(t);
    DocumentContext docCtx = JsonPath.parse(str);
    JsonPath jsonPath = JsonPath.compile("$.dateField");
    Object obj = docCtx.read(jsonPath);

    System.out.println(obj);
    //After parsing with jsonPath the date is retained - Jul 6, 2018 9:16:55 PM
    SimpleDateFormat format = new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aaa");
    Date d = format.parse(obj.toString());
    System.out.println(d + " : : : " + d.getTime());
    //Fri Jul 06 21:16:55 IST 2018 : : : 1530892015000 - Time is not retained       
}

预期: t.getDateField()。getTime()==== d.getTime()

请帮助

致谢

克里斯

2 个答案:

答案 0 :(得分:2)

tl; dr

  • 您的格式设置模式省略了小数秒,因此输出中没有毫秒。
  • 您正在使用过时的日期时间类。改用 java.time

示例:

Instant                                 // Represent a moment in UTC, with a resolution as fine as nanoseconds.
.parse( "2018-07-06T15:46:55.819Z" )    // Parse a string in standard ISO 8601 format. The `Z` on the end means UTC, pronounced “Zulu”.
.atZone( ZoneId.of( "Asia/Kolkata" ) )  // Adjust from UTC to a desired time zone. Same moment, same point on the timeline, different wall-clock time. Returns a `ZonedDateTime` object.
.toString()                             // Generate a String in standard ISO 8601 format. Represents the moment in our `ZonedDateTime` object.

从旧式java.util.Date类转换为现代java.time.Instant,然后再次返回。废话范例:

java.util.Date.from(            // Convert from modern `Instant` to legacy `Date`. 
    myJavaUtilDate.toInstant()  // Convert from legacy `Date` to modern `Instant`.
)

java.time

您正在使用非常麻烦的旧日期时间类:DateSimpleDateFormat。几年前,这些被现代的 java.time 类所取代。

您的输入2018-07-06T15:46:55.819Z为标准ISO 8601格式。解析或生成字符串时, java.time 类默认使用ISO 8601格式。因此,无需指定格式设置模式。

最后的Z发音为Zulu,表示UTC。 Instant类代表UTC的时刻。

Instant instant = Instant.parse( "2018-07-06T15:46:55.819Z" ) ; 

生成ISO 8601格式的输出字符串。

String output = instant.toString() ;
  

2018-07-06T15:46:55.819Z

您的代码忽略了时区的关键问题。与其隐式依赖JVM当前的默认时区,不如使用ZoneId进行显式显示,即使它是ZoneId.systemDefault()

continent/region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用3-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。例如,您的IST可能表示爱尔兰标准时间印度标准时间伊朗标准时间或其他名称。

从UTC调整为特定时区后,我们在时间轴上仍具有相同的时刻和相同的时间点。只有挂钟时间不同。

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;  // Or `ZoneId.systemDefault()`.
ZonedDateTime zdt = instant.atZone( z ) ; // Adjust from UTC to a specific time zone. 

生成一个扩展为ISO 8601格式的输出字符串,以将时区名称附加在方括号中。

String output = zdt.toString() ;
  

2018-07-06T21:16:55.819 + 05:30 [亚洲/加尔各答]

请注意,小数秒(毫秒)仍保持不变。

转换

由于尚未更新为支持 java.time 的旧代码,也许您必须与java.util.Date接口(您的问题尚不清楚)。

您会发现方便的转换方法,将新方法添加到旧类中。

java.util.Datejava.time.Instant

Instant myInstant = myJavaUtilDate.toInstant() ;

按上述步骤进行。调整到所需的时区,并生成一个String

从现代Instant类到传统类Date的另一方向。

java.util.Date myDate = java.util.Date.from( myInstant ) ;

不可变的对象

java.time 类被设计为thread-safe,并使用immutable objects模式。请注意,上面的代码如何根据原始值生成新对象,而不是更改(“变异”)原始对象。


关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

目前位于Joda-Timemaintenance 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中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

答案 1 :(得分:1)

new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aaa");

您将舍弃输入的毫秒部分,这将导致您看到的完全不同。改用它:

new SimpleDateFormat("MMM dd, yyyy hh:mm:ss.SSS aaa");
                                           ^^^^