Answers:
该建议的方式做日期/时间操作是使用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截断方法?
Date truncatedDate = DateUtils.truncate(new Date(), Calendar.DATE);
将删除时间元素。
你看乔达了吗?这是一种处理日期和时间的更容易,更直观的方法。例如,您可以在(例如)LocalDateTime和LocalDate对象之间轻松转换。
例如(以说明API)
LocalDate date = new LocalDateTime(milliseconds).toLocalDate()
另外,它解决了日期/时间格式化程序的一些线程安全问题,强烈建议在Java中处理任何日期/时间问题。
根据Java 8及更高版本中内置的java.time类进行快速更新。
LocalDateTime
有一种truncatedTo
方法可以有效解决您在此处所说的问题:
LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES)
这将仅将当前时间表示为分钟:
2015-03-05T11:47
您可以使用小于DAYS 的ChronoUnit
(或TemporalUnit
)来执行截断(因为截断仅应用于LocalDateTime的时间部分,而不应用于日期部分)。
使用Joda,您可以轻松获得预期的日期。
如评论者所述,从2.7版开始(可能是从2.2以前的某个版本开始的),toDateMidnight
已被赞成或以适当的名称使用withTimeAtStartOfDay()
,以方便使用。
DateTime.now().withTimeAtStartOfDay()
可能。
增加了更好的API的好处。
使用旧版本,您可以
new DateTime(new Date()).toDateMidnight().toDate()
withTimeAtStartOfDay
。
toLocalDate
用来获取甚至没有时间成分的对象。
将Apache的DateUtils与truncate一起使用,如下所示:
DateUtils.truncate(Calendar.getInstance().getTime(), Calendar.DATE);
对于时间戳:
timestamp -= timestamp % (24 * 60 * 60 * 1000)
从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
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.
.toString() // Generate a String in standard ISO 8601 format, wisely extended to append the name of the time zone in square brackets.
2008-01-01T00:00 + 01:00 [欧洲/巴黎]
要生成所需格式的字符串,请传递DateTimeFormatter
。
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.
.format( // Generate a String representing the object’s value.
DateTimeFormatter.ISO_LOCAL_DATE_TIME // Built-in predefined formatter close to what you want.
)
.replace( "T" , " " ) // Replace the standard’s use of a 'T' in the middle with your desired SPACE character.
2008-01-01 00:00:00
其他答案是正确的,但是使用java.time框架现在已过时的旧日期时间类。
java.time框架内置于Java 8及更高版本中。许多java.time功能都向后移植到Java 6和7(ThreeTen-Backport),并进一步适应了Android(ThreeTenABP)。
首先,更改输入字符串以符合ISO 8601格式的规范版本。缺省情况下,java.time类中使用标准ISO 8601格式来解析/生成表示日期时间值的字符串。我们需要将中间的SPACE替换为T
。
String input = "2008-01-01 13:15:00".replace( " " , "T" ); // → 2008-01-01T13:15:00
现在我们可以将其解析为LocalDateTime
,其中“ Local”表示没有特定的位置。输入缺少任何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
方法。请注意,00:00:00
由于夏时制或其他异常情况,第一刻可能不是时间。
时区至关重要,因为在任何给定的时刻,日期在世界各地都会有所不同。例如,巴黎人午夜过后的片刻对巴黎人来说是新的一天,但对于加拿大人来说,在蒙特利尔仍然是“昨天”。
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
对象。无论是ZonedDateTime
和Instant
将代表时间轴上同一时刻,但显示为两个不同的挂钟时间。
An Instant
是java.time中的基本构建块类,根据定义始终是UTC。经常使用此类,因为通常应该在UTC中进行业务逻辑,数据存储和数据交换。
Instant instant = zdtStartOfDay.toInstant();
Instant.toString()…2008-01-01T05:00:00Z
我们看到的是凌晨5点,而不是午夜。在标准格式中,Z
结尾处的缩写Zulu
,表示“ UTC”。
该java.time框架是建立在Java 8和更高版本。这些类取代麻烦的老传统日期时间类,如java.util.Date
,Calendar
,和SimpleDateFormat
。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC驱动程序。不需要字符串,不需要类。java.sql.*
在哪里获取java.time类?
该ThreeTen-额外项目与其他类扩展java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。你可能在这里找到一些有用的类,比如Interval
,YearWeek
,YearQuarter
,和更多。
只是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();
在Java 8中,更好的选择是使用truncatedTo
方法LocalDateTime
,例如:
LocalDateTime.now().truncatedTo(ChronoUnit.DAYS)
calendar.clear(Calendar.HOUR_OF_DAY);
无法清除时间。@cletus的解决方案工作正常。
我修复了这样的问题(在北京东部时间八区):
private Date getTruncatedDate(Date d) {
if (d == null) {
return null;
}
long h = 60 * 60 * 1000L;
long dateStamp = d.getTime() - (d.getTime() + 8 * h) % (24 * h);
return new Date(dateStamp);
}
首先,您应该清楚什么是时间戳。时间戳记是格林尼治标准时间1970年1月1日00:00:00(与UTC相同)或夏令时1970年1月1日08:00:00到现在的总毫秒数。
请记住:时间戳记与时区无关。
因此,在不同的时区使用以下语句可以获得相同的结果:
System.out.println(new Date().getTime());
和
System.out.println(new Date(0));
在不同的时区中打印不同的时间信息:如果将您的pc时区设置为UTC,则会得到
Thu Jan 01 00:00:00 UTC 1970
但是,如果您将时区设置为(UTC +8:00)北京,重庆,香港,乌鲁木齐,则会得到:
Thu Jan 01 08:00:00 CST 1970
Java获取时间戳,然后根据时区显示日期和时间信息。
为了介绍Java如何在不同时区显示日期和时间信息,如何转换时间信息很容易。您应该获取时间戳记,并在切断时间信息时将时区考虑在内。然后,您可以使用剪切的时间戳创建一个新的Date对象(我们可以将其称为date stamp),java在显示日期信息时将补偿时区。
与东部八区(北京时间)一样,北京时间比格林尼治标准时间早8小时,因此在进行模运算时应减去8小时。也就是说,您应该首先获取GMT时间,然后Java将根据您的PC的时区设置增加8个小时的显示时间。
时区问题晦涩难懂,也困扰了我很长时间。现在我说清楚了。希望会有所帮助。
2018-01-04以下方法也适用。
private Date getTruncatedDate2(Date d) {
Calendar cal = Calendar.getInstance(); // locale-specific
cal.setTime(d);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime();
}
您可以这样做以避免时区问题:
public static Date truncDate(Date date) {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
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);
return cal.getTime();
}
尽管Java Date
对象是时间戳值,但是在截断过程中,它将被转换为本地时区,因此,如果您期望UTC时区的值,那么您将获得令人惊讶的值。
Calendar
和Date
类成为遗留年前的java.time在Java中8和更高版本实现JSR 310班。建议在2018年使用它们是不好的建议。
随着乔达时间从2.0版本开始,你可以使用LocalDate.toDate()
。
只是
// someDatetime is whatever java.util.Date you have.
Date someDay = new LocalDate(someDatetime).toDate();
a Java Date object
我使用的java.util.Date
。而且,尽管他不能帮助使用以外的其他语言,但这并不能说明他的时区如何与java.util.Date产生问题(何时?在哪里?)Date
。
对于使用日历的所有答案,您应该这样使用它
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());
}
java.sql.Date
班假装代表日期的唯一价值,但实际上确实有一个时间的日调整UTC时区。因此,这不是真正适合该问题的解决方案。
如果您使用的是Java 8+,这是一种无需时间即可获取日期的简单方法:使用java.time.LocalDate类型而不是Date。
LocalDate now = LocalDate.now();
System.out.println(now.toString());
输出:
2019-05-30
https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html
LocalDate
对于大多数目的而言,使用是个好主意,但目前尚不清楚如何将其与问题输入配合使用2008-01-01 13:15:00
。