Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.8k views
in Technique[技术] by (71.8m points)

java中有比较好的方式去获取某个月中星期几所对应的日期吗?

请教下大家,有一个需求是根据月份,去找出这个月星期几所对应的日期是哪几天?例如给出2020年12月,找出所有周六,那么结果要返回 5、12、19、26这几天,我目前的思路是找出某个月符合条件的第一个日期,然后不断加7天,去判断,不过这样子看上去比较耿直,java8中有没有更好一些的方式或者api提供呢?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

加7天的方式来说,是比较耿直的,但是这也是很顺畅并且正确的思路嘛,就算有java8封装好的一些api,它本质的实现逻辑肯定也还是逃不过这个天数的加减嘛,毕竟加减总比挨着挨着比要好点噻

话说回来,那我开始看到这里,我首先就想到了笨办法,挨着挨着比嘛。
(注:不过在列出我的代码前,我想额外提一点,我建议呢,这个方法的入参最好还是要加个年吧,毕竟2019的12月里的周六,和2020年的12月的周六,那肯定是不一样的。所以我下面给出的方法,入参都是年+月)

那思路就很简单啦,我们直接根据输入的年和月

  1. 构造出咱们的YearMonth(这个可是java8新增的年月的时间类,整挺好)
  2. 根据YearMonthlengthOfMonth()可以快速得到这个月多少天
  3. 依据这个月多少天,利用IntStream.rangeClosed()方法构造一个这个月所有天的数字流IntStream,再用mapToObject()方法转换成Stream<LocalDate>
  4. Stream<LocalDate>挨着挨着判断是否等于周六,最后collector(Collectors.toList())完成
public static List<LocalDate> querySaturday(int year, Month month) {
     YearMonth yearMonth = YearMonth.of(year, month);
     return IntStream.rangeClosed(1, yearMonth.lengthOfMonth())
                     .mapToObj(day -> LocalDate.of(year, month, day))
                     .filter(day -> day.getDayOfWeek() == DayOfWeek.SATURDAY)
                     .collect(Collectors.toList());
}

总之也还算比较简单,不过就是有点费空间,毕竟中间有很多不要的LocalDatenew出来了

那回到题主最早想的加减法方式,当然我们肯定不会自己去加减,不过思路其实和上面一样,肯定也是要构建一个流的,不过加减法的说法那是我们程序员最底层的思维方式,但是放在理解java8的很多api设计上,咱们需要的是声明式的思维,告诉api你想要什么,而不是告诉它怎么去实现,这样起码来说找方法你会想到一些关键词,也就是说其实我最开始也是不知道具体到底有没有api,一旦你多了解了一些java8api设计,不说怎么设计,起码它这个起名你就摸到点门道~

那关键词是什么么?是next,下一个,虽然最开始我不知道到底有没有api,但是我的思路是:
构造一个流,这个流的创建是基于下一个周六,这样的模式创建的流里都是周六,然后依据个数简单截断,再依据月份进行过滤,最终得到答案

那为啥我会想到是next呢?在调整时间上api是咱们的TemporalAdjuster接口掌管,一个TemporalAdjuster接口实现就是一种调整时间的方式,它很多的实现类都在已经为你写好的工具类TemporalAdjusters中,对,多了个s,这里面的静态构造方法名,你打开一看就明白了

image.png

尽都是些很直抒胸臆的方法命名,一看你就知道它在做啥。什么firstlastprevious,那我也就立马发现这个方法,恰好就叫next,传参就是DayOfWeek
image.png

DayOfWeek是啥?就是周一到周六的枚举啊,官方的
image.png

安排的明明白白,那就简单了,我们找到了如何获取下一个周六的方法,那我们只需要首先获取这个年月的第一个周六,然后依照TemporalAdjusters.next方法就可以构造出所有都是周六的流了

那我们怎么获取这个年月的第一个周六呢?还记得刚才说的么?那就找找first开头的方法呗,巧了,还真有一个firstInMonth,传参也是DayOfWeek,这不就简单了么,所以我们可以直接完整代码了

public static List<LocalDate> querySaturday(int year, Month month) {
    YearMonth yearMonth = YearMonth.of(year, month);
 LocalDate firstSaturday = LocalDate.now().with(yearMonth).with(TemporalAdjusters.firstInMonth(DayOfWeek.SATURDAY));
 return Stream.iterate(firstSaturday, localDate -> localDate.with(TemporalAdjusters.next(DayOfWeek.SATURDAY)))
              .limit(4)
              .filter(localDate -> localDate.getMonth() == month)
              .collect(Collectors.toList());
}

差不多就是这样叭,拜了个拜~


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...