Java Date截断时间信息

我有一个包含date和时间信息的Javadate对象。 我想写一个方法,切断时间信息,所以我只剩下date。

示例input:

2008-01-01 13:15:00 

预期产出:

 2008-01-01 00:00:00 

你有小费吗? 我试着做这样的事情:

 (timestamp / (24 * 60 * 60 * 1000)) * (24 * 60 * 60 * 1000) 

但是我遇到了这个时区的问题。

date/时间操作的推荐方法是使用Calendar对象:

 Calendar cal = Calendar.getInstance(); // locale-specific cal.setTime(dateObject); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); long time = cal.getTimeInMillis(); 

你看过Apache Commons Lang中的DateUtils truncate方法吗?

 Date truncatedDate = DateUtils.truncate(new Date(), Calendar.DATE); 

将删除时间元素。

你看过乔达吗? 这是一个容易,更直观的方式来处理date和时间。 例如,你可以在LocalDateTime和LocalDate对象之间转换(比如说)。

例如(来说明API)

 LocalDate date = new LocalDateTime(milliseconds).toLocalDate() 

此外,它还解决了date/时间格式化程序中的一些线程安全问题,强烈build议在Java中处理任何date/时间问题。

 Date date = new Date(); Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); date = cal.getTime(); 

随着乔达你可以很容易地得到预期的date。

从版本2.7开始(也许从以前的一些版本大于2.2开始),正如一位评论者指出的, toDateMidnight已经被弃用,或者被适当地命名为withTimeAtStartOfDay() ,使得方便

 DateTime.now().withTimeAtStartOfDay() 

可能。

好处添加了一个更好的方法API。

用旧版本,你可以做

 new DateTime(new Date()).toDateMidnight().toDate() 

根据现在内置于Java 8及更高版本中的java.time类,仅仅是一个快速更新。

LocalDateTime有一个truncatedTo方法,可以有效地解决你在这里讨论的问题:

 LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES) 

这将只将当前时间表示为几分钟:

 2015-03-05T11:47 

您可以使用任何ChronoUnit (或实际上任何TemporalUnit )来执行截断。

从Apache使用DateUtils,截断,如下所示:

 DateUtils.truncate(Calendar.getInstance().getTime(), Calendar.DATE); 

对于时间戳:

 timestamp -= timestamp % (24 * 60 * 60 * 1000) 

我用新的java8 API做了截断。 我面对一个奇怪的事情,但一般来说它是截断的…

 Instant instant = date.toInstant(); instant = instant.truncatedTo(ChronoUnit.DAYS); date = Date.from(instant); 

来自java.util.Date JavaDocs:

Date类表示特定的即时时间,毫秒精度

并从java.sql.Date JavaDocs:

为了符合SQL DATE的定义,由java.sql.Date实例包装的毫秒值必须通过将与实例关联的特定时区中的小时,分​​钟,秒和毫秒设置为零来“标准化” 。

所以,如果你不需要时间部分,最好的方法是使用java.sql.Date

 java.util.Date utilDate = new java.util.Date(); java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis()); 

输出是:

 java.util.Date : Thu Apr 26 16:22:53 PST 2012 java.sql.Date : 2012-04-26 

这个问题是矛盾的。 它要求一个没有时间的date,但是显示一个时间为00:00:00的例子。

乔达时间

更新: Joda-Time项目现在处于维护模式 ,团队build议迁移到java.time类。 看到我的另一个 java.time解决scheme的答案 。

如果您希望将时间设置为一天中的第一个时间,请在Joda-Time库上使用DateTime对象,并调用withTimeAtStartOfDay方法。 请注意,由于夏令时或其他exception情况,第一时刻可能不是00:00:00的时间。

使用Calendar类的set()方法将HOUR_OF_DAY, MINUTE, SECONDMILLISECOND字段设置为零。

只需clear()多余的字段。

 Calendar calendar = Calendar.getInstance(); calendar.setTime(date); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.clear(Calendar.MINUTE); calendar.clear(Calendar.SECOND); calendar.clear(Calendar.MILLISECOND); Date truncatedDate = calendar.getTime(); 

这让我非常恼火,新的“改进”的日历构造函数不会像“糟糕的”旧的date一样毫秒级的int。 然后我真的交叉,写下这个:

 long stuffYou = startTime.getTimeInMillis() % 1000; startTime.setTimeInMillis(startTime.getTimeInMillis() - stuffYou); 

