我的班级中有一个Date
字段,可以有两种类型的值:有和没有时间。这样的事情:2015-01-01
和2015-01-01 12:00:00
。我想从我的日期制作格式化的字符串。我知道我可以使用SimpleDateFormat
课来做这件事,但我不知道格式。事实上,如果我的日期有时间部分,我必须使用yyyy-MM-dd HH:mm:ss
格式,如果我的日期没有时间部分,我必须使用yyyy-MM-dd
格式。我的问题是,在格式化之前是否有检查日期的时间段?
这是我的代码:
private SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
.....
private String formatDate(Date date){
//I need to something like this:
if(/* `date` has time part */){
return dateTimeFormat.format(date);
}
else{
return dateFormat.format(date);
}
}
答案 0 :(得分:2)
您无法可靠地执行此操作,因为一旦创建了Date
对象,它就会以毫秒为单位表示,其中包括特定时间。因此,您无法知道对象是如何构建的以及是否设置了特定时间。
解决方法是检查小时,分钟和秒是否设置为零。请注意,将日期解析为"yyyy-MM-dd HH:mm:ss"
的可能性很小,但所有这些值都设置为0
,因为时间确实是00:00:00
。但是,这个概率等于1 / (24 * 60 * 60) = 0.00001157407
,所以我假设你可以接受它。
答案 1 :(得分:2)
如其他答案所示,与Java捆绑在一起的旧日期时间类如java.util.Date和java.sql.Date是一团糟。由于糟糕的设计决定,他们被赶到了市场。具体来说,java.util.Date表示日期和时间,而它的子类java.sql.Date假装没有时间但实际上没有。该文档解释说,您应该忽略这种继承关系以帮助维持幻觉。不好。
整个混乱已经被Java 8及更高版本中内置的java.time框架所取代。新课程的灵感来自非常成功的Joda-Time框架,旨在作为其继承者,在概念上类似但重新设计。由JSR 310定义。由ThreeTen-Extra项目扩展。请参阅Tutorial。
新课程中有LocalDate
。这是与Java捆绑的第一个类,仅用于表示日期,没有时间或时区。要确定诸如“今天”之类的日期,您需要一个时区(ZoneId
)。例如,巴黎的新日早些时候比蒙特利尔早。 如果您需要仅限日期值,建议您在此类类别中添加成员。
LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
如果您想要日期时间,请首先考虑Instant
课程。这标志着UTC时间轴上的一个时刻。几乎总是最好用UTC进行业务逻辑和数据存储。 当您需要特定时刻而非模糊日期时,请将此类型的成员添加到您的班级。
Instant now = Instant.now();
要在期望/预期时区内向用户显示,请将时区应用于即时消息以获取ZonedDateTime
。
ZonedDateTime zdt = ZonedDateTime.ofInstant( now , ZoneId.of( "America/Montreal" ) );
我不推荐这种策略,而是直接回答你的问题,关于检测日期时间值的时间是否恰好是一天中的第一时刻...
首先你需要考虑时区。上面提到的所有这些日期时间类都以UTC中的count-from - epoch跟踪时间。旧类以毫秒为单位,新的以纳秒为单位。新旧时代是UTC 1970年的第一个时刻。因此,当您在问题中提出时,没有没有时间的日期时间。最接近的是日期时间,其时间恰好是一天中的第一时刻。似乎是你的情况(尽管我上面的讨论强烈建议你改变你的情况)。
如何确定日期时间是否包含当天的第一时刻?首先,你必须考虑时区。你想要UTC或你想要一个特定的时区,如America/Montreal
。取决于您的业务规则。
如果以java.util.Date开头,请先转换为java.time。
Instant instant = myJUDate.toInstant();
请注意,日期总是从00:00:00.0
开始。由于夏令时(DST)以及可能的其他异常,在某些地方,日期的第一个时刻是不同的wall-clock time。 java.time框架可以使用LocalDate
类及其atStartOfDay
方法确定当天的第一时刻。
因此,在确定我们关心的时区后,我们将Instant调整为ZonedTimeZone。
Instant instant = Instant.now ();
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );
接下来我们需要看看那是否是当天的第一时刻。所以我们转换为LocalDate,然后通过调用atStartOfDay
返回到另一个ZonedDateTime。将第一个ZonedDateTime与第二个ZonedDateTime进行比较,告诉我们原始版本是否确实在当天的开始。总结一下:我们正在转换 ZonedDateTime→LocalDate→ZonedDateTime 。
// Convert to LocalDate, to get start of day, to compare to above.
LocalDate localDate = zdt.toLocalDate ();
ZonedDateTime startOfDay = localDate.atStartOfDay ( zoneId );
Boolean isStartOfDay = ( zdt.isEqual ( startOfDay ) );
转储到控制台。
System.out.println ( "instant: " + instant + " for zoneId: " + zoneId + " is zdt: " + zdt + " if compared to startOfDay: " + startOfDay + " is T/F: " + isStartOfDay );
即时:2015-12-12T23:20:23.560Z for zoneId:America / Montreal is zdt:2015-12-12T18:20:23.560-05:00 [America / Montreal]如果与startOfDay相比:2015-12 -12T00:00-05:00 [America / Montreal]是T / F:false
如果您想要UTC而不是特定时区,请在上面的代码中使用常量ZoneOffset.UTC
作为ZoneId
对象。 ZoneOffset
是ZoneId
的子类。
答案 2 :(得分:1)
假设您正在使用从java.util.Date派生的java.sql.Date,则Date对象不可能没有时间值。 请注意文档: http://docs.oracle.com/javase/7/docs/api/java/sql/Date.html Date对象实例保存一个毫秒值,准确地说是当前时间与UTC时间1970年1月1日午夜之间的差异(以毫秒为单位)。
答案 3 :(得分:0)
使用Calendar
对象。日历可以为您提供Date
值的所有字段的结构化访问权限,即年,月,日,小时,分钟,秒等。这将允许您检查时间字段是否为非零。正如JB Nizet所说,时间部分可能恰好为零,在这种情况下,你会将它误解为只有日期的值。