如何使用Carbon-Laravel获取上个月的第一天和最后一天

70

我需要使用 Carbon 库获取上个月的第一天最后一天,以下是我尝试过的:

$firstDayofPreviousMonth = Carbon::now()->startOfMonth()->subMonth()->toDateString();
$lastDayofPreviousMonth = Carbon::now()->endOfMonth()->subMonth()->toDateString();

我得到的结果是基于$firstDayofPreviousMonth = '2016-04-01'(因为当前月份是5月)和$lastDayofPreviousMonth = '2016-05-01'

对于$firstDayofPreviousMonth,我得到了正确的结果,但是它给出了30天之前的结果,并且对于$lastDayofPreviousMonth给出了错误的结果。

有人能帮我解决这个问题吗?

7个回答

89

试一下这个:

$start = new Carbon('first day of last month');
$end = new Carbon('last day of last month');

2
无法获取时间为00:00:00。 - Ozan Kurt
正如你所看到的,他正在尝试过滤一些数据。你的解决方案给了他错误的结果。请编辑你的答案让他看到精确的结果,那么就没有被踩的理由了。 - Ozan Kurt
2
我不在乎你的想法,因为既然他问这个问题,他不知道该怎么做。所以多亏了你,他可能会错误地过滤掉一些东西。 - Ozan Kurt
这是真正的错误,我在公司使用了这段代码,它返回了错误的日期。根据我的经验,Ozan 是完全正确的,现在就能运行,而不是以后。@Abu Sayem 的答案对我有效。 - Yasmin French
4
这是正确答案。您还可以与endOfDay()startOfDay()结合使用,以获得23:59:59或00:00:00。 - Luciano Fantuzzi

88

试一试吧

$firstDayofPreviousMonth = Carbon::now()->startOfMonth()->subMonth()->toDateString();
$lastDayofPreviousMonth = Carbon::now()->subMonth()->endOfMonth()->toDateString();

更新的代码,更加准确

$firstDayofPreviousMonth = Carbon::now()->startOfMonth()->subMonthsNoOverflow()->toDateString();

$lastDayofPreviousMonth = Carbon::now()->subMonthsNoOverflow()->endOfMonth()->toDateString();

@kenfai 谢谢


4
这绝对是最好的选择,因为它从00:00开始,到23:59:59结束。已接受的解决方案没有考虑时间因素,可能会产生不可靠的结果。 - rgehan
1
我只是想指出,由于PHP DateTime溢出问题,您可能希望使用subMonthNoOverflow()。更多讨论请参见:https://github.com/briannesbitt/Carbon/issues/428 - kenfai
@kenfai 谢谢,我已经更新了代码示例。 - Abu Sayem
谢谢你!因为我遇到了每月31日的问题。 - Philipp Mochine
我使用的是 Laravel 5.6。当我使用更新的解决方案时,出现了一个错误,提示我必须在方法 subMonthsNoOverflow() 中提供值。我输入了1以获得我的结果。 - pankaj

18

使用此功能,日期的开始时间为00:00,结束时间为23:59。

$start = new Carbon('first day of last month');
$start->startOfMonth();
$end = new Carbon('last day of last month');
$end->endOfMonth();

1
这应该是正确的答案,因为它也比较了时间。 - Sem

12

为了具体回答你为什么会得到错误的结果$lastDayofPreviousMonth的问题。

让我们分解一下你示例中的这个语句:

Carbon::now()->endOfMonth()->subMonth()->toDateString();
// Carbon::now() > 2016-05-05
// ->endOfMonth() > 2016-05-31
// ->subMonth() > 2016-04-31 // Simply takes 1 away from 5.

这意味着我们得到了一个无效的日期——4月没有31日。额外的一天被简单地加到最后一个有效日期上(2016-04-30 + 1),将日期滚动到了5月(2016-05-01)。

如前所述,为确保永远不会发生这种情况,在进行任何其他操作之前,请始终将日期重置为该月的第一天(因为每个月都有第一天)。

$lastDayofPreviousMonth = Carbon::now()->startofMonth()->subMonth()->endOfMonth()->toDateString();
// Carbon::now() > 2016-05-05
// ->startofMonth() > 2016-05-01 00:00:00
// ->subMonth() > 2016-04-01 00:00:00
// ->endOfMonth() > 2016-04-30 23:59:59

5

另一个解决方案是使用Carbon方法subMonthNoOverflow()

$lastDayofPreviousMonth = Carbon::now()->subMonthNoOverflow()->endOfMonth()->toDateString();

在遇到每月31日的问题时,在这里找到了解决方法:https://github.com/briannesbitt/Carbon/issues/627


5

目前在使用Carbon的方法时存在一个bug。

Carbon::now()->startOfMonth()->subMonth()->endOfMonth()->toDateTimeString();

这个bug会导致那些有31天的月份返回最后一天是30号。
比如说,如果你在三月份运行上述代码,它会返回2017-03-30而不是你期望的2017-03-31。
因为我需要进行日期之间的操作,所以我最终使用了...
Carbon::now()->startOfMonth()->subSeconds(1)->toDateTimeString();

这样做可以得到正确的日期dateTimeString,适用于以31日结尾的那些天。

1

这对我有效。

$firstDayofPreviousMonth = Carbon::now()->startOfMonth()->subMonth()->toDateTimeString(); // 2021-08-01 00:00:00
$lastDayofPreviousMonth = Carbon::now()->endOfMonth()->subMonth()->toDateTimeString(); // 2021-08-31 23:59:59

使用单个$date变量

$date = Carbon::now();

$firstDayofPreviousMonth = $date->startOfMonth()->subMonth()->toDateTimeString(); // 2021-08-01 00:00:00

$lastDayofPreviousMonth = $date->endOfMonth()->toDateTimeString(); // 2021-08-31 23:59:59

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接