获取上个月的问题

今天2023年3月29日09

echo date('Y-m-d', strtotime('-1 month'));

返回

2023-03-01
echo date('Y-m-d', strtotime('-2 month'));

返回

2023-01-29

真的恶心了我了

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 16

原理大家说的都很清楚了, 可以用Carbon 这个包 针对大小月有很好用的方法

    Carbon::now()->subMonthsNoOverflow(1)->toDateString()
1年前 评论
fatrbaby

这不是bug

1年前 评论

确实

\Illuminate\Support\Carbon::now()->subMonth(1)->format('Y-m-d H:i:s')
2023-03-01 09:30:14

需要这样

echo \Illuminate\Support\Carbon::now()->startOfMonth()->subMonth(1)->format('Y-m-d H:i:s');
2023-02-01 00:00:00

或者

echo \Illuminate\Support\Carbon::now()->subMonthNoOverflow()->format('Y-m-d H:i:s');
2023-02-28 09:53:04

这样

echo date("Y-m-d", strtotime("last day of -1 month", time()));
2023-02-28

试一下go 也是一样,所以这个确实跟语言无关,和踩坑经验相关

    now := time.Now()
    lastMonth := now.AddDate(0, -1, 0)
    fmt.Println(lastMonth.Format("2006-01-02"))
2023-03-01
1年前 评论
Mutoulee

这怎么能算是bug呢?

1年前 评论
DonnyLiu

这应该不算是bug吧

1年前 评论

不要那么主观上来就bug,有没有可能是你自己基本功不到位呢,请用 date('Y-m-d', strtotime('last day of -1 month')) 试一试呢,就算如果真的是bug请到官方仓库提issue或者pr而不是在社区抱怨带来负能量

1年前 评论
// 今天 2023 年 3 月 29 日 09
echo date('Y-m-d', strtotime('-1 month')); // 2023-03-01
echo date('Y-m-d', strtotime('-2 month')); // 2023-01-29

// 按正常逻辑 -1 应该是 2023-02-29, 但是2 月没有这一天, 那么 29 号就会变成 28 号的后一天,即 2023-03-01

参考

1年前 评论
Silly-dog 1年前

这不是BUG

1年前 评论

原理大家说的都很清楚了, 可以用Carbon 这个包 针对大小月有很好用的方法

    Carbon::now()->subMonthsNoOverflow(1)->toDateString()
1年前 评论

这个是以当前时间计算得来的,上月没有29,就会往前移一天。要想计算日期准确需要稍微处理一下

// 获取当前日
$day = date('d');
// 获取上个月,因为 `last day of -1 month` 这是修正语句所以不会错,可以获取到上个月 
$last_day_of_month = strtotime("last day of -1 month");
// 获取上个月最大天数
$last_days = date('t', $last_day_of_month);
// 取最小值
$true_day = min($day, $last_days);
// 获取准确日期
$last_month = date('Y-m-', $last_day_of_month) . $true_day;
echo $last_month;
1年前 评论

这不是一个BUG,描述清楚你的目的,你想获取怎么样的日期,也许我可以帮助你。
官方函数 strtotime 是非常灵活的,无需扩展包就能做到很多很多你想不到的,学好英文,尝试用规范的英文语义化传递参数进去,你会得到预期的效果。可参考我写了一些用例手册,更多的等你自己去发现
www.kancloud.cn/wenshunbiao/wenshu...

1年前 评论
sinmu 1年前

我之前直接问的chatgpt,它给了我这个答案,然后刚我发现不是我要的。

1年前 评论

这种每月的固定多少号到期,只是有些业务设计需要(我个人做过的比较多项目是按30天计),源码底层是不会考虑太多业务方面的东西的。这事让我想起前段时间很多人吐槽的爱奇艺会员,2月少几天。但有时候我们又需要这种业务场景。
闲来无事,原生实现了这种需求(有更精炼的写法,欢迎交流),灵感来自于Carbon包,去学习了它的源码,要方便的话当然是直接用Carbon包啦,下面的代码仅供学习或不想加包的场景使用:

// 面向对象风格
$date = new \DateTime();
$day = $date->format('d');
$date->modify("-1 month");
if ($day !== $date->format('d')) {
    $date = $date->modify('last day of previous month');
}
echo $date->format(DATE_ATOM) . PHP_EOL;

// 函数风格
$timestamp = strtotime('-1 month');
if (date('d') !== date('d', $timestamp)) {
    $timestamp = strtotime('last day of previous month', $timestamp);
}
echo date(DATE_ATOM, $timestamp) . PHP_EOL;
1年前 评论
CodingHePing

直接用carbon包

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!