获取Java日期或日历的Time组件

是否有一种简单或优雅的方式只能抓取Java Date(或日历)的一天中的时间(小时/分钟/秒/毫秒),这对我来说无关紧要? 我正在寻找一个很好的方法来分别考虑日期(年/月/日)和时间部分,但据我所知,我坚持分别访问每个字段。

我知道我可以编写自己的方法来单独抓取我感兴趣的字段,但我会将其作为静态实用程序方法,这很难看。 另外,我知道Date和Calendar对象具有毫秒精度,但在任何一种情况下我都没有看到访问毫秒组件的方法。


编辑:我不清楚这一点:使用Date :: getTime()或Calendar :: getTimeInMillis之一对我来说并不是非常有用,因为那些返回自纪元以来的毫秒数(由该日期或日历表示) ,实际上并没有将时间与其他信息分开。

@Jherico的答案是最接近的事情,我想,但绝对是我仍需要采用我自己编写的方法。 这不是我想要的,因为它仍然包括返回毫秒值的小时,分​​钟和秒 – 尽管我可能会使它适用于我的目的。

我仍然认为每个组件都是独立的 ,尽管它们当然不是。 您可以将时间写为自任意参考日期以来的毫秒数,或者您可以写出与year/month/day hours:minutes:seconds.milliseconds完全相同的时间year/month/day hours:minutes:seconds.millisecondsyear/month/day hours:minutes:seconds.milliseconds

这不是用于显示目的。 我知道如何使用DateFormat制作漂亮的日期字符串。


编辑2:我原来的问题来自我发现自己编写的一小组实用函数 – 例如:

  • 检查两个Date是否代表同一天的日期时间;
  • 检查日期是否在由其他两个日期指定的范围内,但有时检查包含,有时不检查,具体取决于时间组件。

Joda Time有这种function吗?


编辑3: @ Jon关于我的第二个要求的问题,只是为了澄清:第二个要求是使用我的日期有时代表整天的结果 – 时间组件根本不重要 – 有时代表日期时间(这是IMO,包含year/month/day hours:minutes:seconds:...的最准确的单词hours:minutes:seconds:... )。

当Date表示整天时,其时间部分为零(例如Date的“time component”是午夜),但语义规定范围检查在结束日期包含。 因为我只是将此检查留给Date :: before和Date :: after,所以我必须在结束日期添加1天 – 因此当Date的时间组件为零时的特殊shell。

希望没有让事情变得不那么清楚。

好的,我知道这是一个可预测的答案,但是…使用Joda Time 。 它有“日期”,“瞬间”,“一天中的时间”等单独表示。它是一个比内置类IMO更丰富的API和更普通的API。

如果这是你感兴趣的日期/时间操作的唯一一点,那么它可能有点过分……但是如果你使用内置的日期/时间API来做任何重要事情,我强烈建议你移动尽快离开Joda到Joda。

顺便说一句,你应该考虑你感兴趣的时区。 Calendar有一个相关的时区,但是Date没有(它只代表一个时刻,以毫秒为单位,从Unix纪元开始计算)。

提取当天的时间部分应该是当你除以每天的毫秒数时得到剩余的毫秒数。

 long MILLIS_PER_DAY = 24 * 60 * 60 * 1000; Date now = Calendar.getInstance().getTime(); long timePortion = now.getTime() % MILLIS_PER_DAY; 

或者,考虑使用joda-time,一个function更全面的时间库。

要回答其中的一部分,访问毫秒组件就像这样:

 long mill = Calendar.getInstance().getTime(); 

我不知道你想要具体做什么,但如果是文本输出你可以使用java.text.SimpleDateFormat类。

您可以在Calendar对象上调用getTimeInMillis()函数以获得以毫秒为单位的时间。 您可以在日历对象上调用get(Calendar.MILLISECOND)以获取秒的毫秒数。 如果要显示Date或Calendar对象的时间,请使用DateFormat类。 示例:DateFormat.getTimeInstance()。format(now)。 您还可以使用SimpleDateFormat类。

要使用Joda-Time获得时间,请使用org.joda.time.LocalTime类,如此问题中所述, Joda-Time,Time without date 。