我当时并没有使用“东西”这个词,但后来我发现了这样的幸福:

 startTime.set(Calendar.MILLISECOND, 0); 

但是我还是十分的交叉

可能是一个迟到的反应,但这是一个方法来做到这一行,而不使用任何库:

 new SimpleDateFormat("yyyy-MM-dd").parse(new SimpleDateFormat("yyyy-MM-dd").format(YOUR_TIMESTAMP)) 

对于使用日历的所有答案,您应该像这样使用它

 public static Date truncateDate(Date date) { Calendar c = Calendar.getInstance(); c.setTime(date); c.set(Calendar.HOUR_OF_DAY, c.getActualMinimum(Calendar.HOUR_OF_DAY)); c.set(Calendar.MINUTE, c.getActualMinimum(Calendar.MINUTE)); c.set(Calendar.SECOND, c.getActualMinimum(Calendar.SECOND)); c.set(Calendar.MILLISECOND, c.getActualMinimum(Calendar.MILLISECOND)); return c.getTime(); } 

但我更喜欢这个:

 public static Date truncateDate(Date date) { return new java.sql.Date(date.getTime()); } 

TL;博士

 LocalDateTime.parse( // Lacking an offset or time zone, parse as a `LocalDateTime`. *Not* a specific moment in time. "2008-01-01 13:15:00".replace( " " , "T" ) // Alter input string to comply with ISO 8601 standard format. ) .toLocalDate() // Extract a date-only value. .atStartOfDay( // Do not assume the day starts at 00:00:00. Let class determine start-of-day. ZoneId.of( "Europe/Paris" ) // Determining a specific start-of-day requires a time zone. ) // Result is a `ZonedDateTime` object. At this point we have a specific moment in time, a point on the timeline. 

细节

其他答案是正确的,但使用现在由java.time框架过时的旧date时间类。

java.time

java.time框架内置于Java 8及更高版本中。 许多java.timefunction被移植到Java 6&7( ThreeTen-Backport ),并进一步适用于Android( ThreeTenABP )。

首先改变inputstring以符合ISO 8601格式的规范版本。 在java.time类中默认使用标准的ISO 8601格式来parsing/生成表示date时间值的string。 我们需要用T来replace那个SPACE。

 String input = "2008-01-01 13:15:00".replace( " " , "T" ); // → 2008-01-01T13:15:00 

现在我们可以将其parsing为LocalDateTime ,其中“Local”表示没有特定的地方。 input缺less从UTC或时区信息的任何偏移量 。

 LocalDateTime ldt = LocalDateTime.parse( input ); 

ldt.toString()… 2008-01-01T13:15:00

如果您不关心时间或时区,则转换为LocalDate

 LocalDate ld = ldt.toLocalDate(); 

ld.toString()… 2008-01-01

第一天的一刻

如果您希望将时间设置为一天中的第一个时间,请使用ZonedDateTime类,然后转换为LocalDate对象以调用其atStartOfDay方法。 请注意,由于夏令时或其他exception情况,第一时刻可能不是00:00:00的时间。

时区是至关重要的,因为在任何特定的时刻,date在世界范围内随区域而变化。 例如,在巴黎午夜过后的几分钟,对巴黎人来说是新的一天,但对于加拿大人来说,在蒙特利尔仍然是“昨天”。

 ZoneId zoneId = ZoneId.of( "America/Montreal" ); ZonedDateTime zdt = ldt.atZone( zoneId ); LocalDate ldFromZdt = zdt.toLocalDate(); ZonedDateTime zdtStartOfDay = ldFromZdt.atStartOfDay( zoneId ); 

zdtStartOfDay.toString()… 2008-01-01T00:00:00-05:00 [美国/蒙特利尔]

世界标准时间

要通过UTC时区的镜头看到这一刻,请提取Instant对象。 ZonedDateTimeInstant都将表示时间轴上的同一时刻,但performance为两个不同的挂钟时间 。

Instant是java.time中的基本构build块类,通常按照UTC定义。 经常使用这个类,因为通常应该使用UTC来进行业务逻辑,数据存储和数据交换。

 Instant instant = zdtStartOfDay.toInstant(); 

instant.toString()… 2008-01-01T05:00:00Z

我们看到的是凌晨5点而不是午夜。 在标准格式中, Z最后是Zulu缩写,意思是“UTC”。

从版本2.0开始, Joda-Time可以使用LocalDate.toDate()

只是

 // someDatetime is whatever java.util.Date you have. Date someDay = new LocalDate(someDatetime).toDate();