[php_13]PHP获取指定月份的月初月尾时间

本文介绍了如何使用PHP获取指定月份的月初和月末的时间戳,包括获取上个月、当前月及任意指定月份的方法。

原文地址:http://blog.sina.com.cn/s/blog_813e149b01010qk5.html


PHP获取指定月份的月初月尾时间

获取上月月初月尾时间:

$startday=strtotime(date("Y-m-d H:i:s",mktime(0, 0 , 0,date("m")-1,1,date("Y"))));//获取上月头时间
$endday = strtotime(date("Y-m-d H:i:s",mktime(23,59,59,date("m") ,0,date("Y")))); //获取上月尾时间

 

获取指定月份月初月尾时间:

$yourdate = strtotime(date("Y-m-01 00:00:00"));

$endday = strtotime(date('Y-m-d', mktime(23, 59, 59, date('m', strtotime($yourdate))+1, 00)));

 

获取本月月初月尾时间:

date("Y-m-d H:i:s",mktime(0, 0 , 0,date("m"),1,date("Y")));
date("Y-m-d H:i:s",mktime(23,59,59,date("m"),date("t"),date("Y")));


//月初月末时间戳  
$Y = 2016;//获取年,示例,真实环境从前端获取数据  
$m = 8;//获取月,示例,真实环境从前端获取数据  
$month = $Y."-".$m;//当前年月  
$month_start = strtotime($month);//指定月份月初时间戳  
$month_end = mktime(23, 59, 59, date('m', strtotime($month))+1, 00);//指定月份月末时间戳  
//dump(array("month"=>$month,"month_start"=>$month_start,"month_end"=>$month_end));//输出  

