Даты заказа по предстоящим

Итак, я создаю массив различных дат. Дни рождения, юбилеи и праздники. Я хотел бы упорядочить массив, по которому происходит следующее, по сути, отсортировать с октября по сентябрь (перенос на следующий год)

так что если мой массив

$a = ([0]=>"1980-04-14", [1]=>"2007-06-08", 
  [2]=>"2008-12-25", [3]=>"1978-11-03")

Я бы хотел отсортировать это так, чтобы оно было расположено

$a = ([0]=>"1978-11-03", [1]=>"2008-12-25", 
  [2]=>"1980-04-14", [3]=>"2007-06-08")

потому что ноябрьское «событие» - это то, что произойдет следующим (исходя из того, что это октябрь прямо сейчас).

Я пытаюсь использовать сортировку, где находится моя функция cmp

function cmp($a, $b)
{
  $a_tmp = split("-", $a);
  $b_tmp = split("-", $b);
  return strcmp($a_tmp[1], $b_tmp[1]);
} 

Я не уверен, как изменить это, чтобы получить желаемый эффект.

Я люблю это свидание. Явно опечатка. сейчас исправил.

Jack B Nimble 03.10.2008 21:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
3
1
561
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Не сравнивайте строки, вместо этого используйте секунды с 1970 года (целые числа):

$date1 = split("-", $a);
$date2 = split("-", $b);
$seconds1 = mktime(0,0,0,$date1[1],$date1[2],$date1[0]);
$seconds2 = mktime(0,0,0,$date2[1],$date2[2],$date2[0]);
// eliminate years
$seconds1 %= 31536000;
$seconds2 %= 31536000;
return $seconds1 - $seconds2;

Также я не знаю PHP, но думаю, что суть верна.

Обновлено: функция сравнения инкапсулирована для выполнения сравнения, не более того. Чтобы упорядочить список относительно исходного вопроса, отсортируйте массив с включенной сегодняшней датой, найдите сегодняшнюю дату в массиве, а затем переместите элементы перед этой позицией в конец в порядке возрастания по позиции.

Ммм да, вам нужно было бы модулировать ticks1 и ticks2 на 31536000, чтобы исключить годы, но, боюсь, это сработает правильно.

cfeduke 07.10.2008 22:00

У меня возникнет соблазн установить исходный год события, а затем добавить к нему достаточно целых лет, чтобы гарантировать, что значение будет больше, чем ваша контрольная дата (обычно сегодняшняя дата). Или, возможно, больше или равно контрольной дате. Затем вы можете отсортировать их в простом порядке по дате.

Отредактировано для добавления:

Я недостаточно хорошо владею PHP, чтобы дать ответ на этот вопрос, но вот решение Perl.

#!/bin/perl -w

# Sort sequence of dates by next occurrence of anniversary.
# Today's "birthdays" count as low (will appear first in sequence)

use strict;

my $refdate = "2008-10-05";

my @list = (
    "1980-04-14", "2007-06-08",
    "2008-12-25", "1978-11-03",
    "2008-10-04", "2008-10-05",
    "2008-10-06", "2008-02-29"
);

sub date_on_or_after
{
    my($actdate, $refdate) = @_;
    my($answer) = $actdate;
    if ($actdate lt $refdate)   # String compare OK with ISO8601 format
    {
        my($act_yy, $act_mm, $act_dd) = split /-/, $actdate;
        my($ref_yy, $ref_mm, $ref_dd) = split /-/, $refdate;
        $ref_yy++ if ($act_mm < $ref_mm || ($act_mm == $ref_mm && $act_dd < $ref_dd));
        $answer = "$ref_yy-$act_mm-$act_dd";
    }
    return $answer;
}

sub anniversary_compare
{
    my $r1 = date_on_or_after($a, $refdate);
    my $r2 = date_on_or_after($b, $refdate);
    return $r1 cmp $r2;
}

my @result = sort anniversary_compare @list;

print "Before:\n";
print "* $_\n" foreach (@list);
print "Reference date: $refdate\n";
print "After:\n";
print "* $_\n" foreach (@result);

Ясно, что это не очень эффективно - чтобы сделать его эффективным, вы должны вычислить значение date_on_or_after () один раз, а затем отсортировать по этим значениям. Сравнение Perl немного странно - переменные $ a и $ b волшебны и появляются как будто из ниоткуда.

При запуске скрипт выдает:

