给定某年某月(yyyy-MM), 获取该月的每周的开始日期和结束日期(yyyy-MM-dd,每周周一为第一天,周日为最后一天),
比如给定2018-08,该月第一周为2018-08-01至2018-08-05,第二周为2018-08-06至2018-08-12,以此类推,最后一周为2018-08-27至2018-08-31,
再如2018-07,第一周为2018-07-01至2018-07-01,最后一周为2018-07-30至2018-07-31.
该如何求?
给定某年某月(yyyy-MM), 获取该月的每周的开始日期和结束日期(yyyy-MM-dd,每周周一为第一天,周日为最后一天),
比如给定2018-08,该月第一周为2018-08-01至2018-08-05,第二周为2018-08-06至2018-08-12,以此类推,最后一周为2018-08-27至2018-08-31,
再如2018-07,第一周为2018-07-01至2018-07-01,最后一周为2018-07-30至2018-07-31.
该如何求?
Java8 LocalDate
了解一下
public static void main(String[] args) {
// Java8 LocalDate
LocalDate date = LocalDate.parse("2018-08-01");
// 该月第一天
LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth());
// 该月最后一天
LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth());
// 该月的第一个周一
LocalDate start = date.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
List<String> list = new ArrayList<>();
// 处理每个月的1号不是周一的情况
if (!firstDay.equals(start)) {
StringBuilder strbur = new StringBuilder();
strbur.append(firstDay.toString())
.append("至")
.append(start.plusDays(-1).toString());
list.add(strbur.toString());
}
while (start.isBefore(lastDay)) {
StringBuilder strbur = new StringBuilder();
strbur.append(start.toString());
LocalDate temp = start.plusDays(6);
if (temp.isBefore(lastDay)) {
strbur.append("至")
.append(temp.toString());
} else {
strbur.append("至")
.append(lastDay.toString());
}
list.add(strbur.toString());
start = start.plusWeeks(1);
}
System.out.println(list.toString());
}
package com.blog.web.front;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public class Test{
/**
* 演示用
* @param date
* @param format
* @return
*/
public static String formatDate(Date date,String format){
if(null == format || "".equals(format.trim())){
format = "yyyy-MM-dd";
}
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
return dateFormat.format(date);
}
/**
* 演示用
* @param dateStr
* @param format
* @return
*/
public static Date parseDate(String dateStr,String format){
if(null == format || "".equals(format.trim())){
format = "yyyy-MM-dd";
}
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
try {
return dateFormat.parse(dateStr);
} catch (ParseException e) {
return null;
}
}
public static List<String[]> getAllWeek(String dateStr){
Date date = parseDate(dateStr,"yyyy-MM");
Calendar c = Calendar.getInstance();
c.setTime(date);
c.set(Calendar.DAY_OF_MONTH, 1);
int dayOfWeek = c.get(Calendar.DAY_OF_WEEK) - 1;
dayOfWeek = dayOfWeek == 0 ? 7 : dayOfWeek;
int days = c.getActualMaximum(Calendar.DAY_OF_MONTH);
List<String[]> result = new ArrayList<String[]>();
String[] array = null;
for(int curDay = 1;curDay <= days;curDay++){
c.set(Calendar.DAY_OF_MONTH, curDay);
if(1 == curDay || 1 == dayOfWeek){
array = new String[2];
array[0] = formatDate(c.getTime(),null);
}
if(dayOfWeek == 7 || curDay == days){
array[1] = formatDate(c.getTime(),null);
result.add(array);
dayOfWeek = 0;
}
dayOfWeek++;
}
return result;
}
public static void main(String[] args) {
List<String[]> result = getAllWeek("2018-07");
String[] weekPrefixArray = new String[]{"一","二","三","四","五","六","七","八"};
for(int i = 0;i < result.size();i++){
String arr[] = result.get(i);
System.out.println("第"+weekPrefixArray[i]+"周为"+arr[0]+ "至" + arr[1]);
}
}
}
大概思路吧,代码写的不严谨,看看吧。
LocalDate now = LocalDate.now().minusMonths(2);
LocalDate firstDayOfNextMonth = now.with(TemporalAdjusters.firstDayOfNextMonth());
LocalDate firstDayOfMonth = now.with(TemporalAdjusters.firstDayOfMonth());
List<Pair<LocalDate, LocalDate>> list =
Stream.iterate(new Pair<>(firstDayOfMonth, firstDayOfMonth.plusDays(7 - firstDayOfMonth.getDayOfWeek().getValue()))
, it -> new Pair<>(it.getRight().plusDays(1), it.getRight().plusDays(7)))
.limit(8)
.filter(it -> it.getLeft().isBefore(firstDayOfNextMonth))
.map(it -> it.getRight().isBefore(firstDayOfNextMonth) ? it : new Pair<>(it.getLeft(), firstDayOfNextMonth.minusDays(1)))
.collect(Collectors.toList());
我想你应该需要这个,知道每一个的第一个周日,第一个周日不一定是一号。
其他周应该很好算了
/\*\*
\* 获取每个月第一个星期日的日期 \* @param year 年份
\* @param month 月份
\* @return Date 日期 \*/public static Date getFirstSundayOfMonth(int year, int month) {
Calendar cal \= Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month \- 1);
// 设为第一天
cal.set(Calendar.DATE, 1);
while (cal.get(Calendar.DAY\_OF\_WEEK) != Calendar.SUNDAY) {
cal.add(Calendar.DATE, 1);
}
return cal.getTime();
}
比如 2020-3的第一个周日 是3月1号
2020-4的第一个周日 是4月5号
根据上面就知道可以知道,三月的最后一周的(最后一天是周六)是 4月4号
如下
3/1~3/7 第一周
3/8~3/14 第二周
3/15~3/21 第三周
3/22~3/28 第四周
3/29~4/4 第五周(最后一周的日期就是4/4)
3 回答2.6k 阅读✓ 已解决
3 回答4.1k 阅读✓ 已解决
8 回答3.7k 阅读
4 回答2.8k 阅读✓ 已解决
2 回答2.7k 阅读✓ 已解决
3 回答2.5k 阅读✓ 已解决
4 回答1.9k 阅读
题主,以下是我的思考思路,仅供参考:
读完需求,感觉输入输出大体是这个样子,
输入:
yyyy-MM
年月日期一个输出:返回该年月所在月的所有周信息(每周的起始日期和结束日期)
既然是通过某一个月找到该月每周的起始日期、结束日期,那换句话说,一个月里有很多日期,这么日期它可以按照周来分类,第一周的日期为一类,第二周的日期为一类,以此类推,然后每一类中按照日期升序排序,我取第一个日期和最后一个日期最终就可以达到题主要求了,至此除了输入输出外,中间过程应该是这个样子
输入:
yyyy-MM
年月日期一个yyyy-MM
转化为List<日期>
List<日期>
按照周进行分类得到类似一个map
的结果Map<Integer, List<日期>>
(其中key
就是第几周)Map<Integer, List<日期>>
中每一个List<日期>
取第一个值得到该周的第一天,取最后一个值得到该周的最后一天输出:返回该年月所在月的所有周信息(每周的起始日期和结束日期)
有了以上一个步骤,我们再来一一解决步骤需要用到的代码,当然我这里没有选择用
java calender
类,emmm,我觉得它们实在太臃肿了,也容易犯错,API
也不太好用,就以Java8
的新时间API
来替代了在
Java8
的新时间API
中,以前表示一个时间的庞大齐全的Date
类被拆分了成了很多类(以前一个Date
对象既表现了日期,也表现了时间,也表现了时区,大而全但不好用),这里我们要用到的是仅表示日期的YearMonth
(yyyy-MM)和LocalDate
(yyyy-MM-dd),YearMonth
就表达一个年月,LocalDate
就表达一个年月日所以上诉需求立马转换为
输入:
YearMonth
年月日期一个YearMonth
转化为List<LocalDate>
List<LocalDate>
按照周进行分类得到类似一个map
的结果Map<Integer, List<LocalDate>>
(其中key
就是第几周可以)Map<Integer, List<LocalDate>>
中每一个List<LocalDate>
取第一个值得到该周的第一天,取最后一个值得到该周的最后一天输出:返回该年月所在月的所有周信息(每周的起始日期和结束日期)
由于最终我们是在
List<LocalDate>
中取第一个日期和最后一个日期作为最终返回结果,因此套用那句我不知道在哪里看到的话:引用新的编程元素,可以增加代码的可读性,所以我们加一个新的类型WeekData
来表示这么一个返回结果所以上诉需求立马转换为
输入:
YearMonth
年月日期一个YearMonth
转化为List<LocalDate>
List<LocalDate>
按照周进行分类得到类似一个map
的结果Map<Integer, WeekData>
(其中key
就是第几周可以)输出:返回该年月所在月的所有周信息(每周的起始日期和结束日期)
现在就可以来解决每个步骤代码了,这样一个转换的方法,初始状态肯定是这样
YearMonth
作为传参,返回一个Map<Integer, WeekData>
第一个步骤,
YearMonth
转化为List<LocalDate>
,表示的是这个月的所有日期,这种List<LocalDate>
的,我第一想法就是用Java8
的stream
,首先根据yearMonth
获得这个月的开始日期和结束日期,用LocalDate
的with
方法即可,with
就是调整的意思,想啥调整就咋调整非常灵活,随便取一个日期(我这里取的是但当前日期)完成。。。是很简单吧,还有封装好的
TemporalAdjusters.firstDayOfMonth()
和TemporalAdjusters.lastDayOfMonth()
接下来我们来构造
stream
,用Stream.iterate(start, localDate -> localDate.plusDays(1l))
构造一个无限流,它代表,以start作为起始值,按照第二个参数localDate -> localDate.plusDays(1l)
也就是加一天的方式构造一个无限流,当然我要的不是无限,而是要到这个月末,所以limit(ChronoUnit.DAYS.between(start, end) + 1)
,这样就把这个无限流截断了这样第一步就完成了,第二步,按周分类,这里有一个知识点,给一个
LocalDate
对象,怎么判断它是该月的第几周,这里肯定要用LocalDate
的get
方法,因为这个方法就是表示从当前日期中获取某个属性值,参数是接口TemporalField
,你需要传入一个实现类即可,这个实现类就是定义了这个属性,当然JDK
默认有一个实现类枚举ChronoField
,里面有很多好用的实现类可以用,所以很容易就会选到一个枚举ChronoField.ALIGNED_WEEK_OF_MONTH
,看起来好像是对的,ALIGNED
不认识,WEEK_OF_MONTH
感觉意思很明白,貌似能用,其实不然,这个实现类定义的一周跟我们想象中的不一样,它的一周是按照完整7天来算的,拿8月6号来看,我们感觉是第二周,但是实际结果是第一周,因为要满打满算的7天才算一周,8月6号还是算第一周的第六天而已所以得换个方法,
ChronoField.ALIGNED_WEEK_OF_MONTH
是按照周的一共7天这个维度来定义周,但是跟我们想要的周定义不太一样,我们定义的周,例如8月,前面的5天就应该是第一周了,也就是说,我们想象的周,不是说几天是一周,应该是周一是一周的开始,周日是一周的结束,就算只有一个周日,那也是一周,所以我们就看到另一个类WeekFields
其中的静态变量SUNDAY_START
从注释来看是我们要的,不过是以星期天为一周开始的(这是国外的默认了,国内还是以周一为第一周开始的),所以我们直接用它的方式来构造一个就可以啦
最后完整的就是
最后用了哈
Collectors.groupingBy
和Collectors.collectingAndThen
配合了下,总之还算是比较简洁的写法,希望能帮到你最后简单打印哈获得
map
,看看结果