将 `YYYMMDD` 日期字符串数组转换为按月分组的分隔天字符串

问题描述 投票:0回答:6

PHP 日期是很棒的东西

+1 year
例如。然而我让自己陷入了一些混乱。我有三个跨越两个月的日期,我想制作一个优雅的字符串 “2 月 28 日、2 月 29 日和 3 月 1 日”,来自 3 个日期的数组,格式为
YYYYMMDD
。确切的日期数量未知,最少 1 可能最多 4

除了一些相当曲折的

str_replace
操作之外,我如何将其输出转换为我想要的格式?

注意:不超过2个月,也许一个月内全部完成。

$dates_array = ['20240228', '20240229', '20240301'];

foreach ($dates_array as $date) :
  $datetimes[]  = new DateTime($date);
endforeach;

// print_r($datetimes);

foreach ($datetimes as $key=>$date) :
  $month = $date->format('F');
  $day = $date->format('j');                                    
  $date_array[]= $day." ".$month." & ";
endforeach;

$date_string =  join( ' ', $date_array ) ;

echo $date_string;

// 28 February & 29 February & 1 March & 
php arrays datetime grouping date-formatting
6个回答
1
投票

我成功地创建了这个:

$dates = ['20240228', '20240229', '20240301'];

function formatDates(array $datesInput) {
    foreach ($datesInput as $datesKey => $date) {
        $date  = new DateTime($date);
        $month = $date->format('F');
        $day   = $date->format('j');
        if ($datesKey == 0) {
            $datesOutput = $day;
        } elseif ($currentMonth <> $month) {
            $datesOutput .= " $currentMonth & $day";
        } else {
            $datesOutput .= ", $day";
        }
        $currentMonth = $month;
    }
    return "$datesOutput $month";
}

echo formatDates($dates);

返回:

28, 29 February & 1 March

事情并没有那么复杂。然而,我确实将所有内容都放在一个函数中,因为否则我将不得不创建相当多的全局变量,而这被认为是不好的做法。 有关演示,请参阅:

https://3v4l.org/gUWih


1
投票
implode

将它们连接在一起:

$dates_array = ['20240228', '20240229', '20240301'];

foreach ($dates_array as $date) {
    $date = new DateTime($date);
    $datesByMonth[$date->format('F')][] = $date->format('j');
}

foreach($datesByMonth as $month => $dates) {
    $datesByMonth[$month] = implode(', ', $dates) . ' ' . $month;
}

echo implode(' & ', $datesByMonth);

https://3v4l.org/6snHe

如果您有同一个月的日期

在不同的年份

,显然是行不通的,但我想这不是一个要求(?)。


1
投票

迭代日期,在每次迭代中检查前一个日期是否连续并且属于同一个月。

<?php $dates_array = ["20240214", "20240228", "20240229", "20240301"]; $datetime_array = array_map(function($date_string) { return DateTime::createFromFormat("Ymd", $date_string); }, $dates_array); $groups = array_reduce($datetime_array, function($groups, $curr) { $key1 = array_key_last($groups); if ($key1 === null) { $key1 = 0; } else { $key2 = array_key_last($groups[$key1]); $prev = $groups[$key1][$key2]; if ($prev->diff($curr)->d !== 1 || $prev->format("n") !== $curr->format("n")) { $key1 += 1; } } $groups[$key1][] = $curr; return $groups; }, []); $result = array_map(function($group) { $key1 = array_key_last($group); return $key1 === 0 ? $group[$key1]->format("j F") : ($group[0]->format("j") . "-" . $group[$key1]->format("j F")); }, $groups); echo implode(", ", $result); // 14 February, 28-29 February, 1 March


                

1
投票
$datetimes

时,您必须检查列表中的下一个值是否在同一个月,以便知道是否在该日期的格式化输出中包含月份名称。

这是做到这一点的一种方法。广泛的假设是日期将始终按升序提供,但它也会检查下一个日期是否在同一年以及同一月,以防日期之间存在较大差距。

$dates_array = ['20241203', '20240115', '20240116', '20240228', '20240229', '20240301']; foreach ($dates_array as $date) { $datetimes[] = new DateTime($date); } foreach ($datetimes as $key=>$date) { $dateStr = $date->format('j'); //check if there's another entry after this one if (isset($datetimes[$key+1])) { //check the if following entry is in the same month and year as this one if ($datetimes[$key+1]->format("ym") == $date->format("ym")) { $dateStr .= ","; } else { $dateStr .= " ".$date->format("F")." & "; } } else { $dateStr .= " ".$date->format("F"); } $date_array[]= $dateStr; } $date_string = join( ' ', $date_array ) ; echo $date_string;

现场演示:
https://3v4l.org/tWrhe


0
投票

<?php $dates = ['20240228', '20240229','20240301']; $countDates = count($dates) - 1; $output = []; foreach ($dates as $date) : $datetimes[] = new DateTime($date); endforeach; foreach ($datetimes as $i => $datetime) : $dateOutput = [$datetime->format('j')]; $isNextMonthTheSame = isset($datetimes[$i+1]) && $datetime->format('m') === $datetimes[$i+1]->format('m'); if (!$isNextMonthTheSame) { $dateOutput []= ' '. $datetime->format('F'); $dateOutput []= ' & '; } else { $dateOutput []= ', '; } if ($i === $countDates) { array_pop($dateOutput); } $output []= $dateOutput; endforeach; echo implode(array_merge(...$output));

PS:扩展运算符(
...

)已在 PHP 7.4 中实现:

    


0
投票

我可能会使用

array_map()

进行第二个循环任务,以便数据可以方便地

implode()
编辑两次。
代码:(

演示

$dates = ['20240228', '20240229', '20240301']; $groups = []; foreach ($dates as $date) { $date = new DateTime($date); $groups[$date->format('F')][] = $date->format('j'); } echo implode( ' & ', array_map( fn($j, $F) => implode(', ', $j) . " $F", $groups, array_keys($groups) ) );

对于像 KIKO 这样的字符串构建器脚本,我的脚本会在遇到新月份时将文本附加到末尾,或者为再次遇到的月份注入新的“最后一天”。

代码:(

演示

$dates = ['20240228', '20240229', '20240301']; $text = ''; foreach ($dates as $i => $date) { $date = new DateTime($date); $month = $date->format('F'); $day = $date->format('j'); $pos = strpos($text, $month); if ($pos !== false) { $text = substr_replace($text, ", $day", $pos - 1, 0); } else { $text .= ($text ? ' & ' : '') . "$day $month"; } } echo $text;

© www.soinside.com 2019 - 2024. All rights reserved.