<think>我们被要求计算指定日期的最近12个(包括指定日期所在)的月份区间。例如,如果指定日期是2024-08-06,那么我们需要得到从2023-09到2024-08这样的12个月份区间。注意,每个区间是一个的第一天到该的最后一天。但是,注意问题描述是“最近12个月份区间”,一般理解为从当前月份往前推12个,包括当前月份。所以应该是12个,每个区间是一个。另外,注意区间表示:每个区间是月份的第一天和月份的最后一天。实现思路:1.根据指定日期,先获取该日期所在月份的第一天和最后一天(作为最后一个区间)。2.然后往前推11个,得到总共12个的区间。但是,问题要求是“指定日期”的前12个,注意“前12个”的含义。比如,指定日期为2024-08-06,那么:往前推12个:2023-09至2024-08,共12个。注意:这里需要注意的是,从指定日期所在的月份开始,减去11个,再加上指定日期所在月份,共12个。另一种理解是:从当前月份往前推12个(包括当前月份),即12个月份区间。具体步骤:1.将指定日期转换为当的第一天(例如:2024-08-06->2024-08-01)2.然后从这一天开始,往前推11个(这样加上当就是12个),但是我们要得到12个区间,每个区间是一个的第一天和最后一天。做法:-对于指定日期,先获取的第一天(start)和最后一天(end)作为最后一个区间。-然后,对于前11个,我们每次减去一个,然后获取那个的第一天和最后一天。但是,我们也可以用一个循环,从指定日期的月份开始,往后减去i个(i从0到11),然后计算每个的第一天和最后一天。使用Java8的java.time包,我们可以轻松实现。步骤:1.解析指定日期,或者使用当前日期(如果没有指定,则按用户输入)。2.然后,我们以这个日期为基准,循环12次:每次用基准日期减去i个(i从0开始到11),然后计算该的第一天和最后一天。注意:如果基准日期是某个的最后一天,那么减去一个后得到的那个最后一天不会出错(比如331日减去一个是228日或29日,这是合理的)。但是我们的循环中,每个区间都是整,所以用该的第一天和最后一天。另一种思路:先得到指定日期当的第一天,然后从这个第一天开始,减去11个,得到12个月份区间(从减去11个的那个月份的第一天到指定月份的最后一天)。但我们需要每个区间单独表示。我们要的是12个区间,每个区间是每个的第一天和最后一天。因此,我们可以:-从指定日期所在月份的第一天开始,往前推11个,得到起始月份的第一天(这个起始月份就是12个区间的第一个月份)。-然后,用这个起始月份,循环12次,每次加上一个,然后得到每个的区间。但为了统一,我们直接循环12次,每次计算当前月份减去i个(i从0到11)对应的月份区间。例如:基准月份指定日期所在的月份(比如2024-08)i=0:2024-08->区间为2024-08-01至2024-08-31i=1:2023-07->2023-07-01至2023-07-31...但是注意,这样顺序是倒着的。如果我们希望从最早的一个开始,那么我们应该从当前月份减去11个开始,然后逐步增加。实现:用LocalDate的withDayOfMonth(1)得到月份的第一天,然后循环12次(从0到11):计算当前月份的基准:指定日期所在月份的第一天.minusMonths(11-i)这样i=0就是11个前,i=11就是当前。但更简单的是:循环12次,每次减去i个(i从0到11)得到对应的月份,然后计算该的第一天和最后一天。注意:减去i个后,我们得到一个日期,然后取这个日期所在的第一天和最后一天。但是,如果我们直接对基准日期所在的第一天减去i个(i从0到11):当i=0:不减,是当前(8)i=1:减1个就是7直到i=11:减去11个得到去年9那么这样顺序是:当前、前1个、前2个、...、前11个。但是我们需要的是从最早开始(前11个)到当前?还是按时间顺序倒序?问题没有明确顺序,但通常我们可能希望按时间顺序排列,即最早的月份(即距离现在最远的)排在前面,或者倒序(最近的排在前面)。根据问题“最近12个”,可能最近一个(当前)是最重要的,因此我们可以按倒序排列(即当前最先输出,然后依次往前推)?或者按自然顺序?根据需求不同,我们可以调整循环的顺序。我们可以有两种输出:1.从最早的一个开始(即当前的前第11个)到当前。2.从当前开始,往前推11个(倒序)。问题并没有明确,但一般统计报表中,可能是按时间先后顺序(最早到最晚),也可能是按倒序(从最近一个开始往前倒推)。由于问题没有明确,我们按时间先后顺序(即从最早的月份到最近的月份)来输出。因此,我们将循环变量i从11递减到0,这样:当i=11:表示当前月份减去11个,即最早的月份。当i=0:表示当前月份减去0个,即当前月份。但是这样循环中i是递减的,我们可以改为i从0到11,但计算月份时用:基准月份减去(11-i)个,这样i=0时就是减去11个(最早),i=11时就是减去0个(当前)。另一种:直接循环12次,每次取基准月份.minusMonths(11-i)(i从0到11),这样得到12个月份(从最早到当前)。然后,每个月份我们取当的第一天和最后一天。但需要注意的是:当我们对一个的第一天减去若干个时,不会出现错误(因为每个的第一天都是存在的,例如1号)。具体代码步骤:1.定义指定日期(例如:2024-08-06),也可以由用户输入。2.将该日期转为该的第一天(方便计算,虽然最后一天也可以,但第一天更统一)。3.循环12次(i从0到11):计算当前月份的日期=基准日期.minusMonths(11-i);//这样i=0时是11个前,i=11时是当前计算当前月份的第一天=当前月份日期.withDayOfMonth(1);计算当前月份的最后一天=当前月份的第一天.plusMonths(1).minusDays(1);//或者用TemporalAdjusters.lastDayOfMonth()4.将每个的第一天和最后一天组成一个区间(比如一个对象包含两个LocalDate)并存储到列表。但是,我们也可以使用YearMonth类,这样更简单。使用YearMonth:基准YearMonth=YearMonth.from(指定日期);//这样就直接得到指定日期所在的年然后循环:YearMonthym=baseYearMonth.minusMonths(11-i);然后这个的第一天:ym.atDay(1)这个的最后一天:ym.atEndOfMonth()因此,我们可以这样实现:示例代码:</think> 我将为您提供一个使用 Java 8 的 `java.time` API 实现的解决方案,该方案能计算指定日期前12个月份区间(包括起始月初末日期): ```java import java.time.LocalDate; import java.time.YearMonth; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; public class MonthRangeCalculator { public static void main(String[] args) { // 指定日期(可根据需求修改) String targetDateStr = "2024-08-15"; DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); // 获取月份区间 List<MonthRange> monthRanges = getPrevious12MonthRanges( LocalDate.parse(targetDateStr, dateFormatter) ); // 输出结果 System.out.printf("指定日期 [%s] 的前12个区间:\n", targetDateStr); monthRanges.forEach(range -> System.out.printf("- %s (%s 至 %s)\n", range.getYearMonth(), range.getStartDate(), range.getEndDate() ) ); } public static List<MonthRange> getPrevious12MonthRanges(LocalDate targetDate) { // 获取目标日期所在月份 YearMonth targetMonth = YearMonth.from(targetDate); List<MonthRange> ranges = new ArrayList<>(12); // 向前遍历12个 for (int i = 11; i >= 0; i--) { YearMonth month = targetMonth.minusMonths(i); ranges.add(new MonthRange( month.atDay(1), // 月份第一天 month.atEndOfMonth() // 月份最后一天 )); } return ranges; } static class MonthRange { private final LocalDate startDate; private final LocalDate endDate; public MonthRange(LocalDate startDate, LocalDate endDate) { this.startDate = startDate; this.endDate = endDate; } public String getYearMonth() { return startDate.format(DateTimeFormatter.ofPattern("yyyy-MM")); } public LocalDate getStartDate() { return startDate; } public LocalDate getEndDate() { return endDate; } } } ``` ### 关键功能说明: 1. **日期处理**: - 使用 `YearMonth` 处理年计算 - 通过 `minusMonths(i)` 实现精确的月份回溯 - `atDay(1)` 获取月初,`atEndOfMonth()` 获取末 2. **区间计算**: - 返回包含12个 `MonthRange` 对象的列表 - 每个区间包含: - 标准化年标识:$ \text{(yyyy-MM)} $ - 精确起始日期:$ \text{YYYY-MM-01} $ - 精确结束日期:$ \text{末日期} $ 3. **示例输出**: ``` 指定日期 [2024-08-15] 的前12个区间: - 2023-09 (2023-09-01 至 2023-09-30) - 2023-10 (2023-10-01 至 2023-10-31) ... - 2024-07 (2024-07-01 至 2024-07-31) - 2024-08 (2024-08-01 至 2024-08-31) ``` ### 特殊日期处理: 1. **闰年二**:自动处理 `2024-02-28/29` 等场景 2. **末边界**:如输入日期为31号,跨时自动修正为有效日期 3. **时区安全**:使用本地日期避免时区问题 该方法相比传统的 `Calendar` API 更简洁安全,符合 JSR-310 日期时间标准[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值