我在Scala中使用Java的java.util.Date
类,想要比较Date
对象和当前时间。我知道我可以使用getTime()来计算delta:
(new java.util.Date()).getTime() - oldDate.getTime()
然而,这只留给我一个代表毫秒的long
。是否有更简单,更好的方式来获得时间增量?
不幸的是,JDK Date
API非常糟糕。我推荐使用Joda Time library。
Joda Time有一个时间Interval的概念:
Interval interval = new Interval(oldTime, new Instant());
编辑:顺便说一下,Joda有两个概念:Interval
用于表示两个时间之间的时间间隔(表示上午8点到上午10点之间的时间),以及表示没有实际时间边界的时间长度的Duration
(例如代表两个小时) !)
如果您只关心时间比较,大多数Date
实现(包括JDK)实现Comparable
接口,允许您使用Comparable.compareTo()
您可以通过多种方式找到日期和时间之间的差异。我所知道的最简单的方法之一是:
Calendar calendar1 = Calendar.getInstance();
Calendar calendar2 = Calendar.getInstance();
calendar1.set(2012, 04, 02);
calendar2.set(2012, 04, 04);
long milsecs1= calendar1.getTimeInMillis();
long milsecs2 = calendar2.getTimeInMillis();
long diff = milsecs2 - milsecs1;
long dsecs = diff / 1000;
long dminutes = diff / (60 * 1000);
long dhours = diff / (60 * 60 * 1000);
long ddays = diff / (24 * 60 * 60 * 1000);
System.out.println("Your Day Difference="+ddays);
print语句只是一个例子 - 您可以按照自己喜欢的方式对其进行格式化。
由于这里的所有答案都是正确的,但使用遗留的Java或第三方库,如joda或类似的,我将在Java 8及更高版本中使用新的java.time类。见Oracle Tutorial。
LocalDate d1 = LocalDate.of(2017, 5, 1);
LocalDate d2 = LocalDate.of(2017, 5, 18);
long days = ChronoUnit.DAYS.between(d1, d2);
System.out.println( days );
减去以毫秒为单位的日期(如另一篇文章中所述),但在清除日期的时间部分时,您必须使用HOUR_OF_DAY而不是HOUR:
public static final long MSPERDAY = 60 * 60 * 24 * 1000;
...
final Calendar dateStartCal = Calendar.getInstance();
dateStartCal.setTime(dateStart);
dateStartCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateStartCal.set(Calendar.MINUTE, 0);
dateStartCal.set(Calendar.SECOND, 0);
dateStartCal.set(Calendar.MILLISECOND, 0);
final Calendar dateEndCal = Calendar.getInstance();
dateEndCal.setTime(dateEnd);
dateEndCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateEndCal.set(Calendar.MINUTE, 0);
dateEndCal.set(Calendar.SECOND, 0);
dateEndCal.set(Calendar.MILLISECOND, 0);
final long dateDifferenceInDays = ( dateStartCal.getTimeInMillis()
- dateEndCal.getTimeInMillis()
) / MSPERDAY;
if (dateDifferenceInDays > 15) {
// Do something if difference > 15 days
}
如果您不想使用JodaTime或类似的,最好的解决方案可能是:
final static long MILLIS_PER_DAY = 24 * 3600 * 1000;
long msDiff= date1.getTime() - date2.getTime();
long daysDiff = Math.round(msDiff / ((double)MILLIS_PER_DAY));
每天的ms数并不总是相同(因为夏令时和闰秒),但它非常接近,并且至少由于夏令时的偏差会在较长时间内抵消。因此,分割然后舍入将给出正确的结果(至少只要使用的本地日历不包含除DST和闰秒之外的奇怪时间跳跃)。
请注意,这仍假设date1
和date2
设置为一天的同一时间。正如Jon Skeet所指出的那样,对于一天中的不同时间,您首先必须定义“日期差异”的含义。
看看Joda Time,这是一个改进的Java日期/时间API,应该可以正常使用Scala。
让我展示Joda Interval和Days之间的区别:
DateTime start = new DateTime(2012, 2, 6, 10, 44, 51, 0);
DateTime end = new DateTime(2012, 2, 6, 11, 39, 47, 1);
Interval interval = new Interval(start, end);
Period period = interval.toPeriod();
System.out.println(period.getYears() + " years, " + period.getMonths() + " months, " + period.getWeeks() + " weeks, " + period.getDays() + " days");
System.out.println(period.getHours() + " hours, " + period.getMinutes() + " minutes, " + period.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *1 weeks, 1 days*
//0 hours, 54 minutes, 56 seconds
//Period can set PeriodType,such as PeriodType.yearMonthDay(),PeriodType.yearDayTime()...
Period p = new Period(start, end, PeriodType.yearMonthDayTime());
System.out.println(p.getYears() + " years, " + p.getMonths() + " months, " + p.getWeeks() + " weeks, " + p.getDays() + "days");
System.out.println(p.getHours() + " hours, " + p.getMinutes() + " minutes, " + p.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *0 weeks, 8 days*
//0 hours, 54 minutes, 56 seconds
如果你需要一个格式化的返回字符串,如“2天03h 42m 07s”,试试这个:
public String fill2(int value)
{
String ret = String.valueOf(value);
if (ret.length() < 2)
ret = "0" + ret;
return ret;
}
public String get_duration(Date date1, Date date2)
{
TimeUnit timeUnit = TimeUnit.SECONDS;
long diffInMilli = date2.getTime() - date1.getTime();
long s = timeUnit.convert(diffInMilli, TimeUnit.MILLISECONDS);
long days = s / (24 * 60 * 60);
long rest = s - (days * 24 * 60 * 60);
long hrs = rest / (60 * 60);
long rest1 = rest - (hrs * 60 * 60);
long min = rest1 / 60;
long sec = s % 60;
String dates = "";
if (days > 0) dates = days + " Days ";
dates += fill2((int) hrs) + "h ";
dates += fill2((int) min) + "m ";
dates += fill2((int) sec) + "s ";
return dates;
}
检查示例http://www.roseindia.net/java/beginners/DateDifferent.shtml此示例为您提供天,小时,分钟,秒和毫秒的差异:)。
import java.util.Calendar;
import java.util.Date;
public class DateDifferent {
public static void main(String[] args) {
Date date1 = new Date(2009, 01, 10);
Date date2 = new Date(2009, 07, 01);
Calendar calendar1 = Calendar.getInstance();
Calendar calendar2 = Calendar.getInstance();
calendar1.setTime(date1);
calendar2.setTime(date2);
long milliseconds1 = calendar1.getTimeInMillis();
long milliseconds2 = calendar2.getTimeInMillis();
long diff = milliseconds2 - milliseconds1;
long diffSeconds = diff / 1000;
long diffMinutes = diff / (60 * 1000);
long diffHours = diff / (60 * 60 * 1000);
long diffDays = diff / (24 * 60 * 60 * 1000);
System.out.println("\nThe Date Different Example");
System.out.println("Time in milliseconds: " + diff + " milliseconds.");
System.out.println("Time in seconds: " + diffSeconds + " seconds.");
System.out.println("Time in minutes: " + diffMinutes + " minutes.");
System.out.println("Time in hours: " + diffHours + " hours.");
System.out.println("Time in days: " + diffDays + " days.");
}
}
使用GMT时区获取日历的实例,使用Calendar类的set方法设置时间。 GMT时区有0偏移(不是很重要)和夏令时标志设置为false。
final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.set(Calendar.YEAR, 2011);
cal.set(Calendar.MONTH, 9);
cal.set(Calendar.DAY_OF_MONTH, 29);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
final Date startDate = cal.getTime();
cal.set(Calendar.YEAR, 2011);
cal.set(Calendar.MONTH, 12);
cal.set(Calendar.DAY_OF_MONTH, 21);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
final Date endDate = cal.getTime();
System.out.println((endDate.getTime() - startDate.getTime()) % (1000l * 60l * 60l * 24l));
以下代码可以为您提供所需的输出:
String startDate = "Jan 01 2015";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy");
LocalDate date = LocalDate.parse(startDate, formatter);
String currentDate = "Feb 11 2015";
LocalDate date1 = LocalDate.parse(currentDate, formatter);
System.out.println(date1.toEpochDay() - date.toEpochDay());
/**
* Get a diff between two dates
* @param date1 the oldest date
* @param date2 the newest date
* @param timeUnit the unit in which you want the diff
* @return the diff value, in the provided unit
*/
public static long getDateDiff(Date date1, Date date2, TimeUnit timeUnit) {
long diffInMillies = date2.getTime() - date1.getTime();
return timeUnit.convert(diffInMillies,TimeUnit.MILLISECONDS);
}
然后你可以打电话:
getDateDiff(date1,date2,TimeUnit.MINUTES);
以分钟为单位获得2个日期的差异。
TimeUnit
是java.util.concurrent.TimeUnit
,一个从纳米到天的标准Java枚举。
public static Map<TimeUnit,Long> computeDiff(Date date1, Date date2) {
long diffInMillies = date2.getTime() - date1.getTime();
//create the list
List<TimeUnit> units = new ArrayList<TimeUnit>(EnumSet.allOf(TimeUnit.class));
Collections.reverse(units);
//create the result map of TimeUnit and difference
Map<TimeUnit,Long> result = new LinkedHashMap<TimeUnit,Long>();
long milliesRest = diffInMillies;
for ( TimeUnit unit : units ) {
//calculate difference in millisecond
long diff = unit.convert(milliesRest,TimeUnit.MILLISECONDS);
long diffInMilliesForUnit = unit.toMillis(diff);
milliesRest = milliesRest - diffInMilliesForUnit;
//put the result in the map
result.put(unit,diff);
}
return result;
}
输出类似于Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}
,订购单位。
您只需将该地图转换为用户友好的字符串即可。
上面的代码片段计算了两个时刻之间的简单差异。在夏令时开关中可能会出现问题,如this post中所述。这意味着如果您在没有时间的情况下计算日期之间的差异,则可能会丢失一天/小时。
在我看来,日期差异是一种主观的,特别是在日子里。你可以:
day switches
的数量,即日期+ 1下午1点 - 上午11点= 1天,即使经过的时间仅为2小时(如果有夏令时则为1小时:p)如果您对日期差异的定义与第一种情况相符,我的回答是有效的
如果您正在使用JodaTime,您可以获得2个瞬间(毫秒支持的ReadableInstant)日期的差异:
Interval interval = new Interval(oldInstant, new Instant());
但您也可以获得本地日期/时间的差异:
// returns 4 because of the leap year of 366 days
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5), PeriodType.years()).getYears()
// this time it returns 5
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5+1), PeriodType.years()).getYears()
// And you can also use these static methods
Years.yearsBetween(LocalDate.now(), LocalDate.now().plusDays(365*5)).getYears()
public static String getDifferenceBtwTime(Date dateTime) {
long timeDifferenceMilliseconds = new Date().getTime() - dateTime.getTime();
long diffSeconds = timeDifferenceMilliseconds / 1000;
long diffMinutes = timeDifferenceMilliseconds / (60 * 1000);
long diffHours = timeDifferenceMilliseconds / (60 * 60 * 1000);
long diffDays = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24);
long diffWeeks = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 7);
long diffMonths = (long) (timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 30.41666666));
long diffYears = (long)(timeDifferenceMilliseconds / (1000 * 60 * 60 * 24 * 365));
if (diffSeconds < 1) {
return "one sec ago";
} else if (diffMinutes < 1) {
return diffSeconds + " seconds ago";
} else if (diffHours < 1) {
return diffMinutes + " minutes ago";
} else if (diffDays < 1) {
return diffHours + " hours ago";
} else if (diffWeeks < 1) {
return diffDays + " days ago";
} else if (diffMonths < 1) {
return diffWeeks + " weeks ago";
} else if (diffYears < 12) {
return diffMonths + " months ago";
} else {
return diffYears + " years ago";
}
}
注意:startDate和endDates是 - > java.util.Date
import org.joda.time.Duration;
import org.joda.time.Interval;
// Use .getTime() unless it is a joda DateTime object
Interval interval = new Interval(startDate.getTime(), endDate.getTime());
Duration period = interval.toDuration();
//gives the number of days elapsed between start
period.getStandardDays();
和结束日期
与天相似,您还可以获得小时,分钟和秒
period.getStandardHours();
period.getStandardMinutes();
period.getStandardSeconds();
int daysDiff = (date1.getTime() - date2.getTime()) / MILLIS_PER_DAY;
最好的办法是
(Date1-Date2)/86 400 000
该数字是一天中的毫秒数。
一个日期 - 其他日期为您提供毫秒差异。
在双变量中收集答案。
这可能是最简单的方法 - 或许这是因为我已经用Java编写了一段时间(其公认的笨重的日期和时间库)一段时间了,但这段代码看起来“简单而美观”!
您是否对以毫秒为单位返回的结果感到满意,或者您希望以某种替代格式返回结果?
不使用标准API,没有。你可以自己做这样的事情:
class Duration {
private final TimeUnit unit;
private final long length;
// ...
}
或者你可以使用Joda:
DateTime a = ..., b = ...;
Duration d = new Duration(a, b);
只是回答最初的问题:
将以下代码放在像Long getAge(){}这样的函数中
Date dahora = new Date();
long MillisToYearsByDiv = 1000l *60l * 60l * 24l * 365l;
long javaOffsetInMillis = 1990l * MillisToYearsByDiv;
long realNowInMillis = dahora.getTime() + javaOffsetInMillis;
long realBirthDayInMillis = this.getFechaNac().getTime() + javaOffsetInMillis;
long ageInMillis = realNowInMillis - realBirthDayInMillis;
return ageInMillis / MillisToYearsByDiv;
这里最重要的是在乘法和除法时使用长数。当然,Java在其Dates演算中应用的偏移量。
:)
由于问题是用Scala标记的,
import scala.concurrent.duration._
val diff = (System.currentTimeMillis() - oldDate.getTime).milliseconds
val diffSeconds = diff.toSeconds
val diffMinutes = diff.toMinutes
val diffHours = diff.toHours
val diffDays = diff.toDays
这是O(1)中没有任何依赖关系的正确Java 7解决方案。
public static int countDaysBetween(Date date1, Date date2) {
Calendar c1 = removeTime(from(date1));
Calendar c2 = removeTime(from(date2));
if (c1.get(YEAR) == c2.get(YEAR)) {
return Math.abs(c1.get(DAY_OF_YEAR) - c2.get(DAY_OF_YEAR)) + 1;
}
// ensure c1 <= c2
if (c1.get(YEAR) > c2.get(YEAR)) {
Calendar c = c1;
c1 = c2;
c2 = c;
}
int y1 = c1.get(YEAR);
int y2 = c2.get(YEAR);
int d1 = c1.get(DAY_OF_YEAR);
int d2 = c2.get(DAY_OF_YEAR);
return d2 + ((y2 - y1) * 365) - d1 + countLeapYearsBetween(y1, y2) + 1;
}
private static int countLeapYearsBetween(int y1, int y2) {
if (y1 < 1 || y2 < 1) {
throw new IllegalArgumentException("Year must be > 0.");
}
// ensure y1 <= y2
if (y1 > y2) {
int i = y1;
y1 = y2;
y2 = i;
}
int diff = 0;
int firstDivisibleBy4 = y1;
if (firstDivisibleBy4 % 4 != 0) {
firstDivisibleBy4 += 4 - (y1 % 4);
}
diff = y2 - firstDivisibleBy4 - 1;
int divisibleBy4 = diff < 0 ? 0 : diff / 4 + 1;
int firstDivisibleBy100 = y1;
if (firstDivisibleBy100 % 100 != 0) {
firstDivisibleBy100 += 100 - (firstDivisibleBy100 % 100);
}
diff = y2 - firstDivisibleBy100 - 1;
int divisibleBy100 = diff < 0 ? 0 : diff / 100 + 1;
int firstDivisibleBy400 = y1;
if (firstDivisibleBy400 % 400 != 0) {
firstDivisibleBy400 += 400 - (y1 % 400);
}
diff = y2 - firstDivisibleBy400 - 1;
int divisibleBy400 = diff < 0 ? 0 : diff / 400 + 1;
return divisibleBy4 - divisibleBy100 + divisibleBy400;
}
public static Calendar from(Date date) {
Calendar c = Calendar.getInstance();
c.setTime(date);
return c;
}
public static Calendar removeTime(Calendar c) {
c.set(HOUR_OF_DAY, 0);
c.set(MINUTE, 0);
c.set(SECOND, 0);
c.set(MILLISECOND, 0);
return c;
}
在浏览了所有其他答案之后,保持Java 7 Date类型,但使用Java 8 diff方法更精确/标准,
public static long daysBetweenDates(Date d1, Date d2) {
Instant instant1 = d1.toInstant();
Instant instant2 = d2.toInstant();
long diff = ChronoUnit.DAYS.between(instant1, instant2);
return diff;
}
int diffInDays = (int)( (newerDate.getTime() - olderDate.getTime())
/ (1000 * 60 * 60 * 24) )
请注意,这适用于UTC日期,因此如果您查看本地日期,差异可能是休息日。并且由于夏令时,需要采用完全不同的方法使其与本地日期一起正常工作。
尝试这个:
int epoch = (int) (new java.text.SimpleDateFormat("MM/dd/yyyy HH:mm:ss").parse("01/01/1970 00:00:00").getTime() / 1000);
你可以在parse()方法参数中编辑字符串。
您需要更清楚地定义问题。你可以把两个Date
对象之间的毫秒数除以24小时内的毫秒数,例如......但是:
Date
始终使用UTC使用Java 8+中内置的java.time框架:
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10);
Duration duration = Duration.between(oldDate, now);
System.out.println("ISO-8601: " + duration);
System.out.println("Minutes: " + duration.toMinutes());
输出:
ISO-8601:PT24H10M
会议纪要:1450
有关更多信息,请参阅Oracle Tutorial和ISO 8601标准。
将过时的java.util.Date
对象转换为替代品java.time.Instant
。然后将经过的时间计算为Duration
。
Duration d =
Duration.between( // Calculate the span of time between two moments as a number of hours, minutes, and seconds.
myJavaUtilDate.toInstant() , // Convert legacy class to modern class by calling new method added to the old class.
Instant.now() // Capture the current moment in UTC. About two and a half hours later in this example.
)
;
d.toString():PT2H34M56S
d.toMinutes():154
d.toMinutesPart():34
PnYnMnDTnHnMnS
明智的标准ISO 8601将时间跨度的简明文本表示定义为若干年,月,日,小时等。标准称这样的跨度为duration。格式为PnYnMnDTnHnMnS
,其中P
表示“Period”,T
将日期部分与时间部分分开,中间是数字后跟字母。
例子:
P3Y6M4DT12H30M5S
三年,六个月,四天,十二小时,三十五分五秒PT4H30M
四个半小时在Java 8及更高版本中内置的java.time框架取代了麻烦的旧java.util.Date
/ java.util.Calendar
类。新课程的灵感来自非常成功的Joda-Time框架,旨在作为其继承者,在概念上类似但重新设计。由JSR 310定义。由ThreeTen-Extra项目扩展。见Tutorial。
Instant
类代表UTC时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。
Instant instant = Instant.now() ; // Capture current moment in UTC.
最好避免像Date
/ Calendar
这样的遗留类。但是,如果您必须与尚未更新到java.time的旧代码进行交互操作,请来回转换。调用添加到旧类的新转换方法。要从java.util.Date
转移到Instant
,请致电Date::toInstant
。
Instant instant = myJavaUtilDate.toInstant() ; // Convert from legacy `java.util.Date` class to modern `java.time.Instant` class.
java.time类将这种将时间跨度表示为数年,月,日,小时,分钟,秒分为两半的想法分开了:
这是一个例子。
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now ( zoneId );
ZonedDateTime future = now.plusMinutes ( 63 );
Duration duration = Duration.between ( now , future );
转储到控制台。
Period
和Duration
都使用ISO 8601标准生成其值的String表示。
System.out.println ( "now: " + now + " to future: " + now + " = " + duration );
现在:2015-11-26T00:46:48.016-05:00 [美国/蒙特利尔]到未来:2015-11-26T00:46:48.016-05:00 [美国/蒙特利尔] = PT1H3M
Java 9为Duration
添加了方法,以获取日期部分,小时部分,分钟部分和秒部分。
您可以获得整个持续时间中的总天数或小时数,分钟数或秒数或毫秒数或纳秒数。
long totalHours = duration.toHours();
在Java 9中,Duration
class gets new methods用于返回天,小时,分钟,秒,毫秒/纳秒的各个部分。调用to…Part
方法:toDaysPart()
,toHoursPart()
等。
ChronoUnit
如果您只关心更简单的更大粒度的时间,例如“经过的天数”,请使用ChronoUnit
枚举。
long daysElapsed = ChronoUnit.DAYS.between( earlier , later );
另一个例子。
Instant now = Instant.now();
Instant later = now.plus( Duration.ofHours( 2 ) );
…
long minutesElapsed = ChronoUnit.MINUTES.between( now , later );
120
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,如java.util.Date
,Calendar
和SimpleDateFormat
。
Joda-Time项目,现在在maintenance mode,建议迁移到java.time。
要了解更多信息,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规格是JSR 310。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目是未来可能添加到java.time的试验场。你可能会在这里找到一些有用的类,如Interval
,YearWeek
,YearQuarter
和more。
更新:Joda-Time项目现在在maintenance mode,团队建议迁移到java.time班级。我保留此部分的历史记录。
Joda-Time库使用ISO 8601作为其默认值。它的Period
类解析并生成这些PnYnMnDTnHnMnS字符串。
DateTime now = DateTime.now(); // Caveat: Ignoring the important issue of time zones.
Period period = new Period( now, now.plusHours( 4 ).plusMinutes( 30));
System.out.println( "period: " + period );
呈现:
period: PT4H30M
Days d = Days.daysBetween(startDate, endDate);
int days = d.getDays();
一个稍微简单的替代方案:
System.currentTimeMillis() - oldDate.getTime()
至于“更好”:嗯,你究竟需要什么?将持续时间表示为小时数和天数等的问题在于,由于日期的复杂性,它可能导致不准确和错误的期望(例如,由于夏令时,天可能有23或25小时)。
使用毫秒方法可能会导致某些区域设置出现问题。
让我们看一下,例如,03/24/2007和03/25/2007两个日期之间的差异应该是1天;
但是,使用毫秒路线,如果你在英国运行,你将获得0天!
/** Manual Method - YIELDS INCORRECT RESULTS - DO NOT USE**/
/* This method is used to find the no of days between the given dates */
public long calculateDays(Date dateEarly, Date dateLater) {
return (dateLater.getTime() - dateEarly.getTime()) / (24 * 60 * 60 * 1000);
}
更好的实现方法是使用java.util.Calendar
/** Using Calendar - THE CORRECT WAY**/
public static long daysBetween(Calendar startDate, Calendar endDate) {
Calendar date = (Calendar) startDate.clone();
long daysBetween = 0;
while (date.before(endDate)) {
date.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}