[英]Get the number of weeks between two Dates.
我在一个项目中工作,我在日期中有两种类型。 我想计算这两个日期之间的周数。 日期可以在不同的年份。 对此有什么好的解决方案吗?
我试图用其他主题中建议的 Joda-time 来实现这一点。
我不熟悉这个库,但我试着做这样的事情:
public static int getNumberOfWeeks(Date f, Date l){
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.setTime(f);
c2.setTime(l);
DateTime start = new DateTime(c1.YEAR, c1.MONTH, c1.DAY_OF_MONTH, 0, 0, 0, 0);
DateTime end = new DateTime(c2.YEAR, c2.MONTH, c2.DAY_OF_MONTH, 0, 0, 0, 0);
Interval interval = new Interval(start, end);
Period p = interval.toPeriod();
return p.getWeeks();
}
但这是完全错误的......有什么建议吗?
使用joda time很容易:
DateTime dateTime1 = new DateTime(date1);
DateTime dateTime2 = new DateTime(date2);
int weeks = Weeks.weeksBetween(dateTime1, dateTime2).getWeeks();
更新答案以解释 Java 8
// TechTrip - ASSUMPTION d1 is earlier than d2
// leave that for exercise
public static long getFullWeeks(Calendar d1, Calendar d2){
Instant d1i = Instant.ofEpochMilli(d1.getTimeInMillis());
Instant d2i = Instant.ofEpochMilli(d2.getTimeInMillis());
LocalDateTime startDate = LocalDateTime.ofInstant(d1i, ZoneId.systemDefault());
LocalDateTime endDate = LocalDateTime.ofInstant(d2i, ZoneId.systemDefault());
return ChronoUnit.WEEKS.between(startDate, endDate);
}
ChronoUnit
.WEEKS
.between(
myJavaUtilDate_Start.toInstant().atZone( ZoneId.of( "Asia/Tokyo" ) ) ,
myJavaUtilDate_Stop.toInstant().atZone( ZoneId.of( "Asia/Tokyo" ) )
)
7
java.time框架内置于 Java 8 及更高版本中。 这些新类取代了与最早版本的 Java 捆绑在一起的旧日期时间类。
java.time类还取代了非常成功的Joda-Time框架。 java.time和Joda-Time都由Stephen Colbourne领导。
Instant
替换java.util.Date
现代类Instant
替换了遗留类java.util.Date
。 两者都代表 UTC 中的一个时刻,即时间线上的一个特定点。 自 UTC 中 1970 年第一时刻的同一纪元参考 1970-01-01T00:00Z 起,两者在内部都使用计数。 旧类使用毫秒计数,而Instant
使用更精细的纳秒计数。
要进行转换,请调用添加到旧类中的新方法。
Instant start = myJavaUtilDateStart.toInstant() ;
Instant stop = myJavaUtilDateStop.toInstant() ;
让我们用一些示例值来具体说明。
Instant start = OffsetDateTime.of( 2020 , 1 , 23 , 15 , 30 , 0 , 0 , ZoneOffset.UTC ).toInstant();
Instant stop = OffsetDateTime.of( 2020 , 1 , 23 , 15 , 30 , 0 , 0 , ZoneOffset.UTC ).plusWeeks(7 ).toInstant();
我们的两个Instant
对象都代表一个时刻。 目标是计算周数。 Weeks 表示天,days 表示日历上的某些日期。
所以我们有点不匹配。 对于任何给定时刻,日期在全球各地因时区而异。 法国巴黎午夜过后的几分钟是一个新的约会。 与此同时,在魁北克省蒙特利尔,落后几个小时,同一时刻仍然是“昨天”,也就是日历上的前一天。 所以我们不能直接从一对矩计算周数。
您必须首先确定您希望为那些时刻感知日历的时区。
以Continent/Region
格式指定正确的时区名称,例如America/Montreal
、 Africa/Casablanca
或Pacific/Auckland
。 永远不要使用EST
或IST
等 2-4 个字母的缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime
将此ZoneId
应用于我们的Instant
对象以调整到时区,产生一对ZonedDateTime
对象。
ZonedDateTime startZdt = start.atZone( z ) ;
ZonedDateTime stopZdt = stop.atZone( z ) ;
ChronoUnit.WEEKS
现在我们可以使用ChronoUnit
枚举来计算经过的周数。
长周 = ChronoUnit.WEEKS.between( startZdt , stopZdt );
转储到控制台。
System.out.println( "start.toString() = " + start );
System.out.println( "stop.toString() = " + stop );
System.out.println( "startZdt.toString() = " + startZdt );
System.out.println( "stopZdt.toString() = " + stopZdt );
System.out.println( "weeksCount: " + weeksCount );
start.toString() = 2020-01-23T15:30:00Z
stop.toString() = 2020-03-12T15:30:00Z
startZdt.toString() = 2020-01-23T10:30-05:00[美国/蒙特利尔]
stopZdt.toString() = 2020-03-12T11:30-04:00[美国/蒙特利尔]
周数:7
ThreeTen-Extra项目为 Java 8 及更高版本中内置的java.time框架添加了功能。
Weeks
班该项目包括一个Weeks
类来表示周数。 它不仅可以计算,还可以在您的代码中用作类型安全对象。 这种使用还有助于使您的代码自文档化。
您可以通过使用Weeks.between
方法提供一对时间点来实例化。 这些时间点可以是任何实现java.time.temporal.Temporal 的东西,包括Instant
、 LocalDate
、 OffsetDateTime
、 ZonedDateTime
、 Year
、 YearMonth
等等。
你的java.util.Date
对象可以很容易地转换为Instant
对象,时间轴上的时刻以 UTC 为单位,分辨率为纳秒。 查看添加到旧日期时间类的新方法。 要从 Date 转到 Instant,请调用java.util.Date::toInstant
。
Weeks weeks = Weeks.between( startZdt , stopZdt );
您可以询问周数。
int weeksNumber = weeks.getAmount(); // The number of weeks in this Weeks object.
您还可以做更多的事情。
生成标准ISO 8601格式的字符串。 P
标志着开始。 W
表示周数。
PW7
java.time框架内置于 Java 8 及更高版本中。 这些类取代麻烦的老传统日期时间类,如java.util.Date
, Calendar
,和SimpleDateFormat
。
要了解更多信息,请参阅Oracle 教程。 并在 Stack Overflow 上搜索许多示例和解释。 规范是JSR 310 。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
您可以直接与您的数据库交换java.time对象。 使用符合JDBC 4.2或更高版本的JDBC 驱动程序。 不需要字符串,不需要java.sql.*
类。
从哪里获得 java.time 类?
ThreeTen-Extra项目用额外的类扩展了 java.time。 该项目是未来可能添加到 java.time 的试验场。 您可以在这里找到一些有用的类,比如Interval
, YearWeek
, YearQuarter
,和更多。
在java.util.Calendar
使用日期算法:
public static int getWeeksBetween (Date a, Date b) {
if (b.before(a)) {
return -getWeeksBetween(b, a);
}
a = resetTime(a);
b = resetTime(b);
Calendar cal = new GregorianCalendar();
cal.setTime(a);
int weeks = 0;
while (cal.getTime().before(b)) {
// add another week
cal.add(Calendar.WEEK_OF_YEAR, 1);
weeks++;
}
return weeks;
}
public static Date resetTime (Date d) {
Calendar cal = new GregorianCalendar();
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();
}
如果您的要求是开始日期是 2020 年 4 月 3 日,结束日期是 2020 年 4 月 7 日。 两个日期之间相差 4 天。 现在,您可以使用以下代码段将两个日期之间的周数设为 1 。
ChronoUnit.WEEKS.between(LocalDate startDate, LocalDate endDate);
但是,如果您的要求是 03-Apr-2020 在一周内,而 07-Apr-2020 在另一周内,因此您希望两个日期之间的周数为 2 ,则可以使用以下代码段。
LocalDate actualStartDate=...
LocalDate actualEndDate=...
LocalDate startDate = actualStartDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY))
LocalDate endDate = actualEndDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.SATURDAY))
long daysBetweenTwoDates = ChronoUnit.DAYS.between(startDate, endDate);
int numberOfWeeks = (int)Math.ceil(daysBetweenTwoDates/7.0);
在 Java 1.8 中测试
Calendar a = new GregorianCalendar(2002,1,22);
Calendar b = new GregorianCalendar(2002,1,28);
System.out.println(a.get(Calendar.WEEK_OF_YEAR));
System.out.println(b.get(Calendar.WEEK_OF_YEAR));
int weeks = b.get(Calendar.WEEK_OF_YEAR)-a.get(Calendar.WEEK_OF_YEAR);
System.out.println(weeks);
试试这个必须工作
Calendar calendar1 = Calendar.getInstance();
Calendar calendar2 = Calendar.getInstance();
calendar1.set(2007, 01, 10);
calendar2.set(2007, 07, 01);
long milliseconds1 = calendar1.getTimeInMillis();
long milliseconds2 = calendar2.getTimeInMillis();
long diff = milliseconds2 - milliseconds1;
int diffWeeks = (int)diff / (7*24 * 60 * 60 * 1000);
如果您想要确切的完整周数,请使用以下方法,其中结束日期是唯一的:
public static long weeksBetween(Date date1, Date date2) {
return WEEKS.between(date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(),
date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
}
如果您想要此的 ceil 版本,请使用以下内容:
public static long weeksBetween(Date date1, Date date2) {
long daysBetween = DAYS.between(date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(),
date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()) + 1;
return daysBetween / 7 + (daysBetween % 7 == 0 ? 0 : 1);
}
这是我编写的 2 种不基于外部库的方法。
第一种方法是星期一是一周的第一天。
第二种方法是星期日是一周的第一天。
请阅读代码中的注释,可以选择返回两个日期之间的完整周数,
以及两个日期之前和之后剩余天数的分数。
public static int getNumberOfFullWeeks(LocalDate startDate,LocalDate endDate)
{
int dayBeforeStartOfWeek = 0;
int daysAfterLastFullWeek = 0;
if(startDate.getDayOfWeek() != DayOfWeek.MONDAY)
{
// get the partial value before loop starting
dayBeforeStartOfWeek = 7-startDate.getDayOfWeek().getValue() + 1;
}
if(endDate.getDayOfWeek() != DayOfWeek.SUNDAY)
{
// get the partial value after loop ending
daysAfterLastFullWeek = endDate.getDayOfWeek().getValue();
}
LocalDate d1 = startDate.plusDays(dayBeforeStartOfWeek); // now it is the first day of week;
LocalDate d2 = endDate.minusDays(daysAfterLastFullWeek); // now it end in the last full week
// Count how many days there are of full weeks that start on Mon and end in Sun
// if the startDate and endDate are less than a full week the while loop
// will not iterate at all because d1 and d2 will be the same date
LocalDate looper = d1;
int counter = 1;
while (looper.isBefore(d2))
{
counter++;
looper = looper.plusDays(1);
}
// Counter / 7 will always be an integer that will represents full week
// because we started to count at Mon and stop counting in Sun
int fullWeeks = counter / 7;
System.out.println("Full weeks between dates: "
+ fullWeeks + " Days before the first monday: "
+ dayBeforeStartOfWeek + " "
+ " Days after the last sunday: " + daysAfterLastFullWeek);
System.out.println(startDate.toString() + " - " + endDate.toString());
// You can also get a decimal value of the full weeks plus the fraction if the days before
// and after the full weeks
float full_weeks_decimal = (float)fullWeeks;
float fraction = ((float)dayBeforeStartOfWeek + (float)daysAfterLastFullWeek) / 7.0F;
System.out.println("Full weeks with fraction: " + String.valueOf(fraction + full_weeks_decimal));
return fullWeeks;
}
public static int getNumberOfFullWeeks_WeekStartAtSunday(LocalDate startDate,LocalDate endDate)
{
int dayBeforeStartOfWeek = 0;
int daysAfterLastFullWeek = 0;
if(startDate.getDayOfWeek() != DayOfWeek.SUNDAY)
{
// get the partial value before loop starting
dayBeforeStartOfWeek = 7-getDayOfWeekBySundayIs0(startDate.getDayOfWeek()) + 1;
}
if(endDate.getDayOfWeek() != DayOfWeek.SATURDAY)
{
// get the partial value after loop ending
daysAfterLastFullWeek = 1+getDayOfWeekBySundayIs0(endDate.getDayOfWeek());
}
LocalDate d1 = startDate.plusDays(dayBeforeStartOfWeek); // now it is the first day of week;
LocalDate d2 = endDate.minusDays(daysAfterLastFullWeek); // now it end in the last full week
// Count how many days there are of full weeks that start on Sun and end in Sat
// if the startDate and endDate are less than a full week the while loop
// will not iterate at all because d1 and d2 will be the same date
LocalDate looper = d1;
int counter = 1;
while (looper.isBefore(d2))
{
counter++;
looper = looper.plusDays(1);
}
// Counter / 7 will always be an integer that will represents full week
// because we started to count at Sun and stop counting in Sat
int fullWeeks = counter / 7;
System.out.println("Full weeks between dates: "
+ fullWeeks + " Days before the first sunday: "
+ dayBeforeStartOfWeek + " "
+ " Days after the last saturday: " + daysAfterLastFullWeek);
System.out.println(startDate.toString() + " - " + endDate.toString());
// You can also get a decimal value of the full weeks plus the fraction if the days before
// and after the full weeks
float full_weeks_decimal = (float)fullWeeks;
float fraction = ((float)dayBeforeStartOfWeek + (float)daysAfterLastFullWeek) / 7.0F;
System.out.println("Full weeks with fraction: " + String.valueOf(fraction + full_weeks_decimal));
return fullWeeks;
}
public static int getDayOfWeekBySundayIs0(DayOfWeek day)
{
if(day == DayOfWeek.SUNDAY)
{
return 0;
}
else
{
// NOTE: getValue() is starting to count from 1 and not from 0
return day.getValue();
}
}
Joda Time 计算具有两个日期的周数,这在某些情况下可能不符合我们的要求。 我有一个 Joda Time 方法来计算两个日期之间的自然周数。 希望它可以帮助你。 如果你不使用 Joda Time,你可以用 Calendar 修改代码来做同样的事情。
//Unlike Joda Time Weeks.weeksBetween() that returns whole weeks computed
//from duration, we return natural weeks between two dates based on week of year
public static int weeksBetween(ReadablePartial date1, ReadablePartial date2) {
int comp = date1.compareTo(date2);
if (comp == 0) {
return 0;
}
if (comp > 0) {
ReadablePartial mid = date2;
date2 = date1;
date1 = mid;
}
int year1 = date1.get(DateTimeFieldType.weekyear());
int year2 = date2.get(DateTimeFieldType.weekyear());
if (year1 == year2) {
return date2.get(DateTimeFieldType.weekOfWeekyear()) - date1.get(DateTimeFieldType.weekOfWeekyear());
}
int weeks1 = 0;
LocalDate lastDay1 = new LocalDate(date1.get(DateTimeFieldType.year()), 12, 31);
if (lastDay1.getWeekyear() > year1) {
lastDay1 = lastDay1.minusDays(7);
weeks1++;
}
weeks1 += lastDay1.getWeekOfWeekyear() - date1.get(DateTimeFieldType.weekOfWeekyear());
int midWeeks = 0;
for (int i = year1 + 1; i < year2; i++) {
LocalDate y1 = new LocalDate(i, 1, 1);
int yearY1 = y1.getWeekyear();
if (yearY1 < i) {
y1 = y1.plusDays(7);
midWeeks++;
}
LocalDate y2 = new LocalDate(i, 12, 31);
int yearY2 = y2.getWeekyear();
if (yearY2 > i) {
y2 = y2.minusDays(7);
midWeeks++;
}
midWeeks += y2.getWeekOfWeekyear() - y1.getWeekOfWeekyear();
}
int weeks2 = 0;
LocalDate firstDay2 = new LocalDate(date2.get(DateTimeFieldType.year()), 1, 1);
if (firstDay2.getWeekyear() < firstDay2.getYear()) {
firstDay2 = firstDay2.plusDays(7);
weeks2++;
}
weeks2 += date2.get(DateTimeFieldType.weekOfWeekyear()) - firstDay2.getWeekOfWeekyear();
return weeks1 + midWeeks + weeks2;
}
int startWeek = c1.get(Calendar.WEEK_OF_YEAR);
int endWeek = c2.get(Calendar.WEEK_OF_YEAR);
int diff = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR);
int deltaYears = 0;
for(int i = 0;i < diff;i++){
deltaYears += c1.getWeeksInWeekYear();
c1.add(Calendar.YEAR, 1);
}
diff = (endWeek + deltaYears) - startWeek;
包括年份差异。 这对我有用:)
private int weeksBetween(Calendar startDate, Calendar endDate) {
startDate.set(Calendar.HOUR_OF_DAY, 0);
startDate.set(Calendar.MINUTE, 0);
startDate.set(Calendar.SECOND, 0);
int start = (int)TimeUnit.MILLISECONDS.toDays(
startDate.getTimeInMillis())
- startDate.get(Calendar.DAY_OF_WEEK);
int end = (int)TimeUnit.MILLISECONDS.toDays(
endDate.getTimeInMillis());
return (end - start) / 7;
}
如果此方法返回 0,则它们在同一周
如果此方法返回 1 endDate 是 startDate 之后的一周
如果此方法返回 -1 endDate 是 startDate 之前的一周
你明白了
在不使用 JodaTime 的情况下,我能够准确计算两个日历之间的周数(包括闰年等)
private fun calculateNumberOfWeeks() {
val calendarFrom = Calendar.getInstance()
calendarFrom.set(Calendar.HOUR_OF_DAY, 0)
calendarFrom.set(Calendar.MINUTE, 0)
calendarFrom.set(Calendar.SECOND, 0)
calendarFrom.set(Calendar.MILLISECOND, 0)
val calendarTo = Calendar.getInstance()
calendarTo.add(Calendar.MONTH, months)
calendarTo.set(Calendar.HOUR_OF_DAY, 0)
calendarTo.set(Calendar.MINUTE, 0)
calendarTo.set(Calendar.SECOND, 0)
calendarTo.set(Calendar.MILLISECOND, 0)
var weeks = -1
while (calendarFrom.timeInMillis < calendarTo.timeInMillis) {
calendarFrom.add(Calendar.DATE, 7)
weeks++
Log.d(Constants.LOG_TAG, "weeks $weeks")
}
}
简单的方法
Calendar cal1 = new GregorianCalendar();
Calendar cal2 = new GregorianCalendar();
cal1.set(2014, 3, 3);
cal2.set(2015, 3, 6);
weekscount.setText("weeks= "+ ( (cal2.getTime().getTime() - cal1.getTime().getTime()) / (1000 * 60 * 60 * 24))/7);
这是查找两个日期之间的周数的简单方法。
SimpleDateFormat myFormat = new SimpleDateFormat("dd MM yyyy");
String classStartData = "31 01 2021";
String classEndData = "08 03 2021";
Date dateClassStart = myFormat.parse(classStartData);
Date dateClassEnd = myFormat.parse(classEndData);
long differenceWeek = dateClassEnd.getTime() - dateClassStart.getTime();
int programLength = (int)(TimeUnit.DAYS.convert(differenceWeek, TimeUnit.MILLISECONDS)/7);
System.out.println("Class length in weeks: " +programLength);
在参考了许多解决方案之后,这对我有用。 {前提是我不想使用外部库}
public static int getNumberOfWeeks(Date date1, Date date2) {
if (date1.after(date2)) {
return getNumberOfWeeks(date2, date1);
}
Date date = date1;
int days = 0;
while (date.before(date2)) {
days++;
date = addDays(date, 1);
}
return days/7;
}
向日期添加天数:
Date addDays(Date date, int days) {
if (days == 0) {
return date;
} else {
Date shiftedDate = new Date(date.getTime() + (long)days * 86400000L);
return shiftedDate;
}
}
您可以通过以下方式进行:
// method header not shown
// example dates:
f = new GregorianCalendar(2009,Calendar.AUGUST,1);
l = new GregorianCalendar(2010,Calendar.SEPTEMBER,1);
DateTime start = new DateTime(f);
DateTime end = new DateTime(l);
// Alternative to above - example dates with joda:
// DateTime start = new DateTime(2009,8,1,0,0,0,0);
// DateTime end = new DateTime(2010,9,1,0,0,0,0);
Interval interval = new Interval(start,end);
int weeksBetween = interval.toPeriod(PeriodType.weeks()).getWeeks();
// return weeksBetween;
这应该给你一个 int 代表两个日期之间的周数。
public int diffInWeeks(Date start, Date end) { long diffSeconds = (end.getTime() - start.getTime())/1000; return (int)diffSeconds/(60 * 60 * 24 * 7); }
看看下面的文章: Java - 计算两个日期之间的差异
daysBetween 方法将允许您获取日期之间的天数。 然后你可以简单地除以 7 得到完整的周数。
Calendar date1 = Calendar.getInstance();
Calendar date2 = Calendar.getInstance();
date1.clear();
date1.set(datePicker1.getYear(), datePicker1.getMonth(),
datePicker1.getDayOfMonth());
date2.clear();
date2.set(datePicker2.getYear(), datePicker2.getMonth(),
datePicker2.getDayOfMonth());
long diff = date2.getTimeInMillis() - date1.getTimeInMillis();
float dayCount = (float) diff / (24 * 60 * 60 * 1000);
int week = (dayCount / 7) ;
希望这可以帮助你
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.