至于仅在有效忽略时间的情况下比较日期,在Joda-Time中调用每个DateTime实例上的withTimeAtStartOfDay()方法来设置相同的时间值。 下面是一些使用Joda-Time 2.3的示例代码,类似于我今天在另一个答案中发布的代码。

  // © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so. // Joda-Time - The popular alternative to Sun/Oracle's notoriously bad date, time, and calendar classes bundled with Java 7 and earlier. // http://www.joda.org/joda-time/ // Joda-Time will become outmoded by the JSR 310 Date and Time API introduced in Java 8. // JSR 310 was inspired by Joda-Time but is not directly based on it. // http://jcp.org/en/jsr/detail?id=310 // By default, Joda-Time produces strings in the standard ISO 8601 format. // https://en.wikipedia.org/wiki/ISO_8601 // Capture one moment in time. org.joda.time.DateTime now = new org.joda.time.DateTime(); System.out.println("Now: " + now); // Calculate approximately same time yesterday. org.joda.time.DateTime yesterday = now.minusDays(1); System.out.println("Yesterday: " + yesterday); // Compare dates. A DateTime includes time (hence the name). // So effectively eliminate the time by setting to start of day. Boolean isTodaySameDateAsYesterday = now.withTimeAtStartOfDay().isEqual(yesterday.withTimeAtStartOfDay()); System.out.println("Is today same date as yesterday: " + isTodaySameDateAsYesterday); org.joda.time.DateTime halloweenInUnitedStates = new org.joda.time.DateTime(2013, 10, 31, 0, 0); Boolean isFirstMomentSameDateAsHalloween = now.withTimeAtStartOfDay().isEqual(halloweenInUnitedStates.withTimeAtStartOfDay()); System.out.println("Is now the same date as Halloween in the US: " + isFirstMomentSameDateAsHalloween); 

如果你担心的是将它放入String中进行显示或保存,那么只需创建一个只显示时间部分的SimpleDateFormat,就像新的SimpleDateFormat(“HH:mm:ss”)一样。 当然,日期仍在Date对象中,但您并不在意。

如果你想对它进行算术运算,比如取两个Date对象并找出它们相隔多少秒而忽略日期部分,那么“2009-09-01 11:00:00”减去“1941-12-07 09 :00:00“等于2小时,然后我认为你需要使用像Jherico这样的解决方案:获取很长时间并将模块放置1天。

你为什么要把它们分开? 如果你的意思是用时间部分做任何算术,你很快就会遇到麻烦。 如果你在晚上11:59退出并添加一分钟,现在你的时间和日期是分开的,你已经搞砸了自己 – 你的时间和日期都不正确。

如果你只想显示它们,那么应用各种简单的日期格式应该可以得到你想要的。

如果你想操纵这个日期,我建议你得到很长的价值观,并以此为基础。 在任何时候你都可以使用那么长的时间并应用一种格式来获得非常容易显示的分钟/小时/秒。

但我只是有点担心分别操纵日期和时间的概念,似乎打开了一个可以做到的蠕虫。 (甚至没有提到时区问题!)。

我很确定这就是为什么Java没有简单的方法来做到这一点。

在下面找到一个采用Joda Time并支持时区的解决方案。 因此,您将获得JVM中当前配置的时区中的日期和时间(into currentDatecurrentTime )。

请注意,Joda Time不支持闰秒 。 所以,你可以减去26或27秒的真实价值。 这可能只会在未来50年内解决,届时积累的误差将接近1分钟,人们将开始关心它。