Before:
* 1980-04-14
* 2007-06-08
* 2008-12-25
* 1978-11-03
* 2008-10-04
* 2008-10-05
* 2008-10-06
* 2008-02-29
Reference date: 2008-10-05
After:
* 2008-10-05
* 2008-10-06
* 1978-11-03
* 2008-12-25
* 2008-02-29
* 1980-04-14
* 2007-06-08
* 2008-10-04

Обратите внимание, что это в значительной степени уклоняется от вопроса о том, что произойдет с 29 февраля, потому что это «работает» для этого. По сути, он будет генерировать «дату» 2009-02-29, которая правильно сравнивает последовательность. Годовщина на 2000-02-28 будет указана перед годовщиной на 2008-02-29 (если 2000-02-28 были включены в данные).

Я подозреваю, что мой тоже не очень эффективен. Но я также не чувствую, что у меня есть ошибка 02-29.

Jack B Nimble 07.10.2008 07:34

Так что мне пришло в голову просто добавить 12 к любому месяцу, который меньше моего целевого месяца. Что не работает.

итак последняя функция

function cmp($a, $b)
{
    $a_tmp = explode('-', $a['date']);
    $b_tmp = explode('-', $b['date']);
    if ($a_tmp[1] < date('m')) {
        $a_tmp[1] += 12;
    }
    if ($b_tmp[1] < date('m')) {
        $b_tmp[1] += 12;
    }
    return strcmp($a_tmp[1] . $a_tmp[2], $b_tmp[1] . $b_tmp[2]);
} 

Это не сработает, если вы попытаетесь включить день в уже прошедшем месяце (например, если вы включите 10/1/2000 в свой список).

Randy 03.10.2008 21:36

Что произойдет, если одна из дат - 29 февраля 2008 года?

Jonathan Leffler 05.10.2008 16:54

Учитывая, что сегодня 2008-10-05, как ваш код показывает записи 2008-10-04, 2008-10-05, 2008-10-06? В частности, обратите внимание, что следующее празднование 2008-10-04 позже всех других рассматриваемых дат. Вы не определили, считается ли сегодняшняя дата этим или следующим годом.

Jonathan Leffler 05.10.2008 17:05

И, беспокоясь, - "шоу" в моем предыдущем комментарии излишни.

Jonathan Leffler 05.10.2008 17:06

Возможно отображение 10-04. На данный момент меня это не беспокоит. Возможно, мне придется прибавить 30 к любому дню сверх текущего. На данный момент это просто сортировка строк, поэтому такие дни, как 02-29 и 10-45, не имеют значения, они просто сортируются по порядку.

Jack B Nimble 07.10.2008 07:32

Просто используйте день года ('date ("z", mktime (0,0,0, $ d, $ m, $ y))') для сравнения, вы можете игнорировать месяц и год и не беспокоиться о високосных годах .

cfeduke 07.10.2008 22:11
Ответ принят как подходящий

function relative_year_day($date) {
    $value = date('z', strtotime($date)) - date('z');

    if ($value < 0)
        $value += 365;

    return $value;
}

function cmp($a, $b)
{
    $aValue = relative_year_day($a);
    $bValue = relative_year_day($b);

    if ($aValue == $bValue)
        return 0;

    return ($aValue < $bValue) ? -1 : 1;
}

$a = array("1980-04-14", "2007-06-08",
    "2008-12-25", "1978-11-03");

usort($a, "cmp");

используйте strtotime (), чтобы преобразовать все даты в метку времени, прежде чем добавлять их в массив, затем вы можете отсортировать массив в возрастающем (также хронологическом) порядке. Теперь все, что вам нужно сделать, это разобраться с датами в прошлом, что легко сделать, сравнив их с текущей меткой времени.

т.е.

for ($i=0; $i<count($a); $i++){
  if ($currentTimestamp > $a[$i]){
    unset($a[$i]);
  }
}

Нет причин изобретать велосипед. Если вам не нужны ключи, вы можете использовать это.

$a = array_combine(array_map('strtotime', $a), $a);
ksort($a);

Или, если вы хотите определить свой собственный обратный вызов.

function dateCmp($date1, $date2) {
  return (strtotime($date1) > strtotime($date2))?1:-1;
}

usort($a, 'dateCmp');

Если вы хотите, чтобы ключи были правильно связаны, просто вызовите вместо этого uasort.

uasort($a, 'dateCmp');

Я быстро проверил скорость, и функции обратного вызова были намного медленнее.

Другие вопросы по теме