最近,我尝试将当前日期的毫秒表示用作数据库(Realm)的主键。
我可以将日期作为字符串存储并存储,但由于我需要对大量数据执行快速升序搜索,因此我决定以毫秒格式存储数据。
为实现这一点,我按照以下步骤操作:
1)初始化GregorianCalendar实例并传递当前日期
Calendar c = new GregorianCalendar();
c.setTime(new Date());
2)设定时间恰好与当天的午夜相匹配
c.set(Calendar.HOUR_OF_DAY,0);
c.set(Calendar.MINUTE,0);
c.set(Calendar.SECOND,0);
c.set(Calendar.MILLISECOND,0);
3)将结果转换为毫秒
c.getTime().getTime()
后来我通过将对象插入数据库来测试它。 以下是日志输出。我几次计算了相同的日期,所有这些都是上面的代码,没有任何变化。
01-03 06:59:38.607 16256-16256/com.example.bizarre.bindaccess D/Day: Long: 1 422 528 534 032 Date: 29.01.15
01-03 06:59:38.611 16256-16256/com.example.bizarre.bindaccess D/Day: Long: 1 422 528 647 420 Date: 29.01.15
01-03 06:59:38.611 16256-16256/com.example.bizarre.bindaccess D/Day: Long: 1 422 528 669 794 Date: 29.01.15
01-03 06:59:38.611 16256-16256/com.example.bizarre.bindaccess D/Day: Long: 1 422 528 707 566 Date: 29.01.15
01-03 06:59:38.615 16256-16256/com.example.bizarre.bindaccess D/Day: Long: 1 422 532 686 557 Date: 29.01.15
01-03 06:59:38.615 16256-16256/com.example.bizarre.bindaccess D/Day: Long: 1 422 532 726 052 Date: 29.01.15
01-03 06:59:38.615 16256-16256/com.example.bizarre.bindaccess D/Day: Long: 1 422 532 754 147 Date: 29.01.15
尽管我的行动为零小时,分钟,秒和毫秒,并且每次我得到的午夜值都会以毫秒计算,但我得到的价值会略有不同。
我的建议是:
1)这取决于设备时间方案。
2)它本身与android有关。
3)麻烦就在我身边。
如果有人可以帮助我,我会很高兴。
P.S。我还使用了一个网站http://www.fileformat.info/tip/java/date2millis.htm来获得29.01.15的millis,结果是1 422 489 600 000。
已更新#1。 1)所有插件都在同一设备上,当地时区没有改变,所以环境不受影响。 2)正如我上面所说,也许不清楚 - 我在类型为long的类字段中以 millis 保存数据。无论如何,这个领域也不受影响。
已更新#2。实际上,我的问题是:“我遇到的行为怎么解释?”。但由于它可能过于宽泛或不清楚,我将重点放在我最初想要实现的目标上 - “如何以一致的毫秒值(类型为0)获取本地(设备上)时区的当前日期长)吗“
答案 0 :(得分:3)
Instant.ofEpochMilli( 1_422_528_534_032L )
.truncatedTo( ChronoUnit.DAYS )
2015-01-29T00:00:00Z
虽然不清楚,但我会将您的问题解释为:如何从一个从纪元开始计数并将其更改为代表该日期的00:00:00时间? / em>的
“如何以一致的毫秒值(长类型)的形式在本地(设备上)时区获取当前日期?”
来自时代的计数几乎总是在UTC(否则是麻烦和近乎疯狂的恕我直言)。因此,您可能会混淆两个不同的方面:(a)从UTC开始计算时代(Instant
),以及(b)那个非常相同的时刻,但通过使用的挂钟时间的镜头看到特定地区的人(ZonedDateTime
)。
Big big 提示:作为程序员,学会用UTC思考和工作。您在UTC中记录和存储/交换数据也是如此。 将UTC视为 The One True Time™ ,所有其他仅仅是变体。
另一个提示:不花费你宝贵的时间和精力去思考遗留的Date
/ Calendar
类。它们是一个可怜的混乱,我们现在可以随着行业领先的java.time类的到来而愉快地放弃。
您正在使用现在由java.time类取代的麻烦的旧日期时间类。请参阅下面的Android。
请务必将您的纪元数字处理为64位long
/ Long
,而不是32位int
/ Integer
。
long input = 1_422_528_534_032L ; // Numeric literal for a `long` in modern Java.
Instant
类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。
Instant instant = Instant.ofEpochMilli( input ) ;
instant.toString():2015-01-29T10:48:54.032Z
要有效地将时间清除为00:00:00,我们可以通过指定ChronoUnit.DAYS
来截断。
Instant instantTruncated = instant.truncatedTo( ChronoUnit.DAYS ) ;
instantTruncated.toString():2015-01-29T00:00:00Z
如果你想比较,你可以提取一个从纪元开始的计数。
long millisSinceEpoch = instantTruncated.toEpochMilli() ;
1422489600000
为了好玩,让我们计算三角洲。
long delta = ( input - millisSinceEpoch ) ;
38934032
另外,我们将该增量表示为Duration
,其中toString
方法以标准ISO 8601格式生成字符串。
Duration d = Duration.ofMillis( delta ) ;
d.toString():PT10H48M54.032S
查看所有这些code run live at IdeOne.com。
如果你想看到同一时刻,时间线上的点,通过特定区域内人们看到的挂钟时间的镜头,应用时区(ZoneId
)来获得{ {3}}对象。
ZoneId z = ZoneId.of( "Europe/Sofia" ) ; // Or "Asia/Kolkata", whatever.
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment in history, but viewed using the wall-clock time in some particular region.
顺便说一下,虽然UTC的开始时间总是00:00:00,但 在其他时区总是如此。由于夏令时(DST)和其他异常,某些区域中的某些日期可能会在另一个时间点开始,例如01:00:00。让java.time确定一天的开始:
ZonedDateTime zdt = LocalDate.of( 2015 , Month.JANUARY , 29 ).atStartOfDay( ZoneId.of( "Asia/Gaza" ) ) ;
long millisFromEpoch = zdt.toInstant().toEpochMilli() ; // Generate a count-from-epoch of UTC in milliseconds.
ZonedDateTime
框架内置于Java 8及更高版本中。这些类取代了麻烦的旧java.time日期时间类,例如legacy,java.util.Date
和& Calendar
现在位于SimpleDateFormat
的Joda-Time项目建议迁移到maintenance mode类。
要了解详情,请参阅java.time。并搜索Stack Overflow以获取许多示例和解释。规范是Oracle Tutorial。
从哪里获取java.time类?