另见: https : //en.wikipedia.org/wiki/Leap_second

 /** * This class splits the current date/time (now!) and an informed date/time into their components: *  * 
  • schedulable: if the informed date/time is in the present (now!) or in future.
  • *
  • informedDate: the date (only) part of the informed date/time
  • *
  • informedTime: the time (only) part of the informed date/time
  • *
  • currentDate: the date (only) part of the current date/time (now!)
  • *
  • currentTime: the time (only) part of the current date/time (now!)
  • *
    */ public class ScheduleDateTime { public final boolean schedulable; public final long millis; public final java.util.Date informedDate; public final java.util.Date informedTime; public final java.util.Date currentDate; public final java.util.Date currentTime; public ScheduleDateTime(long millis) { final long now = System.currentTimeMillis(); this.schedulable = (millis > -1L) && (millis >= now); final TimeZoneUtils tz = new TimeZoneUtils(); final java.util.Date dmillis = new java.util.Date( (millis > -1L) ? millis : now ); final java.time.ZonedDateTime zdtmillis = java.time.ZonedDateTime.ofInstant(dmillis.toInstant(), java.time.ZoneId.systemDefault()); final java.util.Date zdmillis = java.util.Date.from(tz.tzdate(zdtmillis)); final java.util.Date ztmillis = new java.util.Date(tz.tztime(zdtmillis)); final java.util.Date dnow = new java.util.Date(now); final java.time.ZonedDateTime zdtnow = java.time.ZonedDateTime.ofInstant(dnow.toInstant(), java.time.ZoneId.systemDefault()); final java.util.Date zdnow = java.util.Date.from(tz.tzdate(zdtnow)); final java.util.Date ztnow = new java.util.Date(tz.tztime(zdtnow)); this.millis = millis; this.informedDate = zdmillis; this.informedTime = ztmillis; this.currentDate = zdnow; this.currentTime = ztnow; } } public class TimeZoneUtils { public java.time.Instant tzdate() { final java.time.ZonedDateTime zdtime = java.time.ZonedDateTime.now(); return tzdate(zdtime); } public java.time.Instant tzdate(java.time.ZonedDateTime zdtime) { final java.time.ZonedDateTime zddate = zdtime.truncatedTo(java.time.temporal.ChronoUnit.DAYS); final java.time.Instant instant = zddate.toInstant(); return instant; } public long tztime() { final java.time.ZonedDateTime zdtime = java.time.ZonedDateTime.now(); return tztime(zdtime); } public long tztime(java.time.ZonedDateTime zdtime) { final java.time.ZonedDateTime zddate = zdtime.truncatedTo(java.time.temporal.ChronoUnit.DAYS); final long millis = zddate.until(zdtime, java.time.temporal.ChronoUnit.MILLIS); return millis; } }

    TL;博士

     LocalTime lt = myUtilDate.toInstant().atZone( ZoneId.of( "America/Montreal" ) ).toLocalTime() ; 

    避免旧的日期时间类

    您正在使用旧的旧日期时间类。 它们很麻烦,令人困惑; 避免他们。

    而是使用java.time类。 这些取代了旧类以及Joda-Time库。

    兑换

    java.util.Date转换为Instant

    Instant类表示UTC时间轴上的一个时刻,分辨率为纳秒 。

     Instant instant = myUtilDate.toInstant(); 

    时区

    应用时区。 时区至关重要。 对于任何给定的时刻,日期在全球范围内因地区而异。 例如,法国巴黎午夜过后几分钟是新的一天,同时也是魁北克蒙特利尔的“昨天”。

    应用ZoneId以获取ZonedDateTime对象。

     ZoneId z = ZoneId.of( "America/Montreal" ); ZonedDateTime zdt = instant.atZone( z ); 

    Local…类型

    LocalDate类表示没有时间且没有时区的仅日期值。 同样, LocalTime表示没有日期且没有时区的时间。 您可以将这些视为两个组件,它们与ZoneId一起构成ZonedDateTime 。 您可以从ZonedDateTime提取这些ZonedDateTime

     LocalDate ld = zdt.toLocalDate(); LocalTime lt = zdt.toLocalTime(); 

    字符串

    如果您的目标仅仅是为用户生成字符串,则不需要Local…类型。 而是使用DateTimeFormatter生成仅表示日期部分或时间部分的字符串。 该类足够智能,可以在生成String时自动进行本地化 。

    指定Locale以确定(a)用于翻译日期名称,月份名称等的人类语言,以及(b)用于确定缩写,大小写,标点符号等问题的文化规范。

     Locale l = Locale.CANADA_FRENCH ; // Or Locale.US, Locale.ITALY, etc. DateTimeFormatter fDate = DateTimeFormatter.ofLocalizedDate( FormatStyle.MEDIUM ).withLocale( locale ); String outputDate = zdt.format( fDate ); DateTimeFormatter fTime = DateTimeFormatter.ofLocalizedTime( FormatStyle.MEDIUM ).withLocale( locale ); String outputTime = zdt.format( fTime ); 

    关于java.time

    java.time框架内置于Java 8及更高版本中。 这些类取代了旧的麻烦的日期时间类,如java.util.Date.Calendarjava.text.SimpleDateFormat

    现在处于维护模式的Joda-Time项目建议迁移到java.time。

    要了解更多信息,请参阅Oracle教程 。 并搜索Stack Overflow以获取许多示例和解释。

    许多java.timefunction在ThreeTen- Backport中反向移植到Java 6和7,并在ThreeTenABP中进一步适应Android (请参阅如何使用… )。

    ThreeTen-Extra项目使用其他类扩展了java.time。 该项目是未来可能添加到java.time的试验场。

    使用Calendar API –

    方案1-

     Calendar c = Calendar.getInstance(); String timeComp = c.get(Calendar.HOUR_OF_DAY)+":"+c.get(Calendar.MINUTE)+":"+c.get(Calendar.SECOND)+":"+c.get(Calendar.MILLISECOND); System.out.println(timeComp); 

    输出 – 13:24:54:212

    溶液2-

     SimpleDateFormat time_format = new SimpleDateFormat("HH:mm:ss.SSS"); String timeComp = time_format.format(Calendar.getInstance().getTime()); 

    输出 – 15:57:25.518